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 "rust-hir-full-decls.h"
23 : #include "rust-hir-map.h"
24 : #include "rust-lint-marklive.h"
25 : #include "rust-name-resolver.h"
26 : #include "rust-diagnostics.h"
27 :
28 : namespace Rust {
29 : namespace Analysis {
30 :
31 : // Scan item symbols and warn the symbol if it is not in the live_symbols set.
32 : // There are three kinds of item we should handle in this pass.
33 : // 1. Function item
34 : // 2. The function item in the impl block without trait
35 : // 3. StructStruct, e.g., `Struct Foo{one: 1, two: 2}`. Furthermore, the unused
36 : // struct fields will be warned too.
37 : // 4. TupleStruct, e.g., `Struct Foo(i32, i32)`
38 4032 : class ScanDeadcode : public MarkLiveBase
39 : {
40 : using Rust::Analysis::MarkLiveBase::visit;
41 :
42 : public:
43 4032 : static void Scan (HIR::Crate &crate)
44 : {
45 4032 : std::set<HirId> live_symbols = Analysis::MarkLive::Analysis (crate);
46 4032 : ScanDeadcode sdc (live_symbols);
47 20783 : for (auto &it : crate.get_items ())
48 16751 : it.get ()->accept_vis (sdc);
49 4032 : };
50 :
51 12556 : void visit (HIR::Function &function) override
52 : {
53 12556 : HirId hirId = function.get_mappings ().get_hirid ();
54 12556 : auto starts_with_underscore
55 12556 : = function.get_function_name ().as_string ().rfind ('_', 0) == 0;
56 12408 : if (should_warn (hirId) && !function.get_visibility ().is_public ()
57 16516 : && !starts_with_underscore)
58 : {
59 3958 : if (mappings.is_impl_item (hirId))
60 : {
61 3802 : HIR::ImplBlock *implBlock = mappings.lookup_associated_impl (hirId);
62 3802 : if (!implBlock->has_trait_ref ())
63 : {
64 89 : rust_warning_at (
65 178 : function.get_function_name ().get_locus (), 0,
66 : "associated function is never used: %qs",
67 178 : function.get_function_name ().as_string ().c_str ());
68 : }
69 : }
70 : else
71 : {
72 156 : rust_warning_at (
73 312 : function.get_function_name ().get_locus (), 0,
74 : "function is never used: %qs",
75 312 : function.get_function_name ().as_string ().c_str ());
76 : }
77 : }
78 12556 : }
79 :
80 1300 : void visit (HIR::StructStruct &stct) override
81 : {
82 1300 : HirId hirId = stct.get_mappings ().get_hirid ();
83 473 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
84 : {
85 238 : bool name_starts_underscore
86 238 : = stct.get_identifier ().as_string ().at (0) == '_';
87 238 : if (!name_starts_underscore)
88 215 : rust_warning_at (stct.get_locus (), 0,
89 : "struct is never constructed: %qs",
90 430 : stct.get_identifier ().as_string ().c_str ());
91 : }
92 : else
93 : {
94 : // only warn the unused fields when in unwarned struct.
95 2467 : for (auto &field : stct.get_fields ())
96 : {
97 1405 : HirId field_hir_id = field.get_mappings ().get_hirid ();
98 2810 : if (should_warn (field_hir_id)
99 659 : && !field.get_visibility ().is_public ()
100 1886 : && field.get_field_name ().as_string ().at (0) != '_')
101 : {
102 462 : rust_warning_at (field.get_locus (), 0,
103 : "field is never read: %qs",
104 924 : field.get_field_name ().as_string ().c_str ());
105 : }
106 : }
107 : }
108 1300 : }
109 :
110 792 : void visit (HIR::TupleStruct &stct) override
111 : {
112 : // only warn tuple struct unconstructed, and ignoring unused field
113 792 : HirId hirId = stct.get_mappings ().get_hirid ();
114 73 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
115 : {
116 57 : rust_warning_at (stct.get_locus (), 0,
117 : "struct is never constructed: %qs",
118 114 : stct.get_identifier ().as_string ().c_str ());
119 : }
120 792 : }
121 :
122 5307 : void visit (HIR::ImplBlock &blc) override
123 : {
124 5307 : if (blc.has_impl_items ())
125 : {
126 12072 : for (auto &implItem : blc.get_impl_items ())
127 : {
128 7872 : implItem->accept_vis (*this);
129 : }
130 : }
131 5307 : }
132 :
133 1152 : void visit (HIR::Module &mod) override
134 : {
135 4830 : for (auto &item : mod.get_items ())
136 3678 : item->accept_vis (*this);
137 1152 : }
138 :
139 : private:
140 : std::set<HirId> live_symbols;
141 : Resolver::Resolver *resolver;
142 : Analysis::Mappings &mappings;
143 :
144 4032 : ScanDeadcode (std::set<HirId> &live_symbols)
145 4032 : : live_symbols (live_symbols), resolver (Resolver::Resolver::get ()),
146 8064 : mappings (Analysis::Mappings::get ()){};
147 :
148 16053 : bool should_warn (HirId hirId)
149 : {
150 : // TODO: There are more condition to check if should warn, i.e visibility,
151 : // attributes.
152 16053 : return live_symbols.find (hirId) == live_symbols.end ();
153 : }
154 : };
155 :
156 : } // namespace Analysis
157 : } // namespace Rust
158 :
159 : #endif
|