Branch data Line data Source code
1 : : // Copyright (C) 2021-2025 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 : 4203 : class ScanDeadcode : public MarkLiveBase
39 : : {
40 : : using Rust::Analysis::MarkLiveBase::visit;
41 : :
42 : : public:
43 : 4203 : static void Scan (HIR::Crate &crate)
44 : : {
45 : 4203 : std::set<HirId> live_symbols = Analysis::MarkLive::Analysis (crate);
46 : 4203 : ScanDeadcode sdc (live_symbols);
47 : 19779 : for (auto &it : crate.get_items ())
48 : 15576 : it.get ()->accept_vis (sdc);
49 : 4203 : };
50 : :
51 : 11560 : void visit (HIR::Function &function) override
52 : : {
53 : 11560 : HirId hirId = function.get_mappings ().get_hirid ();
54 : 5398 : if (should_warn (hirId) && !function.get_visibility ().is_public ())
55 : : {
56 : 2977 : if (mappings.is_impl_item (hirId))
57 : : {
58 : 2764 : HIR::ImplBlock *implBlock = mappings.lookup_associated_impl (hirId);
59 : 2764 : if (!implBlock->has_trait_ref ())
60 : : {
61 : 98 : rust_warning_at (
62 : 196 : function.get_function_name ().get_locus (), 0,
63 : : "associated function is never used: %qs",
64 : 196 : function.get_function_name ().as_string ().c_str ());
65 : : }
66 : : }
67 : : else
68 : : {
69 : 213 : rust_warning_at (
70 : 426 : function.get_function_name ().get_locus (), 0,
71 : : "function is never used: %qs",
72 : 426 : function.get_function_name ().as_string ().c_str ());
73 : : }
74 : : }
75 : 11560 : }
76 : :
77 : 1128 : void visit (HIR::StructStruct &stct) override
78 : : {
79 : 1128 : HirId hirId = stct.get_mappings ().get_hirid ();
80 : 415 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
81 : : {
82 : 255 : bool name_starts_underscore
83 : 255 : = stct.get_identifier ().as_string ().at (0) == '_';
84 : 255 : if (!name_starts_underscore)
85 : 227 : rust_warning_at (stct.get_locus (), 0,
86 : : "struct is never constructed: %qs",
87 : 454 : stct.get_identifier ().as_string ().c_str ());
88 : : }
89 : : else
90 : : {
91 : : // only warn the unused fields when in unwarned struct.
92 : 2174 : for (auto &field : stct.get_fields ())
93 : : {
94 : 1301 : HirId field_hir_id = field.get_mappings ().get_hirid ();
95 : 2602 : if (should_warn (field_hir_id)
96 : 627 : && !field.get_visibility ().is_public ()
97 : 1750 : && field.get_field_name ().as_string ().at (0) != '_')
98 : : {
99 : 436 : rust_warning_at (field.get_locus (), 0,
100 : : "field is never read: %qs",
101 : 872 : field.get_field_name ().as_string ().c_str ());
102 : : }
103 : : }
104 : : }
105 : 1128 : }
106 : :
107 : 797 : void visit (HIR::TupleStruct &stct) override
108 : : {
109 : : // only warn tuple struct unconstructed, and ignoring unused field
110 : 797 : HirId hirId = stct.get_mappings ().get_hirid ();
111 : 99 : if (should_warn (hirId) && !stct.get_visibility ().is_public ())
112 : : {
113 : 69 : rust_warning_at (stct.get_locus (), 0,
114 : : "struct is never constructed: %qs",
115 : 138 : stct.get_identifier ().as_string ().c_str ());
116 : : }
117 : 797 : }
118 : :
119 : 4556 : void visit (HIR::ImplBlock &blc) override
120 : : {
121 : 4556 : if (blc.has_impl_items ())
122 : : {
123 : 10342 : for (auto &implItem : blc.get_impl_items ())
124 : : {
125 : 6782 : implItem->accept_vis (*this);
126 : : }
127 : : }
128 : 4556 : }
129 : :
130 : 839 : void visit (HIR::Module &mod) override
131 : : {
132 : 3599 : for (auto &item : mod.get_items ())
133 : 2760 : item->accept_vis (*this);
134 : 839 : }
135 : :
136 : : private:
137 : : std::set<HirId> live_symbols;
138 : : Resolver::Resolver *resolver;
139 : : Analysis::Mappings &mappings;
140 : :
141 : 4203 : ScanDeadcode (std::set<HirId> &live_symbols)
142 : 4203 : : live_symbols (live_symbols), resolver (Resolver::Resolver::get ()),
143 : 8406 : mappings (Analysis::Mappings::get ()){};
144 : :
145 : 14786 : bool should_warn (HirId hirId)
146 : : {
147 : : // TODO: There are more condition to check if should warn, i.e visibility,
148 : : // attributes.
149 : 14786 : return live_symbols.find (hirId) == live_symbols.end ();
150 : : }
151 : : };
152 : :
153 : : } // namespace Analysis
154 : : } // namespace Rust
155 : :
156 : : #endif
|