// <http://www.gnu.org/licenses/>.
#include "rust-unused-var-checker.h"
+#include "rust-hir-expr.h"
#include "rust-hir-item.h"
#include "options.h"
: nr_context (
Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()),
mappings (Analysis::Mappings::get ()),
- unused_var_context (std::make_unique<UnusedVarContext> ())
+ unused_var_context (UnusedVarContext ())
{}
void
UnusedVarChecker::go (HIR::Crate &crate)
{
- UnusedVarCollector collector (*unused_var_context);
+ UnusedVarCollector collector (unused_var_context);
collector.go (crate);
for (auto &item : crate.get_items ())
item->accept_vis (*this);
std::string var_name = item.get_identifier ().as_string ();
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
auto id = item.get_mappings ().get_hirid ();
- if (!unused_var_context->is_variable_used (id) && !starts_with_under_score)
- rust_warning_at (item.get_locus (), OPT_Wunused_variable,
- "unused name '%s'",
+ if (!unused_var_context.is_variable_used (id) && !starts_with_under_score)
+ rust_warning_at (item.get_locus (), OPT_Wunused_variable, "unused name %qs",
item.get_identifier ().as_string ().c_str ());
}
std::string var_name = item.get_identifier ().as_string ();
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
auto id = item.get_mappings ().get_hirid ();
- if (!unused_var_context->is_variable_used (id) && !starts_with_under_score)
- rust_warning_at (item.get_locus (), OPT_Wunused_variable,
- "unused name '%s'",
+ if (!unused_var_context.is_variable_used (id) && !starts_with_under_score)
+ rust_warning_at (item.get_locus (), OPT_Wunused_variable, "unused name %qs",
item.get_identifier ().as_string ().c_str ());
}
std::string var_name = pattern.get_identifier ().as_string ();
bool starts_with_under_score = var_name.compare (0, 1, "_") == 0;
auto id = pattern.get_mappings ().get_hirid ();
- if (!unused_var_context->is_variable_used (id) && var_name != "self"
+ if (!unused_var_context.is_variable_used (id) && var_name != "self"
&& !starts_with_under_score)
rust_warning_at (pattern.get_locus (), OPT_Wunused_variable,
- "unused name '%s'",
+ "unused name %qs",
pattern.get_identifier ().as_string ().c_str ());
}
+void
+
+UnusedVarChecker::visit (HIR::AssignmentExpr &expr)
+
+{
+ const auto &lhs = expr.get_lhs ();
+ auto var_name = lhs.to_string ();
+ NodeId ast_node_id = lhs.get_mappings ().get_nodeid ();
+ NodeId def_id = nr_context.lookup (ast_node_id).value ();
+ HirId id = mappings.lookup_node_to_hir (def_id).value ();
+ if (unused_var_context.is_variable_assigned (id,
+ lhs.get_mappings ().get_hirid ())
+ && !starts_with_under_score)
+ rust_warning_at (lhs.get_locus (), OPT_Wunused_variable,
+ "unused assignment %qs", var_name.c_str ());
+}
} // namespace Analysis
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+#include "rust-hir-expr.h"
#include "rust-hir-item.h"
#include "rust-hir-pattern.h"
#include "rust-hir-visitor.h"
private:
const Resolver2_0::NameResolutionContext &nr_context;
Analysis::Mappings &mappings;
- std::unique_ptr<UnusedVarContext> unused_var_context;
+ UnusedVarContext unused_var_context;
using HIR::DefaultHIRVisitor::visit;
virtual void visit (HIR::TraitItemFunc &decl) override;
virtual void visit (HIR::ConstantItem &item) override;
virtual void visit (HIR::StaticItem &item) override;
virtual void visit (HIR::IdentifierPattern &identifier) override;
+ virtual void visit (HIR::AssignmentExpr &identifier) override;
};
} // namespace Analysis
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
// <http://www.gnu.org/licenses/>.
#include "rust-unused-var-collector.h"
+#include "rust-hir-expr.h"
#include "rust-hir-full-decls.h"
#include "rust-hir-item.h"
#include "rust-hir-path.h"
#include "rust-hir-pattern.h"
#include "rust-immutable-name-resolution-context.h"
+#include "tree-check.h"
namespace Rust {
namespace Analysis {
void
UnusedVarCollector::visit (HIR::IdentifierPattern &pattern)
{
- auto id = pattern.get_mappings ().get_hirid ();
- unused_var_context.add_variable (id);
+ unused_var_context.add_variable (pattern.get_mappings ().get_hirid ());
}
void
{
mark_path_used (ident);
}
+void
+UnusedVarCollector::visit (HIR::AssignmentExpr &expr)
+{
+ auto def_id = get_def_id (expr.get_lhs ());
+ HirId id = expr.get_lhs ().get_mappings ().get_hirid ();
+ unused_var_context.add_assign (def_id, id);
+ visit_outer_attrs (expr);
+ expr.get_rhs ().accept_vis (*this);
+}
+
} // namespace Analysis
} // namespace Rust
virtual void visit (HIR::StaticItem &item) override;
virtual void visit (HIR::IdentifierPattern &pattern) override;
virtual void visit (HIR::QualifiedPathInExpression &expr) override;
+ virtual void visit (HIR::AssignmentExpr &expr) override;
- template <typename T> void mark_path_used (T &path_expr)
+ template <typename T> HirId get_def_id (T &path_expr)
{
NodeId ast_node_id = path_expr.get_mappings ().get_nodeid ();
- NodeId def_id = nr_context.lookup (ast_node_id).value ();
- HirId hir_id = mappings.lookup_node_to_hir (def_id).value ();
- unused_var_context.mark_used (hir_id);
+ NodeId id = nr_context.lookup (ast_node_id).value ();
+ HirId def_id = mappings.lookup_node_to_hir (id).value ();
+ return def_id;
+ }
+
+ template <typename T> void mark_path_used (T &path_expr)
+ {
+ auto def_id = get_def_id (path_expr);
+ unused_var_context.mark_used (def_id);
+ unused_var_context.remove_assign (def_id);
}
};
} // namespace Analysis
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
return it != is_used.end () && it->second;
}
+void
+UnusedVarContext::add_assign (HirId id_def, HirId id)
+{
+ assigned_vars[id_def].push_back (id);
+}
+
+void
+UnusedVarContext::remove_assign (HirId id_def)
+{
+ if (assigned_vars.find (id_def) != assigned_vars.end ())
+ assigned_vars[id_def].pop_back ();
+}
+bool
+UnusedVarContext::is_variable_assigned (HirId id_def, HirId id)
+{
+ auto assigned_vec = assigned_vars[id_def];
+ return std::find (assigned_vec.begin (), assigned_vec.end (), id)
+ != assigned_vec.end ();
+}
+
std::string
UnusedVarContext::as_string () const
{
public:
void add_variable (HirId id);
void mark_used (HirId id);
-
bool is_variable_used (HirId id) const;
+ void add_assign (HirId id_def, HirId id);
+ void remove_assign (HirId id_def);
+ bool is_variable_assigned (HirId id_def, HirId id);
+
std::string as_string () const;
private:
std::map<HirId, bool> is_used;
+ std::map<HirId, std::vector<HirId>> assigned_vars;
};
} // namespace Analysis
--- /dev/null
+// { dg-additional-options "-frust-unused-check-2.0" }
+pub fn a()->i32 {
+ let mut a = 1;
+ a = 2;
+// { dg-warning "unused assignment .a." "" { target *-*-* } .-1 }
+ a = 3;
+// { dg-warning "unused assignment .a." "" { target *-*-* } .-1 }
+ a = 4;
+// { dg-warning "unused assignment .a." "" { target *-*-* } .-1 }
+ a = 5;
+ let mut b = a;
+ b = 1;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+ b = 2;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+ b = 3;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+ b = 4;
+// { dg-warning "unused assignment .b." "" { target *-*-* } .-1 }
+ b = 5;
+ return b
+}