rust/src/librustc/lint/internal.rs

146 lines
4.6 KiB
Rust
Raw Normal View History

//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
//! Clippy.
2019-03-19 16:46:45 -05:00
use crate::hir::{def::Def, HirId, Path, QPath, Ty, TyKind};
2019-02-24 10:54:53 -06:00
use crate::lint::{
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
};
2019-02-24 10:54:53 -06:00
use errors::Applicability;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::Ident;
declare_lint! {
pub DEFAULT_HASH_TYPES,
2019-03-16 08:59:34 -05:00
Allow,
"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)
}
2019-02-24 10:54:53 -06:00
fn name(&self) -> &'static str {
"DefaultHashTypes"
}
}
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);
2019-02-24 10:54:53 -06:00
db.span_suggestion(
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,
2019-03-16 08:59:34 -05:00
Allow,
"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)
}
2019-02-24 10:54:53 -06:00
fn name(&self) -> &'static str {
"TyKindUsage"
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage {
2019-02-28 10:34:01 -06:00
fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path, _: HirId) {
let segments_iter = path.segments.iter().rev().skip(1).rev();
2019-02-28 10:34:01 -06:00
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(),
};
2019-03-19 16:46:45 -05:00
match last.def {
Some(Def::Err) => (),
Some(def)
if def
.def_id()
.match_path(cx.tcx, &["rustc", "ty", "sty", "TyKind"]) =>
2019-02-28 10:34:01 -06:00
{
cx.struct_span_lint(
USAGE_OF_TY_TYKIND,
path.span,
"usage of `ty::TyKind::<kind>`",
)
.span_suggestion(
path.span,
"try using ty::<kind> directly",
"ty".to_string(),
Applicability::MaybeIncorrect, // ty maybe needs an import
)
.emit();
}
2019-03-19 16:46:45 -05:00
_ => (),
}
}
}
}
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();
}
}
}
}
}
}
}
}