about summary refs log tree commit diff
diff options
context:
space:
mode:
authorflip1995 <hello@philkrones.com>2018-12-06 13:50:04 +0100
committerflip1995 <hello@philkrones.com>2019-04-03 18:22:18 +0200
commit5c0656789dfde752ea7af001e3d04a2a916685cf (patch)
treee04e63c9288e0d35f90b25e1438da9bdf0f771a2
parentc796b1f46aba25880942a461c3d1079250b9c8ac (diff)
downloadrust-5c0656789dfde752ea7af001e3d04a2a916685cf.tar.gz
rust-5c0656789dfde752ea7af001e3d04a2a916685cf.zip
Add internal lints default_hash_types and usage_of_ty_tykind
-rw-r--r--src/librustc/lint/internal.rs165
-rw-r--r--src/librustc/lint/mod.rs1
2 files changed, 166 insertions, 0 deletions
diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs
new file mode 100644
index 00000000000..d4cf18123c3
--- /dev/null
+++ b/src/librustc/lint/internal.rs
@@ -0,0 +1,165 @@
+// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
+//! Clippy.
+
+use errors::Applicability;
+use hir::{Expr, ExprKind, PatKind, Path, QPath, Ty, TyKind};
+use lint::{
+    EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
+};
+use rustc_data_structures::fx::FxHashMap;
+use syntax::ast::Ident;
+
+declare_lint! {
+    pub DEFAULT_HASH_TYPES,
+    Warn,
+    "forbid HashMap and HashSet and suggest the FxHash* variants"
+}
+
+pub struct DefaultHashTypes {
+    map: FxHashMap<String, String>,
+}
+
+impl DefaultHashTypes {
+    pub fn new() -> Self {
+        let mut map = FxHashMap::default();
+        map.insert("HashMap".to_string(), "FxHashMap".to_string());
+        map.insert("HashSet".to_string(), "FxHashSet".to_string());
+        Self { map }
+    }
+}
+
+impl LintPass for DefaultHashTypes {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(DEFAULT_HASH_TYPES)
+    }
+}
+
+impl EarlyLintPass for DefaultHashTypes {
+    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
+        let ident_string = ident.to_string();
+        if let Some(replace) = self.map.get(&ident_string) {
+            let msg = format!(
+                "Prefer {} over {}, it has better performance",
+                replace, ident_string
+            );
+            let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
+            db.span_suggestion_with_applicability(
+                ident.span,
+                "use",
+                replace.to_string(),
+                Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
+            );
+            db.note(&format!(
+                "a `use rustc_data_structures::fx::{}` may be necessary",
+                replace
+            ))
+            .emit();
+        }
+    }
+}
+
+declare_lint! {
+    pub USAGE_OF_TY_TYKIND,
+    Warn,
+    "Usage of `ty::TyKind` outside of the `ty::sty` module"
+}
+
+pub struct TyKindUsage;
+
+impl LintPass for TyKindUsage {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(USAGE_OF_TY_TYKIND)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage {
+    fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &'tcx Expr) {
+        let qpaths = match &expr.node {
+            ExprKind::Match(_, arms, _) => {
+                let mut qpaths = vec![];
+                for arm in arms {
+                    for pat in &arm.pats {
+                        match &pat.node {
+                            PatKind::Path(qpath) | PatKind::TupleStruct(qpath, ..) => {
+                                qpaths.push(qpath)
+                            }
+                            _ => (),
+                        }
+                    }
+                }
+                qpaths
+            }
+            ExprKind::Path(qpath) => vec![qpath],
+            _ => vec![],
+        };
+        for qpath in qpaths {
+            if let QPath::Resolved(_, path) = qpath {
+                let segments_iter = path.segments.iter().rev().skip(1).rev();
+
+                if let Some(last) = segments_iter.clone().last() {
+                    if last.ident.as_str() == "TyKind" {
+                        let path = Path {
+                            span: path.span.with_hi(last.ident.span.hi()),
+                            def: path.def,
+                            segments: segments_iter.cloned().collect(),
+                        };
+
+                        if let Some(def) = last.def {
+                            if def
+                                .def_id()
+                                .match_path(cx.tcx, &["rustc", "ty", "sty", "TyKind"])
+                            {
+                                cx.struct_span_lint(
+                                    USAGE_OF_TY_TYKIND,
+                                    path.span,
+                                    "usage of `ty::TyKind::<kind>`",
+                                )
+                                .span_suggestion_with_applicability(
+                                    path.span,
+                                    "try using ty::<kind> directly",
+                                    "ty".to_string(),
+                                    Applicability::MaybeIncorrect, // ty maybe needs an import
+                                ).emit();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty) {
+        if let TyKind::Path(qpath) = &ty.node {
+            if let QPath::Resolved(_, path) = qpath {
+                if let Some(last) = path.segments.iter().last() {
+                    if last.ident.as_str() == "TyKind" {
+                        if let Some(def) = last.def {
+                            if def
+                                .def_id()
+                                .match_path(cx.tcx, &["rustc", "ty", "sty", "TyKind"])
+                            {
+                                cx.struct_span_lint(
+                                    USAGE_OF_TY_TYKIND,
+                                    path.span,
+                                    "usage of `ty::TyKind`",
+                                )
+                                .help("try using `ty::Ty` instead")
+                                .emit();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index a5506bb8f59..b54d26054da 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -574,6 +574,7 @@ impl_stable_hash_for!(enum self::LintSource {
 pub type LevelSource = (Level, LintSource);
 
 pub mod builtin;
+pub mod internal;
 mod context;
 mod levels;