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 or the MIT license +// , 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, +} + +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::`", + ) + .span_suggestion_with_applicability( + path.span, + "try using ty:: 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;