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

Commit 5830fa7

Browse files
committed
Metadata Collection: Collecting direct emission applicabilities (324/455)
1 parent ee8a99a commit 5830fa7

File tree

1 file changed

+93
-33
lines changed

1 file changed

+93
-33
lines changed

clippy_lints/src/utils/internal_lints/metadata_collector.rs

Lines changed: 93 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414
//! - [ ] TODO The Applicability for each lint for [#4310](https://github.com/rust-lang/rust-clippy/issues/4310)
1515
1616
// # Applicability
17-
// - TODO xFrednet 2021-01-17: Find all methods that take and modify applicability or predefine
18-
// them?
1917
// - TODO xFrednet 2021-01-17: Find lint emit and collect applicability
18+
// - TODO xFrednet 2021-02-27: Link applicability from function parameters
19+
// - (Examples: suspicious_operation_groupings:267, needless_bool.rs:311)
20+
// - TODO xFrednet 2021-02-27: Tuple if let thingy
21+
// - (Examples: unused_unit.rs:140, misc.rs:694)
2022
// # NITs
2123
// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
2224

2325
use if_chain::if_chain;
2426
use rustc_data_structures::fx::FxHashMap;
25-
use rustc_hir::{self as hir, ExprKind, Item, ItemKind, Mutability};
27+
use rustc_hir::{self as hir, intravisit, ExprKind, Item, ItemKind, Mutability};
2628
use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
29+
use rustc_middle::hir::map::Map;
2730
use rustc_session::{declare_tool_lint, impl_lint_pass};
2831
use rustc_span::{sym, Loc, Span, Symbol};
2932
use serde::Serialize;
@@ -33,13 +36,15 @@ use std::path::Path;
3336

3437
use crate::utils::internal_lints::is_lint_ref_type;
3538
use crate::utils::{
36-
last_path_segment, match_function_call, match_type, paths, span_lint, walk_ptrs_ty_depth, match_path,
39+
last_path_segment, match_function_call, match_path, match_type, paths, span_lint, walk_ptrs_ty_depth,
3740
};
3841

3942
/// This is the output file of the lint collector.
4043
const OUTPUT_FILE: &str = "metadata_collection.json";
4144
/// These lints are excluded from the export.
4245
const BLACK_LISTED_LINTS: [&str; 2] = ["lint_author", "deep_code_inspection"];
46+
/// These groups will be ignored by the lint group matcher
47+
const BLACK_LISTED_LINT_GROUP: [&str; 1] = ["clippy::all"];
4348

4449
// TODO xFrednet 2021-02-15: `span_lint_and_then` & `span_lint_hir_and_then` requires special
4550
// handling
@@ -52,6 +57,9 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 5] = [
5257
&["clippy_utils", "diagnostics", "span_lint_and_sugg"],
5358
];
5459

60+
/// The index of the applicability name of `paths::APPLICABILITY_VALUES`
61+
const APPLICABILITY_NAME_INDEX: usize = 2;
62+
5563
declare_clippy_lint! {
5664
/// **What it does:** Collects metadata about clippy lints for the website.
5765
///
@@ -297,6 +305,10 @@ fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Ite
297305

298306
fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
299307
for (group_name, lints, _) in &cx.lint_store.get_lint_groups() {
308+
if BLACK_LISTED_LINT_GROUP.contains(group_name) {
309+
continue;
310+
}
311+
300312
if lints.iter().any(|x| *x == lint_id) {
301313
return Some((*group_name).to_string());
302314
}
@@ -341,7 +353,10 @@ fn match_simple_lint_emission<'hir>(
341353
}
342354

343355
/// This returns the lint name and the possible applicability of this emission
344-
fn extract_emission_info<'hir>(cx: &LateContext<'hir>, args: &[hir::Expr<'_>]) -> Option<(String, Option<String>)> {
356+
fn extract_emission_info<'hir>(
357+
cx: &LateContext<'hir>,
358+
args: &'hir [hir::Expr<'hir>],
359+
) -> Option<(String, Option<String>)> {
345360
let mut lint_name = None;
346361
let mut applicability = None;
347362

@@ -358,41 +373,38 @@ fn extract_emission_info<'hir>(cx: &LateContext<'hir>, args: &[hir::Expr<'_>]) -
358373
}
359374
}
360375

361-
lint_name.map(|lint_name| {
362-
(
363-
sym_to_string(lint_name).to_ascii_lowercase(),
364-
applicability,
365-
)
366-
})
376+
lint_name.map(|lint_name| (sym_to_string(lint_name).to_ascii_lowercase(), applicability))
367377
}
368378

369-
fn resolve_applicability(cx: &LateContext<'hir>, expr: &hir::Expr<'_>) -> Option<String> {
379+
/// This function tries to resolve the linked applicability to the given expression.
380+
fn resolve_applicability(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<String> {
370381
match expr.kind {
371382
// We can ignore ifs without an else block because those can't be used as an assignment
372-
hir::ExprKind::If(_con, _if_block, Some(_else_block)) => {
373-
// self.process_assign_expr(if_block);
374-
// self.process_assign_expr(else_block);
375-
return Some("TODO IF EXPR".to_string());
383+
hir::ExprKind::If(_con, if_block, Some(else_block)) => {
384+
let mut visitor = ApplicabilityVisitor::new(cx);
385+
intravisit::walk_expr(&mut visitor, if_block);
386+
intravisit::walk_expr(&mut visitor, else_block);
387+
visitor.complete()
376388
},
377-
hir::ExprKind::Match(_expr, _arms, _) => {
378-
// for arm in *arms {
379-
// self.process_assign_expr(arm.body);
380-
// }
381-
return Some("TODO MATCH EXPR".to_string());
389+
hir::ExprKind::Match(_expr, arms, _) => {
390+
let mut visitor = ApplicabilityVisitor::new(cx);
391+
arms.iter()
392+
.for_each(|arm| intravisit::walk_expr(&mut visitor, arm.body));
393+
visitor.complete()
382394
},
383395
hir::ExprKind::Loop(block, ..) | hir::ExprKind::Block(block, ..) => {
384-
if let Some(block_expr) = block.expr {
385-
return resolve_applicability(cx, block_expr);
386-
}
396+
let mut visitor = ApplicabilityVisitor::new(cx);
397+
intravisit::walk_block(&mut visitor, block);
398+
visitor.complete()
387399
},
388400
ExprKind::Path(hir::QPath::Resolved(_, path)) => {
389401
// direct applicabilities are simple:
390402
for enum_value in &paths::APPLICABILITY_VALUES {
391403
if match_path(path, enum_value) {
392-
return Some(enum_value[2].to_string());
404+
return Some(enum_value[APPLICABILITY_NAME_INDEX].to_string());
393405
}
394406
}
395-
407+
396408
// Values yay
397409
if let hir::def::Res::Local(local_hir) = path.res {
398410
if let Some(local) = get_parent_local(cx, local_hir) {
@@ -401,19 +413,67 @@ fn resolve_applicability(cx: &LateContext<'hir>, expr: &hir::Expr<'_>) -> Option
401413
}
402414
}
403415
}
416+
417+
// This is true for paths that are linked to function parameters. They might be a bit more work so
418+
// not today :)
419+
None
420+
},
421+
_ => None,
422+
}
423+
}
424+
425+
fn get_parent_local(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
426+
let map = cx.tcx.hir();
427+
428+
match map.find(map.get_parent_node(hir_id)) {
429+
Some(hir::Node::Local(local)) => Some(local),
430+
Some(hir::Node::Pat(pattern)) => get_parent_local(cx, pattern.hir_id),
431+
_ => None,
432+
}
433+
}
434+
435+
/// This visitor finds the highest applicability value in the visited expressions
436+
struct ApplicabilityVisitor<'a, 'hir> {
437+
cx: &'a LateContext<'hir>,
438+
/// This is the index of hightest `Applicability` for
439+
/// `clippy_utils::paths::APPLICABILITY_VALUES`
440+
applicability_index: Option<usize>,
441+
}
442+
443+
impl<'a, 'hir> ApplicabilityVisitor<'a, 'hir> {
444+
fn new(cx: &'a LateContext<'hir>) -> Self {
445+
Self {
446+
cx,
447+
applicability_index: None,
404448
}
405-
_ => {}
406449
}
407450

451+
fn add_new_index(&mut self, new_index: usize) {
452+
self.applicability_index = self
453+
.applicability_index
454+
.map_or(new_index, |old_index| old_index.min(new_index))
455+
.into();
456+
}
408457

409-
Some("TODO".to_string())
458+
fn complete(self) -> Option<String> {
459+
self.applicability_index
460+
.map(|index| paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX].to_string())
461+
}
410462
}
411463

412-
fn get_parent_local(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
413-
let map = cx.tcx.hir();
414-
if let Some(hir::Node::Local(local)) = map.find(map.get_parent_node(hir_id)) {
415-
return Some(local);
464+
impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityVisitor<'a, 'hir> {
465+
type Map = Map<'hir>;
466+
467+
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
468+
intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
416469
}
417470

418-
None
471+
fn visit_path(&mut self, path: &hir::Path<'_>, _id: hir::HirId) {
472+
for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() {
473+
if match_path(path, enum_value) {
474+
self.add_new_index(index);
475+
break;
476+
}
477+
}
478+
}
419479
}

0 commit comments

Comments
 (0)