]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/utils/internal_lints.rs
rustup https://github.com/rust-lang/rust/pull/68944
[rust.git] / clippy_lints / src / utils / internal_lints.rs
index 825e796382b5a7f294ab33fe0b66ff293acbaeb6..7dbb0d5a9ab820238d15295f193d68c09c04e734 100644 (file)
@@ -1,23 +1,21 @@
 use crate::utils::{
-    is_expn_of, match_def_path, match_type, method_calls, paths, span_help_and_lint, span_lint, span_lint_and_sugg,
+    is_expn_of, match_def_path, match_type, method_calls, paths, 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::{Crate as AstCrate, ItemKind, LitKind, Name, NodeId};
+use rustc_ast::visit::FnKind;
 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::*;
+use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, Ty, TyKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
-use rustc_session::declare_tool_lint;
-use rustc_session::{declare_lint_pass, impl_lint_pass};
-use rustc_span::source_map::Span;
+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 syntax::ast;
-use syntax::ast::{Crate as AstCrate, ItemKind, Name};
-use syntax::visit::FnKind;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for various things we like to keep tidy in clippy.
     "this message should not appear anywhere as we ICE before and don't emit the lint"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for cases of an auto-generated lint without an updated description,
+    /// i.e. `default lint description`.
+    ///
+    /// **Why is this bad?** Indicates that the lint is not finished.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust,ignore
+    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
+    /// ```
+    ///
+    /// Good:
+    /// ```rust,ignore
+    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
+    /// ```
+    pub DEFAULT_LINT,
+    internal,
+    "found 'default lint description' in a lint declaration"
+}
+
 declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 
 impl EarlyLintPass for ClippyLintsInternal {
@@ -163,18 +184,45 @@ pub struct LintWithoutLintPass {
     registered_lints: FxHashSet<Name>,
 }
 
-impl_lint_pass!(LintWithoutLintPass => [LINT_WITHOUT_LINT_PASS]);
+impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
-        if let hir::ItemKind::Static(ref ty, Mutability::Not, _) = item.kind {
+        if let hir::ItemKind::Static(ref ty, Mutability::Not, body_id) = item.kind {
             if is_lint_ref_type(cx, ty) {
+                let expr = &cx.tcx.hir().body(body_id).value;
+                if_chain! {
+                    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");
+                    if let ExprKind::Lit(Spanned {
+                        node: LitKind::Str(ref sym, _),
+                        ..
+                    }) = field.expr.kind;
+                    if sym.as_str() == "default lint description";
+
+                    then {
+                        span_lint(
+                            cx,
+                            DEFAULT_LINT,
+                            item.span,
+                            &format!("the lint `{}` has the default lint description", item.ident.name),
+                        );
+                    }
+                }
                 self.declared_lints.insert(item.ident.name, item.span);
             }
         } else if is_expn_of(item.span, "impl_lint_pass").is_some()
             || is_expn_of(item.span, "declare_lint_pass").is_some()
         {
-            if let hir::ItemKind::Impl(.., None, _, ref impl_item_refs) = item.kind {
+            if let hir::ItemKind::Impl {
+                of_trait: None,
+                items: ref impl_item_refs,
+                ..
+            } = item.kind
+            {
                 let mut collector = LintCollector {
                     output: &mut self.registered_lints,
                     cx,
@@ -251,8 +299,8 @@ fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
             self.output.insert(path.segments[0].ident.name);
         }
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
-        NestedVisitorMap::All(&self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::All(self.cx.tcx.hir())
     }
 }
 
@@ -268,8 +316,8 @@ pub fn new() -> Self {
         map.insert("span_lint", "utils::span_lint");
         map.insert("struct_span_lint", "utils::span_lint");
         map.insert("lint", "utils::span_lint");
-        map.insert("span_lint_note", "utils::span_note_and_lint");
-        map.insert("span_lint_help", "utils::span_help_and_lint");
+        map.insert("span_lint_note", "utils::span_lint_and_note");
+        map.insert("span_lint_help", "utils::span_lint_and_help");
         Self { map }
     }
 }
@@ -286,7 +334,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if match_type(cx, ty, &paths::EARLY_CONTEXT)
                 || match_type(cx, ty, &paths::LATE_CONTEXT);
             then {
-                span_help_and_lint(
+                span_lint_and_help(
                     cx,
                     COMPILER_LINT_FUNCTIONS,
                     path.ident.span,
@@ -330,18 +378,16 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
 declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
 
 impl EarlyLintPass for ProduceIce {
-    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &ast::FnDecl, _: Span, _: ast::NodeId) {
+    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
         if is_trigger_fn(fn_kind) {
-            panic!("Testing the ICE message");
+            panic!("Would you like some help with that?");
         }
     }
 }
 
 fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
     match fn_kind {
-        FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => {
-            ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy"
-        },
+        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
         FnKind::Closure(..) => false,
     }
 }