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