Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 35844d0

Browse files
committed
Metadata collection: Resolve lint from locals
1 parent 2ce5e36 commit 35844d0

File tree

3 files changed

+699
-569
lines changed

3 files changed

+699
-569
lines changed

clippy_lints/src/utils/internal_lints/metadata_collector.rs

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
1616
// # Applicability
1717
// - TODO xFrednet 2021-01-17: Find lint emit and collect applicability
18-
// - TODO xFrednet 2021-02-28: 1x reference to closure
19-
// - See clippy_lints/src/needless_pass_by_value.rs@NeedlessPassByValue::check_fn
2018
// - TODO xFrednet 2021-02-28: 4x weird emission forwarding
2119
// - See clippy_lints/src/enum_variants.rs@EnumVariantNames::check_name
2220
// - TODO xFrednet 2021-02-28: 6x emission forwarding with local that is initializes from
@@ -26,14 +24,12 @@
2624
// - See clippy_lints/src/misc.rs@check_binary
2725
// - TODO xFrednet 2021-02-28: 2x lint from local from method call
2826
// - See clippy_lints/src/non_copy_const.rs@lint
29-
// - TODO xFrednet 2021-02-28: 20x lint from local
30-
// - See clippy_lints/src/map_unit_fn.rs@lint_map_unit_fn
3127
// # NITs
3228
// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
3329

3430
use if_chain::if_chain;
3531
use rustc_data_structures::fx::FxHashMap;
36-
use rustc_hir::{self as hir, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath};
32+
use rustc_hir::{self as hir, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath, def::DefKind};
3733
use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
3834
use rustc_middle::hir::map::Map;
3935
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -49,7 +45,7 @@ use crate::utils::{
4945
};
5046

5147
/// This is the output file of the lint collector.
52-
const OUTPUT_FILE: &str = "metadata_collection.json";
48+
const OUTPUT_FILE: &str = "../metadata_collection.json";
5349
/// These lints are excluded from the export.
5450
const BLACK_LISTED_LINTS: [&str; 2] = ["lint_author", "deep_code_inspection"];
5551
/// These groups will be ignored by the lint group matcher. This is useful for collections like
@@ -270,12 +266,16 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
270266
/// ```
271267
fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) {
272268
if let Some(args) = match_lint_emission(cx, expr) {
273-
if let Some((lint_name, applicability, is_multi_part)) = extract_complex_emission_info(cx, args) {
269+
let mut emission_info = extract_complex_emission_info(cx, args);
270+
if emission_info.is_empty() {
271+
lint_collection_error_span(cx, expr.span, "Look, here ... I have no clue what todo with it");
272+
return;
273+
}
274+
275+
for (lint_name, applicability, is_multi_part) in emission_info.drain(..) {
274276
let app_info = self.applicability_into.entry(lint_name).or_default();
275277
app_info.applicability = applicability;
276278
app_info.is_multi_suggestion = is_multi_part;
277-
} else {
278-
lint_collection_error_span(cx, expr.span, "Look, here ... I have no clue what todo with it");
279279
}
280280
}
281281
}
@@ -380,8 +380,8 @@ fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>)
380380
fn extract_complex_emission_info<'hir>(
381381
cx: &LateContext<'hir>,
382382
args: &'hir [hir::Expr<'hir>],
383-
) -> Option<(String, Option<String>, bool)> {
384-
let mut lint_name = None;
383+
) -> Vec<(String, Option<String>, bool)> {
384+
let mut lints= Vec::new();
385385
let mut applicability = None;
386386
let mut multi_part = false;
387387

@@ -390,9 +390,8 @@ fn extract_complex_emission_info<'hir>(
390390

391391
if match_type(cx, arg_ty, &paths::LINT) {
392392
// If we found the lint arg, extract the lint name
393-
if let ExprKind::Path(ref lint_path) = arg.kind {
394-
lint_name = Some(last_path_segment(lint_path).ident.name);
395-
}
393+
let mut resolved_lints = resolve_lints(cx, arg);
394+
lints.append(&mut resolved_lints);
396395
} else if match_type(cx, arg_ty, &paths::APPLICABILITY) {
397396
applicability = resolve_applicability(cx, arg);
398397
} else if arg_ty.is_closure() {
@@ -402,7 +401,14 @@ fn extract_complex_emission_info<'hir>(
402401
}
403402
}
404403

405-
lint_name.map(|lint_name| (sym_to_string(lint_name).to_ascii_lowercase(), applicability, multi_part))
404+
lints.drain(..).map(|lint_name| (lint_name, applicability.clone(), multi_part)).collect()
405+
}
406+
407+
/// Resolves the possible lints that this expression could reference
408+
fn resolve_lints(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
409+
let mut resolver = LintResolver::new(cx);
410+
resolver.visit_expr(expr);
411+
resolver.lints
406412
}
407413

408414
/// This function tries to resolve the linked applicability to the given expression.
@@ -426,6 +432,50 @@ fn check_is_multi_part(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hi
426432
false
427433
}
428434

435+
struct LintResolver<'a, 'hir> {
436+
cx: &'a LateContext<'hir>,
437+
lints: Vec<String>,
438+
}
439+
440+
impl<'a, 'hir> LintResolver<'a, 'hir> {
441+
fn new(cx: &'a LateContext<'hir>) -> Self {
442+
Self {
443+
cx,
444+
lints: Vec::<String>::default(),
445+
}
446+
}
447+
}
448+
449+
impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
450+
type Map = Map<'hir>;
451+
452+
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
453+
intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
454+
}
455+
456+
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
457+
if_chain! {
458+
if let ExprKind::Path(qpath) = &expr.kind;
459+
if let QPath::Resolved(_, path) = qpath;
460+
461+
let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
462+
if match_type(self.cx, expr_ty, &paths::LINT);
463+
then {
464+
if let hir::def::Res::Def(DefKind::Static, _) = path.res {
465+
let lint_name = last_path_segment(qpath).ident.name;
466+
self.lints.push(sym_to_string(lint_name).to_ascii_lowercase());
467+
} else if let Some(local) = get_parent_local(self.cx, expr) {
468+
if let Some(local_init) = local.init {
469+
intravisit::walk_expr(self, local_init);
470+
}
471+
}
472+
}
473+
}
474+
475+
intravisit::walk_expr(self, expr);
476+
}
477+
}
478+
429479
/// This visitor finds the highest applicability value in the visited expressions
430480
struct ApplicabilityResolver<'a, 'hir> {
431481
cx: &'a LateContext<'hir>,
@@ -488,7 +538,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
488538
}
489539
}
490540

491-
/// This returns the parent local node if the expression is a reference to
541+
/// This returns the parent local node if the expression is a reference one
492542
fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
493543
if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
494544
if let hir::def::Res::Local(local_hir) = path.res {

clippy_utils/src/paths.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
8383
#[cfg(feature = "internal-lints")]
8484
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
8585
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
86-
#[cfg(feature = "internal-lints")]
86+
#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
8787
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
8888
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
8989
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];

0 commit comments

Comments
 (0)