Skip to content

Commit 038d637

Browse files
committed
Implement unused variable checker on HIR.
gcc/rust/ChangeLog: * Make-lang.in: New file. * checks/lints/unused-var/rust-unused-var-checker.cc (UnusedVarChecker): Implement unused variable checker. * checks/lints/unused-var/rust-unused-var-checker.h (UnusedVarChecker): Implement unused variable checker. * checks/lints/unused-var/rust-unused-var-collector.cc (UnusedVarCollector): Implement unused variable collector. * checks/lints/unused-var/rust-unused-var-collector.h (UnusedVarCollector): Implement unused variable collector. * checks/lints/unused-var/rust-unused-var-context.cc (UnusedVarContext): Implement unused variable context. * checks/lints/unused-var/rust-unused-var-context.h (UnusedVarContext): Implement unused variable context. Signed-off-by: Ryutaro Okada <[email protected]>
1 parent 85ec714 commit 038d637

File tree

7 files changed

+496
-0
lines changed

7 files changed

+496
-0
lines changed

gcc/rust/Make-lang.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ GRS_OBJS = \
208208
rust/rust-const-checker.o \
209209
rust/rust-lint-marklive.o \
210210
rust/rust-lint-unused-var.o \
211+
rust/rust-unused-var-checker.o \
212+
rust/rust-unused-var-collector.o \
213+
rust/rust-unused-var-context.o \
211214
rust/rust-readonly-check.o \
212215
rust/rust-readonly-check2.o \
213216
rust/rust-hir-type-check-path.o \
@@ -441,6 +444,7 @@ RUST_INCLUDES = -I $(srcdir)/rust \
441444
-I $(srcdir)/rust/typecheck \
442445
-I $(srcdir)/rust/checks/lints \
443446
-I $(srcdir)/rust/checks/errors \
447+
-I $(srcdir)/rust/checks/lints/unused-var \
444448
-I $(srcdir)/rust/checks/errors/privacy \
445449
-I $(srcdir)/rust/checks/errors/borrowck \
446450
-I $(srcdir)/rust/util \
@@ -510,6 +514,11 @@ rust/%.o: rust/checks/lints/%.cc
510514
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
511515
$(POSTCOMPILE)
512516

517+
# build unused variable checking pass files in rust folder
518+
rust/%.o: rust/checks/lints/unused-var/%.cc
519+
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
520+
$(POSTCOMPILE)
521+
513522
# build rust/checks/errors files in rust folder
514523
rust/%.o: rust/checks/errors/%.cc
515524
$(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $<
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (C) 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+
#include "rust-unused-var-checker.h"
20+
#include "rust-hir-item.h"
21+
22+
#include "options.h"
23+
24+
namespace Rust {
25+
namespace Analysis {
26+
UnusedVarChecker::UnusedVarChecker ()
27+
: nr_context (
28+
Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
29+
mappings (Analysis::Mappings::get ()),
30+
unused_var_context (*UnusedVarContext::get ())
31+
{}
32+
void
33+
UnusedVarChecker::go (HIR::Crate &crate)
34+
{
35+
UnusedVarCollector ().go (crate);
36+
for (auto &item : crate.get_items ())
37+
item->accept_vis (*this);
38+
}
39+
void
40+
UnusedVarChecker::visit (HIR::LetStmt &stmt)
41+
{
42+
HIR::Pattern &pattern = stmt.get_pattern ();
43+
check_variable (pattern);
44+
walk (stmt);
45+
}
46+
void
47+
UnusedVarChecker::visit_function_param (HIR::FunctionParam &param)
48+
{
49+
check_variable (param.get_param_name ());
50+
}
51+
52+
void
53+
UnusedVarChecker::visit (HIR::ConstantItem &item)
54+
{
55+
std::string var_name = item.get_identifier ().as_string ();
56+
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
57+
auto id = item.get_mappings ().get_hirid ();
58+
if (!unused_var_context.is_variable_used (id) && !starts_with_under_score)
59+
rust_warning_at (item.get_locus (), OPT_Wunused_variable,
60+
"unused name '%s'",
61+
item.get_identifier ().as_string ().c_str ());
62+
}
63+
64+
void
65+
UnusedVarChecker::visit (HIR::StaticItem &item)
66+
{
67+
std::string var_name = item.get_identifier ().as_string ();
68+
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
69+
auto id = item.get_mappings ().get_hirid ();
70+
if (!unused_var_context.is_variable_used (id) && !starts_with_under_score)
71+
rust_warning_at (item.get_locus (), OPT_Wunused_variable,
72+
"unused name '%s'",
73+
item.get_identifier ().as_string ().c_str ());
74+
}
75+
76+
void
77+
UnusedVarChecker::visit (HIR::TraitItemFunc &item)
78+
{
79+
// TODO: check trait item functions if they are not derived.
80+
}
81+
82+
void
83+
UnusedVarChecker::check_variable (HIR::Pattern &pattern)
84+
{
85+
switch (pattern.get_pattern_type ())
86+
{
87+
case HIR::Pattern::PatternType::IDENTIFIER:
88+
check_variable_identifier (
89+
static_cast<HIR::IdentifierPattern &> (pattern));
90+
break;
91+
case HIR::Pattern::PatternType::TUPLE:
92+
check_variable_tuple (static_cast<HIR::TuplePattern &> (pattern));
93+
break;
94+
default:
95+
break;
96+
}
97+
}
98+
void
99+
UnusedVarChecker::check_variable_identifier (HIR::IdentifierPattern &pattern)
100+
{
101+
std::string var_name = pattern.get_identifier ().as_string ();
102+
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
103+
auto id = pattern.get_mappings ().get_hirid ();
104+
if (!unused_var_context.is_variable_used (id) && var_name != "self"
105+
&& !starts_with_under_score)
106+
rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
107+
"unused name '%s'",
108+
pattern.get_identifier ().as_string ().c_str ());
109+
}
110+
void
111+
UnusedVarChecker::check_variable_tuple (HIR::TuplePattern &pattern)
112+
{
113+
switch (pattern.get_items ().get_item_type ())
114+
{
115+
case HIR::TupleItems::ItemType::MULTIPLE:
116+
{
117+
auto items = static_cast<HIR::TuplePatternItemsMultiple &> (
118+
pattern.get_items ());
119+
for (auto &item : items.get_patterns ())
120+
check_variable (*item);
121+
}
122+
break;
123+
default:
124+
break;
125+
}
126+
}
127+
} // namespace Analysis
128+
} // namespace Rust
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (C) 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+
#include "rust-hir-item.h"
20+
#include "rust-hir-visitor.h"
21+
#include "rust-immutable-name-resolution-context.h"
22+
#include "rust-unused-var-collector.h"
23+
24+
namespace Rust {
25+
namespace Analysis {
26+
class UnusedVarChecker : public HIR::DefaultHIRVisitor
27+
{
28+
public:
29+
UnusedVarChecker ();
30+
void go (HIR::Crate &crate);
31+
32+
private:
33+
const Resolver2_0::NameResolutionContext &nr_context;
34+
Analysis::Mappings &mappings;
35+
UnusedVarContext &unused_var_context;
36+
37+
using HIR::DefaultHIRVisitor::visit;
38+
virtual void visit (HIR::LetStmt &stmt) override;
39+
virtual void visit_function_param (HIR::FunctionParam &param) override;
40+
virtual void visit (HIR::TraitItemFunc &decl) override;
41+
virtual void visit (HIR::ConstantItem &item) override;
42+
virtual void visit (HIR::StaticItem &item) override;
43+
void check_variable_identifier (HIR::IdentifierPattern &identifier);
44+
void check_variable_tuple (HIR::TuplePattern &pattern);
45+
void check_variable (HIR::Pattern &pattern);
46+
};
47+
} // namespace Analysis
48+
} // namespace Rust
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright (C) 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+
#include "rust-unused-var-collector.h"
20+
#include "rust-hir-full-decls.h"
21+
#include "rust-hir-item.h"
22+
#include "rust-hir-path.h"
23+
#include "rust-immutable-name-resolution-context.h"
24+
25+
namespace Rust {
26+
namespace Analysis {
27+
UnusedVarCollector::UnusedVarCollector ()
28+
: nr_context (
29+
Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
30+
mappings (Analysis::Mappings::get ()),
31+
unused_var_context (*UnusedVarContext::get ())
32+
{}
33+
void
34+
UnusedVarCollector::go (HIR::Crate &crate)
35+
{
36+
for (auto &item : crate.get_items ())
37+
item->accept_vis (*this);
38+
}
39+
void
40+
UnusedVarCollector::visit (HIR::LetStmt &stmt)
41+
{
42+
HIR::Pattern &pattern = stmt.get_pattern ();
43+
collect_variable (pattern);
44+
walk (stmt);
45+
}
46+
47+
void
48+
UnusedVarCollector::visit (HIR::ConstantItem &item)
49+
{
50+
unused_var_context.add_variable (item.get_mappings ().get_hirid ());
51+
walk (item);
52+
}
53+
54+
void
55+
UnusedVarCollector::visit (HIR::StaticItem &item)
56+
{
57+
unused_var_context.add_variable (item.get_mappings ().get_hirid ());
58+
walk (item);
59+
}
60+
61+
void
62+
UnusedVarCollector::visit_function_param (HIR::FunctionParam &param)
63+
{
64+
collect_variable (param.get_param_name ());
65+
}
66+
67+
void
68+
UnusedVarCollector::visit_closure_param (HIR::ClosureParam &param)
69+
{
70+
collect_variable (param.get_pattern ());
71+
}
72+
73+
void
74+
UnusedVarCollector::collect_variable (HIR::Pattern &pattern)
75+
{
76+
switch (pattern.get_pattern_type ())
77+
{
78+
case HIR::Pattern::PatternType::IDENTIFIER:
79+
{
80+
auto &identifier = static_cast<HIR::IdentifierPattern &> (pattern);
81+
auto id = identifier.get_mappings ().get_hirid ();
82+
unused_var_context.add_variable (id);
83+
}
84+
break;
85+
case HIR::Pattern::PatternType::TUPLE:
86+
{
87+
collect_variable_tuple (static_cast<HIR::TuplePattern &> (pattern));
88+
}
89+
break;
90+
default:
91+
break;
92+
}
93+
}
94+
void
95+
UnusedVarCollector::collect_variable_tuple (HIR::TuplePattern &pattern)
96+
{
97+
switch (pattern.get_items ().get_item_type ())
98+
{
99+
case HIR::TuplePatternItems::ItemType::MULTIPLE:
100+
{
101+
auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
102+
pattern.get_items ());
103+
for (auto &sub : items.get_patterns ())
104+
collect_variable (*sub);
105+
}
106+
break;
107+
default:
108+
break;
109+
}
110+
}
111+
112+
void
113+
UnusedVarCollector::visit (HIR::PathInExpression &expr)
114+
{
115+
mark_path_used (expr);
116+
}
117+
118+
void
119+
UnusedVarCollector::visit (HIR::QualifiedPathInExpression &expr)
120+
{
121+
mark_path_used (expr);
122+
}
123+
124+
void
125+
UnusedVarCollector::visit (HIR::StructExprFieldIdentifier &ident)
126+
{
127+
mark_path_used (ident);
128+
}
129+
} // namespace Analysis
130+
} // namespace Rust

0 commit comments

Comments
 (0)