]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/cognitive_complexity.rs
rustup https://github.com/rust-lang/rust/pull/68944
[rust.git] / clippy_lints / src / cognitive_complexity.rs
index 33603b27b7a4b9db146f145d2d25fc6cc66e97be..fcab459018848c5539438e6ead9cb67f4f6c008d 100644 (file)
@@ -1,13 +1,15 @@
 //! calculate cognitive complexity and warn about overly complex functions
 
-use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc::hir::*;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
-use rustc::{declare_tool_lint, impl_lint_pass};
-use syntax::ast::Attribute;
-use syntax::source_map::Span;
+use rustc::hir::map::Map;
+use rustc_ast::ast::Attribute;
+use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::source_map::Span;
+use rustc_span::BytePos;
 
-use crate::utils::{match_type, paths, span_help_and_lint, LimitStack};
+use crate::utils::{match_type, paths, snippet_opt, span_lint_and_help, LimitStack};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for methods with high cognitive complexity.
@@ -29,6 +31,7 @@ pub struct CognitiveComplexity {
 }
 
 impl CognitiveComplexity {
+    #[must_use]
     pub fn new(limit: u64) -> Self {
         Self {
             limit: LimitStack::new(limit),
@@ -39,8 +42,16 @@ pub fn new(limit: u64) -> Self {
 impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
 
 impl CognitiveComplexity {
-    fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, body: &'tcx Body, span: Span) {
-        if span.from_expansion() {
+    #[allow(clippy::cast_possible_truncation)]
+    fn check<'a, 'tcx>(
+        &mut self,
+        cx: &'a LateContext<'a, 'tcx>,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        body_span: Span,
+    ) {
+        if body_span.from_expansion() {
             return;
         }
 
@@ -62,11 +73,33 @@ fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, body: &'tcx Body, s
         if rust_cc >= ret_adjust {
             rust_cc -= ret_adjust;
         }
+
         if rust_cc > self.limit.limit() {
-            span_help_and_lint(
+            let fn_span = match kind {
+                FnKind::ItemFn(ident, _, _, _, _) | FnKind::Method(ident, _, _, _) => ident.span,
+                FnKind::Closure(_) => {
+                    let header_span = body_span.with_hi(decl.output.span().lo());
+                    let pos = snippet_opt(cx, header_span).and_then(|snip| {
+                        let low_offset = snip.find('|')?;
+                        let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?;
+                        let low = header_span.lo() + BytePos(low_offset as u32);
+                        let high = low + BytePos(high_offset as u32 + 1);
+
+                        Some((low, high))
+                    });
+
+                    if let Some((low, high)) = pos {
+                        Span::new(low, high, header_span.ctxt())
+                    } else {
+                        return;
+                    }
+                },
+            };
+
+            span_lint_and_help(
                 cx,
                 COGNITIVE_COMPLEXITY,
-                span,
+                fn_span,
                 &format!(
                     "the function has a cognitive complexity of ({}/{})",
                     rust_cc,
@@ -82,15 +115,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CognitiveComplexity {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
-        _: intravisit::FnKind<'tcx>,
-        _: &'tcx FnDecl,
-        body: &'tcx Body,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
         span: Span,
         hir_id: HirId,
     ) {
         let def_id = cx.tcx.hir().local_def_id(hir_id);
         if !cx.tcx.has_attr(def_id, sym!(test)) {
-            self.check(cx, body, span);
+            self.check(cx, kind, decl, body, span);
         }
     }
 
@@ -108,9 +141,11 @@ struct CCHelper {
 }
 
 impl<'tcx> Visitor<'tcx> for CCHelper {
-    fn visit_expr(&mut self, e: &'tcx Expr) {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         walk_expr(self, e);
-        match e.node {
+        match e.kind {
             ExprKind::Match(_, ref arms, _) => {
                 if arms.len() > 1 {
                     self.cc += 1;
@@ -121,7 +156,7 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
             _ => {},
         }
     }
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
         NestedVisitorMap::None
     }
 }