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 4028 : class ScanDeadcode : public MarkLiveBase
39 : {
40 : using Rust::Analysis::MarkLiveBase::visit;
41 :
42 : public:
43 4028 : static void Scan (HIR::Crate &crate)
44 : {
45 4028 : std::set<HirId> live_symbols = Analysis::MarkLive::Analysis (crate);
46 4028 : ScanDeadcode sdc (live_symbols);
47 20761 : for (auto &it : crate.get_items ())
48 16733 : it.get ()->accept_vis (sdc);
49 4028 : };
50 :
51 12549 : void visit (HIR::Function &function) override
52 : {
53 12549 : HirId hirId = function.get_mappings ().get_hirid ();
54 6203 : if (should_warn (hirId) && !function.get_visibility ().is_public ())
55 : {
56 3959 : if (mappings.is_impl_item (hirId))
57 : {
58 3802 : HIR::ImplBlock *implBlock = mappings.lookup_associated_impl (hirId);
59 3802 : if (!implBlock->has_trait_ref ())
60 : {
61 89 : rust_warning_at (
62 178 : function.get_function_name ().get_locus (), 0,
63 : "associated function is never used: %qs",
64 178 : function.get_function_name ().as_string ().c_str ());
65 : }
66 : }
67 : else
68 : {
69 157 : rust_warning_at (
70 314 : function.get_function_name ().get_locus (), 0,
71 : "function is never used: %qs",
72 314 : function.get_function_name ().as_string ().c_str ());
73 : }
74 : }
75 12549 : }
76 :
77 1300 : void visit (HIR::StructStruct &stct) override
78 : {
79 1300 : HirId hirId = stct.get_mappings ().get_hirid ();
80 473 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
81 : {
82 238 : bool name_starts_underscore
83 238 : = stct.get_identifier ().as_string ().at (0) == '_';
84 238 : if (!name_starts_underscore)
85 215 : rust_warning_at (stct.get_locus (), 0,
86 : "struct is never constructed: %qs",
87 430 : stct.get_identifier ().as_string ().c_str ());
88 : }
89 : else
90 : {
91 : // only warn the unused fields when in unwarned struct.
92 2467 : for (auto &field : stct.get_fields ())
93 : {
94 1405 : HirId field_hir_id = field.get_mappings ().get_hirid ();
95 2810 : if (should_warn (field_hir_id)
96 659 : && !field.get_visibility ().is_public ()
97 1886 : && field.get_field_name ().as_string ().at (0) != '_')
98 : {
99 462 : rust_warning_at (field.get_locus (), 0,
100 : "field is never read: %qs",
101 924 : field.get_field_name ().as_string ().c_str ());
102 : }
103 : }
104 : }
105 1300 : }
106 :
107 792 : void visit (HIR::TupleStruct &stct) override
108 : {
109 : // only warn tuple struct unconstructed, and ignoring unused field
110 792 : HirId hirId = stct.get_mappings ().get_hirid ();
111 73 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
112 : {
113 57 : rust_warning_at (stct.get_locus (), 0,
114 : "struct is never constructed: %qs",
115 114 : stct.get_identifier ().as_string ().c_str ());
116 : }
117 792 : }
118 :
119 5307 : void visit (HIR::ImplBlock &blc) override
120 : {
121 5307 : if (blc.has_impl_items ())
122 : {
123 12072 : for (auto &implItem : blc.get_impl_items ())
124 : {
125 7872 : implItem->accept_vis (*this);
126 : }
127 : }
128 5307 : }
129 :
130 1152 : void visit (HIR::Module &mod) override
131 : {
132 4830 : for (auto &item : mod.get_items ())
133 3678 : item->accept_vis (*this);
134 1152 : }
135 :
136 : private:
137 : std::set<HirId> live_symbols;
138 : Resolver::Resolver *resolver;
139 : Analysis::Mappings &mappings;
140 :
141 4028 : ScanDeadcode (std::set<HirId> &live_symbols)
142 4028 : : live_symbols (live_symbols), resolver (Resolver::Resolver::get ()),
143 8056 : mappings (Analysis::Mappings::get ()){};
144 :
145 16046 : bool should_warn (HirId hirId)
146 : {
147 : // TODO: There are more condition to check if should warn, i.e visibility,
148 : // attributes.
149 16046 : return live_symbols.find (hirId) == live_symbols.end ();
150 : }
151 : };
152 :
153 : } // namespace Analysis
154 : } // namespace Rust
155 :
156 : #endif
|