Skip to content

Commit

Permalink
Use SpanlessEq to test for span equality.
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongmao86 committed Mar 27, 2020
1 parent 1cee809 commit b8cb469
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 184 deletions.
5 changes: 2 additions & 3 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box wildcard_imports::WildcardImports);
store.register_early_pass(|| box macro_use::MacroUseImports);
store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
store.register_early_pass(|| box utils::internal_lints::CollapsibleCalls);
store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);

store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
Expand Down Expand Up @@ -1125,13 +1125,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:

store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL),
LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
LintId::of(&utils::internal_lints::DEFAULT_LINT),
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
LintId::of(&utils::internal_lints::PRODUCE_ICE),
LintId::of(&utils::internal_lints::DEFAULT_LINT),
LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
]);

store.register_group(true, "clippy::all", Some("clippy"), vec![
Expand Down
269 changes: 127 additions & 142 deletions clippy_lints/src/utils/internal_lints.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
use crate::utils::SpanlessEq;
use crate::utils::{
is_expn_of, match_def_path, match_type, method_calls, paths, span_lint, span_lint_and_help, span_lint_and_sugg,
walk_ptrs_ty, snippet as other_snippet, match_path_ast
is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, snippet as other_snippet, span_lint,
span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_ast::ast;
use rustc_ast::ast::{Crate as AstCrate, Expr as AstExpr, ItemKind, LitKind, Name, NodeId};
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, Name, NodeId};
use rustc_ast::visit::FnKind;
use rustc_ast::ptr::P;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, Ty, TyKind};
use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::SymbolStr;


use std::borrow::Cow;

declare_clippy_lint! {
Expand Down Expand Up @@ -176,7 +174,7 @@ impl EarlyLintPass for ClippyLintsInternal {
CLIPPY_LINTS_INTERNAL,
item.span,
"this constant should be before the previous constant due to lexical \
ordering",
ordering",
);
}
}
Expand Down Expand Up @@ -206,8 +204,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind;
if let ExprKind::Struct(_, ref fields, _) = inner_exp.kind;
let field = fields.iter()
.find(|f| f.ident.as_str() == "desc")
.expect("lints must have a description field");
.find(|f| f.ident.as_str() == "desc")
.expect("lints must have a description field");
if let ExprKind::Lit(Spanned {
node: LitKind::Str(ref sym, _),
..
Expand Down Expand Up @@ -343,7 +341,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
if let Some(sugg) = self.map.get(&*fn_name.as_str());
let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
if match_type(cx, ty, &paths::EARLY_CONTEXT)
|| match_type(cx, ty, &paths::LATE_CONTEXT);
|| match_type(cx, ty, &paths::LATE_CONTEXT);
then {
span_lint_and_help(
cx,
Expand Down Expand Up @@ -405,175 +403,162 @@ fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {

declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);

impl EarlyLintPass for CollapsibleCalls {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &AstExpr) {
use ast::{StmtKind, ExprKind};

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CollapsibleCalls {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
if let ExprKind::Call(ref func, ref and_then_args) = expr.kind;
if let ExprKind::Path(None, ref path) = func.kind;
if match_path_ast(path, &["span_lint_and_then"]);
if let ExprKind::Path(ref path) = func.kind;
if match_qpath(path, &["span_lint_and_then"]);
if and_then_args.len() == 5;
if let ExprKind::Closure(_, _, _, _, block, _) = &and_then_args[4].kind;
if let ExprKind::Block(block, _) = &block.kind;
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
if let body = cx.tcx.hir().body(*body_id);
if let ExprKind::Block(block, _) = &body.value.kind;
let stmts = &block.stmts;
if stmts.len() == 1;
if let StmtKind::Expr(only_expr) = &stmts[0].kind;
if let ExprKind::MethodCall(ref ps, ref span_call_args) = &only_expr.kind;
let and_then_args = get_and_then_args(cx, and_then_args);
//
if let StmtKind::Semi(only_expr) = &stmts[0].kind;
if let ExprKind::MethodCall(ref ps, _, ref span_call_args) = &only_expr.kind;
let and_then_snippets = get_and_then_snippets(cx, and_then_args);
let mut sle = SpanlessEq::new(cx).ignore_fn();
then {
match &*ps.ident.as_str() {
"span_suggestion" =>
suggest_span_suggestion(cx, expr, and_then_args, suggestion_args(cx, span_call_args)),
"span_help" =>
suggest_span_help(cx, expr, and_then_args, help_args(cx, span_call_args)),
"span_note" =>
suggest_span_note(cx, expr, and_then_args, note_args(cx, span_call_args)),
"span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
suggest_suggestion(cx, expr, and_then_snippets, span_suggestion_snippets(cx, span_call_args));
},
"span_suggestion" => {
dbg!(&span_call_args[0]);
dbg!(&span_call_args[1]);
dbg!(&span_call_args[2]);
}
"span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
let help_snippet = snippet(cx, span_call_args[2].span);
suggest_help(cx, expr, and_then_snippets, help_snippet);
},
"span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
let note_snippet = snippet(cx, span_call_args[2].span);
suggest_note(cx, expr, and_then_snippets, note_snippet);
},
"help" => {
let help_snippet = snippet(cx, span_call_args[1].span);
suggest_help(cx, expr, and_then_snippets, help_snippet);
}
"note" => {
let note_snippet = snippet(cx, span_call_args[1].span);
suggest_note(cx, expr, and_then_snippets, note_snippet);
}
_ => (),
}
}
}
}
}

struct AndThenArgs<'a> {
struct AndThenSnippets<'a> {
cx: Cow<'a, str>,
lint: Cow<'a, str>,
span: Cow<'a, str>,
msg: Cow<'a, str>,
}

fn get_and_then_args<'a>(cx: &EarlyContext<'_>, and_then_args: &Vec<P<AstExpr>>) -> AndThenArgs<'a>{
let cx_snippet = snippet(cx, and_then_args[0].span);
let lint_snippet= snippet(cx, and_then_args[1].span);
let span_snippet = snippet(cx, and_then_args[2].span);
let msg_snippet= snippet(cx, and_then_args[3].span);
fn get_and_then_snippets<'a, 'hir>(
cx: &LateContext<'_, '_>,
and_then_snippets: &'hir [Expr<'hir>],
) -> AndThenSnippets<'a> {
let cx_snippet = snippet(cx, and_then_snippets[0].span);
let lint_snippet = snippet(cx, and_then_snippets[1].span);
let span_snippet = snippet(cx, and_then_snippets[2].span);
let msg_snippet = snippet(cx, and_then_snippets[3].span);

AndThenArgs {
AndThenSnippets {
cx: cx_snippet,
lint: lint_snippet,
span: span_snippet,
msg: msg_snippet,
}
}

struct SuggestionArgs<'a> {
span: Cow<'a, str>,
struct SpanSuggestionSnippets<'a> {
help: Cow<'a, str>,
sugg: Cow<'a, str>,
applicability: Cow<'a, str>,
}

fn suggestion_args<'a>(cx: &EarlyContext<'_>, span_call_args: &Vec<P<AstExpr>>) -> SuggestionArgs<'a> {
let span_snippet_of_span_call = snippet(cx, span_call_args[0].span);
let help_snippet = snippet(cx, span_call_args[1].span);
let sugg_snippet = snippet(cx, span_call_args[2].span);
let applicability_snippet = snippet(cx, span_call_args[3].span);
fn span_suggestion_snippets<'a, 'hir>(
cx: &LateContext<'_, '_>,
span_call_args: &'hir [Expr<'hir>],
) -> SpanSuggestionSnippets<'a> {
let help_snippet = snippet(cx, span_call_args[2].span);
let sugg_snippet = snippet(cx, span_call_args[3].span);
let applicability_snippet = snippet(cx, span_call_args[4].span);

SuggestionArgs {
span: span_snippet_of_span_call,
SpanSuggestionSnippets {
help: help_snippet,
sugg: sugg_snippet,
applicability: applicability_snippet,
}
}

fn suggest_span_suggestion(cx: &EarlyContext<'_>, expr: &AstExpr, and_then_args: AndThenArgs<'_>, suggestion_args: SuggestionArgs<'_>) {
if and_then_args.span == suggestion_args.span {
println!("suggestion true");
span_lint_and_sugg (
cx,
COLLAPSIBLE_SPAN_LINT_CALLS,
expr.span,
"this call is collapsible",
"collapse into",
format!(
"span_lint_and_sugg({}, {}, {}, {}, {}, {},{})",
and_then_args.cx,
and_then_args.lint,
and_then_args.span,
and_then_args.msg,
suggestion_args.help,
suggestion_args.sugg,
suggestion_args.applicability
),
Applicability::MachineApplicable
);
}
}

struct HelpArgs<'a> {
span: Cow<'a, str>,
help: Cow<'a, str>,
}

fn help_args<'a>(cx: &EarlyContext<'_>, span_call_args: &Vec<P<AstExpr>>) -> HelpArgs<'a>{
let span_snippet_of_span_call = snippet(cx, span_call_args[0].span);
let help_snippet = snippet(cx, span_call_args[1].span);

HelpArgs {
span: span_snippet_of_span_call,
help: help_snippet,
}
}

fn suggest_span_help(cx: &EarlyContext<'_>, expr: &AstExpr, and_then_args: AndThenArgs<'_>, help_args: HelpArgs<'_>) {
if and_then_args.span == help_args.span {
span_lint_and_sugg(
cx,
COLLAPSIBLE_SPAN_LINT_CALLS,
expr.span,
"this call is collapsible",
"collapse into",
format!(
"span_lint_and_help({}, {}, {}, {},{})",
and_then_args.cx,
and_then_args.lint,
and_then_args.span,
and_then_args.msg,
help_args.help
),
Applicability::MachineApplicable
);
}
}

struct NoteArgs<'a> {
span: Cow<'a, str>,
note: Cow<'a, str>,
}

fn note_args<'a>(cx: &EarlyContext<'_>, span_call_args: &Vec<P<AstExpr>>) -> NoteArgs<'a> {
let span_snippet_of_span_call = snippet(cx, span_call_args[0].span);
let note_snippet = snippet(cx, span_call_args[1].span);

NoteArgs {
span: span_snippet_of_span_call,
note: note_snippet,
}
}

fn suggest_span_note(cx: &EarlyContext<'_>, expr: &AstExpr, and_then_args: AndThenArgs<'_> , note_args: NoteArgs<'_> ) {
if and_then_args.span == note_args.span {
span_lint_and_sugg(
cx,
COLLAPSIBLE_SPAN_LINT_CALLS,
expr.span,
"this call is collspible",
"collapse into",
format!(
"span_lint_and_note({},{}, {}, {}, {})",
and_then_args.cx,
and_then_args.lint,
and_then_args.span,
and_then_args.msg,
note_args.note
),
Applicability::MachineApplicable
);
}
}

fn snippet<'a>(cx: &EarlyContext<'_>, span: Span) -> Cow<'a, str> {
other_snippet(cx, span, "Should not be")
fn suggest_suggestion(
cx: &LateContext<'_, '_>,
expr: &Expr<'_>,
and_then_snippets: AndThenSnippets<'_>,
span_suggestion_snippets: SpanSuggestionSnippets<'_>,
) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_SPAN_LINT_CALLS,
expr.span,
"this call is collapsible",
"collapse into",
format!(
"span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
and_then_snippets.cx,
and_then_snippets.lint,
and_then_snippets.span,
and_then_snippets.msg,
span_suggestion_snippets.help,
span_suggestion_snippets.sugg,
span_suggestion_snippets.applicability
),
Applicability::MachineApplicable,
);
}

fn suggest_help(cx: &LateContext<'_, '_>, expr: &Expr<'_>, and_then_snippets: AndThenSnippets<'_>, help: Cow<'_, str>) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_SPAN_LINT_CALLS,
expr.span,
"this call is collapsible",
"collapse into",
format!(
"span_lint_and_help({}, {}, {}, {}, {})",
and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, help
),
Applicability::MachineApplicable,
);
}

fn suggest_note(cx: &LateContext<'_, '_>, expr: &Expr<'_>, and_then_snippets: AndThenSnippets<'_>, note: Cow<'_, str>) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_SPAN_LINT_CALLS,
expr.span,
"this call is collspible",
"collapse into",
format!(
"span_lint_and_note({}, {}, {}, {}, {}, {})",
and_then_snippets.cx,
and_then_snippets.lint,
and_then_snippets.span,
and_then_snippets.msg,
and_then_snippets.span,
note
),
Applicability::MachineApplicable,
);
}

fn snippet<'a>(cx: &LateContext<'_, '_>, span: Span) -> Cow<'a, str> {
other_snippet(cx, span, "Should not be this snippet")
}
Loading

0 comments on commit b8cb469

Please sign in to comment.