Line data Source code
1 : // Copyright (C) 2021-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #ifndef RUST_HIR_SCAN_DEADCODE
20 : #define RUST_HIR_SCAN_DEADCODE
21 :
22 : #include "options.h"
23 : #include "rust-hir-full-decls.h"
24 : #include "rust-hir-map.h"
25 : #include "rust-lint-marklive.h"
26 : #include "rust-name-resolver.h"
27 : #include "rust-diagnostics.h"
28 :
29 : namespace Rust {
30 : namespace Analysis {
31 :
32 : // Scan item symbols and warn the symbol if it is not in the live_symbols set.
33 : // There are three kinds of item we should handle in this pass.
34 : // 1. Function item
35 : // 2. The function item in the impl block without trait
36 : // 3. StructStruct, e.g., `Struct Foo{one: 1, two: 2}`. Furthermore, the unused
37 : // struct fields will be warned too.
38 : // 4. TupleStruct, e.g., `Struct Foo(i32, i32)`
39 4305 : class ScanDeadcode : public MarkLiveBase
40 : {
41 : using Rust::Analysis::MarkLiveBase::visit;
42 :
43 : public:
44 4305 : static void Scan (HIR::Crate &crate)
45 : {
46 4305 : std::set<HirId> live_symbols = Analysis::MarkLive::Analysis (crate);
47 4305 : ScanDeadcode sdc (live_symbols);
48 22114 : for (auto &it : crate.get_items ())
49 17809 : it.get ()->accept_vis (sdc);
50 4305 : };
51 :
52 12994 : void visit (HIR::Function &function) override
53 : {
54 12994 : HirId hirId = function.get_mappings ().get_hirid ();
55 12994 : auto starts_with_underscore
56 12994 : = function.get_function_name ().as_string ().rfind ('_', 0) == 0;
57 6328 : if (should_warn (hirId) && !function.get_visibility ().is_public ()
58 17040 : && !starts_with_underscore)
59 : {
60 4029 : if (mappings.is_impl_item (hirId))
61 : {
62 3868 : HIR::ImplBlock *implBlock = mappings.lookup_associated_impl (hirId);
63 3868 : if (!implBlock->has_trait_ref ())
64 : {
65 89 : rust_warning_at (
66 178 : function.get_function_name ().get_locus (), 0,
67 : "associated function is never used: %qs",
68 178 : function.get_function_name ().as_string ().c_str ());
69 : }
70 : }
71 : else
72 : {
73 161 : rust_warning_at (
74 322 : function.get_function_name ().get_locus (), 0,
75 : "function is never used: %qs",
76 322 : function.get_function_name ().as_string ().c_str ());
77 : }
78 : }
79 12994 : }
80 :
81 1375 : void visit (HIR::StructStruct &stct) override
82 : {
83 1375 : HirId hirId = stct.get_mappings ().get_hirid ();
84 486 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
85 : {
86 226 : bool name_starts_underscore
87 226 : = stct.get_identifier ().as_string ().at (0) == '_';
88 226 : if (!name_starts_underscore)
89 203 : rust_warning_at (stct.get_locus (), 0,
90 : "struct is never constructed: %qs",
91 406 : stct.get_identifier ().as_string ().c_str ());
92 : }
93 : else
94 : {
95 : // only warn the unused fields when in unwarned struct.
96 2621 : for (auto &field : stct.get_fields ())
97 : {
98 1472 : HirId field_hir_id = field.get_mappings ().get_hirid ();
99 2944 : if (should_warn (field_hir_id)
100 683 : && !field.get_visibility ().is_public ()
101 1957 : && field.get_field_name ().as_string ().at (0) != '_')
102 : {
103 455 : rust_warning_at (field.get_locus (), 0,
104 : "field is never read: %qs",
105 910 : field.get_field_name ().as_string ().c_str ());
106 : }
107 : }
108 : }
109 1375 : }
110 :
111 796 : void visit (HIR::TupleStruct &stct) override
112 : {
113 : // only warn tuple struct unconstructed, and ignoring unused field
114 796 : HirId hirId = stct.get_mappings ().get_hirid ();
115 68 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
116 : {
117 51 : rust_warning_at (stct.get_locus (), 0,
118 : "struct is never constructed: %qs",
119 102 : stct.get_identifier ().as_string ().c_str ());
120 : }
121 796 : }
122 :
123 5410 : void visit (HIR::ImplBlock &blc) override
124 : {
125 5410 : if (blc.has_impl_items ())
126 : {
127 12280 : for (auto &implItem : blc.get_impl_items ())
128 : {
129 7988 : implItem->accept_vis (*this);
130 : }
131 : }
132 5410 : }
133 :
134 1139 : void visit (HIR::Module &mod) override
135 : {
136 4726 : for (auto &item : mod.get_items ())
137 3587 : item->accept_vis (*this);
138 1139 : }
139 :
140 462 : void visit (HIR::ConstantItem &item) override
141 : {
142 462 : if (!flag_unused_check_2_0)
143 460 : return;
144 4 : std::string var_name = item.get_identifier ().as_string ();
145 2 : bool starts_with_under_score = var_name.at (0) == '_';
146 2 : HirId hirId = item.get_mappings ().get_hirid ();
147 2 : if (should_warn (hirId) && !item.get_visibility ().is_public ()
148 3 : && !starts_with_under_score)
149 1 : rust_warning_at (item.get_locus (), OPT_Wunused_variable,
150 : "deadcode const item %qs",
151 2 : item.get_identifier ().as_string ().c_str ());
152 2 : }
153 :
154 48 : void visit (HIR::StaticItem &item) override
155 : {
156 48 : if (!flag_unused_check_2_0)
157 45 : return;
158 6 : std::string var_name = item.get_identifier ().as_string ();
159 3 : bool starts_with_under_score = var_name.at (0) == '_';
160 3 : HirId hirId = item.get_mappings ().get_hirid ();
161 3 : if (should_warn (hirId) && !item.get_visibility ().is_public ()
162 5 : && !starts_with_under_score)
163 1 : rust_warning_at (item.get_locus (), OPT_Wunused_variable,
164 : "deadcode static item %qs",
165 2 : item.get_identifier ().as_string ().c_str ());
166 3 : }
167 :
168 : private:
169 : std::set<HirId> live_symbols;
170 : Resolver::Resolver *resolver;
171 : Analysis::Mappings &mappings;
172 :
173 4305 : ScanDeadcode (std::set<HirId> &live_symbols)
174 4305 : : live_symbols (live_symbols), resolver (Resolver::Resolver::get ()),
175 8610 : mappings (Analysis::Mappings::get ()){};
176 :
177 16642 : bool should_warn (HirId hirId)
178 : {
179 : // TODO: There are more condition to check if should warn, i.e visibility,
180 : // attributes.
181 16642 : return live_symbols.find (hirId) == live_symbols.end ();
182 : }
183 : };
184 :
185 : } // namespace Analysis
186 : } // namespace Rust
187 :
188 : #endif
|