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