From a1372eb5bc08dcd69bf34888568d1164ab81e137 Mon Sep 17 00:00:00 2001 From: xiongmao86 Date: Sun, 9 Feb 2020 23:59:41 +0800 Subject: [PATCH] Implement lint logic. --- clippy_lints/src/utils/internal_lints.rs | 108 ++++++++++++++++++++++- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index cd191261dfb7..aec158c71a45 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,6 @@ 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, + walk_ptrs_ty, snippet_opt }; use if_chain::if_chain; use rustc::hir::map::Map; @@ -404,8 +404,108 @@ fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool { declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); -impl EarlyLintPass for CollapsibleCalls { +impl EarlyLintPass for CollapsibleCalls { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - span_lint_and_help(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.span, "lint_message", "help_message"); + use ast::ExprKind; + + if_chain! { + if let ExprKind::Call(ref func, ref and_then_args) = expr.kind; + if let ExprKind::Path(None, ref path) = func.kind; + if let match_path_ast(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; + let stmts = block.stmts; + if stmts.len() == 1; + if let StmtKind::Expr(only_expr) = stmts[0].kind; + if let ExprKind::MethodCall(ps, span_call_args) = only_expr.kind; + then { + 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); + + match ps.ident.name.as_str() { + "span_suggestion" => { + 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); + + if span_snippet == span_snippet_of_span_call { + span_lint_and_sugg ( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_sugg({}, {}, {}, {}, {}, {},{})", + cx_snippet, + lint_snippet, + span_snippet, + msg_snippet, + help_snippet, + sugg_snippet, + applicability_snippet + ), + Applicability::MachineApplicable + ); + } + }, + "span_help" => { + let span_snippet_of_span_call = snippet(cx, span_call_args[0].span); + let help_snippet = snippet(cx, span_call_args[1].span); + + if span_snippet == span_snippet_of_span_call { + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_help({}, {}, {}, {},{})", + cx_snippet, + lint_snippet, + span_snippet, + msg_snippet, + help_snippet + ), + Applicability::MachineApplicable + ); + } + }, + "span_note" => { + let span_snippet_of_span_call = snippet(cx, span_call_args[0].span); + let note_snippet = snippet(cx, span_call_args[1].span); + + if span_snippet == span_snippet_of_span_call { + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collspible", + "collapse into", + format!( + "span_lint_and_note({},{}, {}, {}, {})", + cx_snippet, + lint_snippet, + span_snippet, + msg_snippet, + note_snippet + ), + Applicability::MachineApplicable + ); + } + }, + _ => (), + } + } + } } -} \ No newline at end of file +} + +fn snippet(cx: &EarlyContext<'_>, span: Span) -> String { + snippet_opt(cx, span).expect("should be able to retrive span.") +}