Merge pull request #3187 from flip1995/internal_fn

New internal lint: compiler_lint_functions
This commit is contained in:
Philipp Hansch 2018-09-19 19:43:48 +01:00 committed by GitHub
commit b6707ffc42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 21 deletions

View file

@ -1,6 +1,7 @@
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::span_lint;
/// **What it does:** Checks for unnecessary double parentheses. /// **What it does:** Checks for unnecessary double parentheses.
/// ///
@ -35,20 +36,20 @@ impl EarlyLintPass for DoubleParens {
match expr.node { match expr.node {
ExprKind::Paren(ref in_paren) => match in_paren.node { ExprKind::Paren(ref in_paren) => match in_paren.node {
ExprKind::Paren(_) | ExprKind::Tup(_) => { ExprKind::Paren(_) | ExprKind::Tup(_) => {
cx.span_lint(DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses"); span_lint(cx, DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses");
}, },
_ => {}, _ => {},
}, },
ExprKind::Call(_, ref params) => if params.len() == 1 { ExprKind::Call(_, ref params) => if params.len() == 1 {
let param = &params[0]; let param = &params[0];
if let ExprKind::Paren(_) = param.node { if let ExprKind::Paren(_) = param.node {
cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
} }
}, },
ExprKind::MethodCall(_, ref params) => if params.len() == 2 { ExprKind::MethodCall(_, ref params) => if params.len() == 2 {
let param = &params[1]; let param = &params[1];
if let ExprKind::Paren(_) = param.node { if let ExprKind::Paren(_) = param.node {
cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
} }
}, },
_ => {}, _ => {},

View file

@ -293,8 +293,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
reg.register_late_lint_pass(box serde_api::Serde); reg.register_late_lint_pass(box serde_api::Serde);
reg.register_early_lint_pass(box utils::internal_lints::Clippy); reg.register_early_lint_pass(box utils::internal_lints::Clippy);
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default()); reg.register_late_lint_pass(box utils::internal_lints::CompilerLintFunctions::new());
reg.register_early_lint_pass(box utils::internal_lints::DefaultHashTypes::default()); reg.register_early_lint_pass(box utils::internal_lints::DefaultHashTypes::default());
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
reg.register_late_lint_pass(box utils::inspector::Pass); reg.register_late_lint_pass(box utils::inspector::Pass);
reg.register_late_lint_pass(box utils::author::Pass); reg.register_late_lint_pass(box utils::author::Pass);
reg.register_late_lint_pass(box types::TypePass); reg.register_late_lint_pass(box types::TypePass);
@ -494,8 +495,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
reg.register_lint_group("clippy::internal", Some("clippy_internal"), vec![ reg.register_lint_group("clippy::internal", Some("clippy_internal"), vec![
utils::internal_lints::CLIPPY_LINTS_INTERNAL, utils::internal_lints::CLIPPY_LINTS_INTERNAL,
utils::internal_lints::LINT_WITHOUT_LINT_PASS, utils::internal_lints::COMPILER_LINT_FUNCTIONS,
utils::internal_lints::DEFAULT_HASH_TYPES, utils::internal_lints::DEFAULT_HASH_TYPES,
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
]); ]);
reg.register_lint_group("clippy::all", Some("clippy"), vec![ reg.register_lint_group("clippy::all", Some("clippy"), vec![

View file

@ -1,14 +1,16 @@
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, EarlyContext, EarlyLintPass}; use crate::utils::{
use crate::rustc::{declare_tool_lint, lint_array}; match_qpath, match_type, paths, span_help_and_lint, span_lint, span_lint_and_sugg, walk_ptrs_ty,
use crate::rustc::hir::*; };
use if_chain::if_chain;
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::utils::{match_qpath, paths, span_lint, span_lint_and_sugg};
use crate::syntax::symbol::LocalInternedString;
use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name}; use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString;
/// **What it does:** Checks for various things we like to keep tidy in clippy. /// **What it does:** Checks for various things we like to keep tidy in clippy.
/// ///
@ -23,7 +25,6 @@ declare_clippy_lint! {
"various things that will negatively affect your clippy experience" "various things that will negatively affect your clippy experience"
} }
/// **What it does:** Ensures every lint is associated to a `LintPass`. /// **What it does:** Ensures every lint is associated to a `LintPass`.
/// ///
/// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without /// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without
@ -53,7 +54,6 @@ declare_clippy_lint! {
"declaring a lint without associating it in a LintPass" "declaring a lint without associating it in a LintPass"
} }
/// **What it does:** Checks for the presence of the default hash types "HashMap" or "HashSet" /// **What it does:** Checks for the presence of the default hash types "HashMap" or "HashSet"
/// and recommends the FxHash* variants. /// and recommends the FxHash* variants.
/// ///
@ -65,6 +65,29 @@ declare_clippy_lint! {
"forbid HashMap and HashSet and suggest the FxHash* variants" "forbid HashMap and HashSet and suggest the FxHash* variants"
} }
/// **What it does:** Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
/// variant of the function.
///
/// **Why is this bad?** The `utils::*` variants also add a link to the Clippy documentation to the
/// warning/error messages.
///
/// **Known problems:** None.
///
/// **Example:**
/// Bad:
/// ```rust
/// cx.span_lint(LINT_NAME, "message");
/// ```
///
/// Good:
/// ```rust
/// utils::span_lint(cx, LINT_NAME, "message");
/// ```
declare_clippy_lint! {
pub COMPILER_LINT_FUNCTIONS,
internal,
"usage of the lint functions of the compiler instead of the utils::* variant"
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Clippy; pub struct Clippy;
@ -119,7 +142,6 @@ pub struct LintWithoutLintPass {
registered_lints: FxHashSet<Name>, registered_lints: FxHashSet<Name>,
} }
impl LintPass for LintWithoutLintPass { impl LintPass for LintWithoutLintPass {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(LINT_WITHOUT_LINT_PASS) lint_array!(LINT_WITHOUT_LINT_PASS)
@ -171,7 +193,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
} }
} }
fn is_lint_ref_type(ty: &Ty) -> bool { fn is_lint_ref_type(ty: &Ty) -> bool {
if let TyKind::Rptr( if let TyKind::Rptr(
_, _,
@ -188,7 +209,6 @@ fn is_lint_ref_type(ty: &Ty) -> bool {
false false
} }
fn is_lint_array_type(ty: &Ty) -> bool { fn is_lint_array_type(ty: &Ty) -> bool {
if let TyKind::Path(ref path) = ty.node { if let TyKind::Path(ref path) = ty.node {
match_qpath(path, &paths::LINT_ARRAY) match_qpath(path, &paths::LINT_ARRAY)
@ -224,8 +244,8 @@ pub struct DefaultHashTypes {
impl DefaultHashTypes { impl DefaultHashTypes {
pub fn default() -> Self { pub fn default() -> Self {
let mut map = FxHashMap::default(); let mut map = FxHashMap::default();
map.insert("HashMap".to_owned(), "FxHashMap".to_owned()); map.insert("HashMap".to_string(), "FxHashMap".to_string());
map.insert("HashSet".to_owned(), "FxHashSet".to_owned()); map.insert("HashSet".to_string(), "FxHashSet".to_string());
Self { map } Self { map }
} }
} }
@ -240,8 +260,62 @@ impl EarlyLintPass for DefaultHashTypes {
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
let ident_string = ident.to_string(); let ident_string = ident.to_string();
if let Some(replace) = self.map.get(&ident_string) { if let Some(replace) = self.map.get(&ident_string) {
let msg = format!("Prefer {} over {}, it has better performance and we don't need any collision prevention in clippy", replace, ident_string); let msg = format!("Prefer {} over {}, it has better performance \
span_lint_and_sugg(cx, DEFAULT_HASH_TYPES, ident.span, &msg, "use", replace.to_owned()); and we don't need any collision prevention in clippy",
replace, ident_string);
span_lint_and_sugg(
cx,
DEFAULT_HASH_TYPES,
ident.span,
&msg,
"use",
replace.to_string(),
);
}
}
}
#[derive(Clone, Default)]
pub struct CompilerLintFunctions {
map: FxHashMap<String, String>,
}
impl CompilerLintFunctions {
pub fn new() -> Self {
let mut map = FxHashMap::default();
map.insert("span_lint".to_string(), "utils::span_lint".to_string());
map.insert("struct_span_lint".to_string(), "utils::span_lint".to_string());
map.insert("lint".to_string(), "utils::span_lint".to_string());
map.insert("span_lint_note".to_string(), "utils::span_note_and_lint".to_string());
map.insert("span_lint_help".to_string(), "utils::span_help_and_lint".to_string());
Self { map }
}
}
impl LintPass for CompilerLintFunctions {
fn get_lints(&self) -> LintArray {
lint_array!(COMPILER_LINT_FUNCTIONS)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_chain! {
if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
let fn_name = path.ident.as_str().to_string();
if let Some(sugg) = self.map.get(&fn_name);
let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
if match_type(cx, ty, &paths::EARLY_CONTEXT)
|| match_type(cx, ty, &paths::LATE_CONTEXT);
then {
span_help_and_lint(
cx,
COMPILER_LINT_FUNCTIONS,
path.ident.span,
"usage of a compiler lint function",
&format!("Please use the Clippy variant of this function: `{}`", sugg),
);
}
} }
} }
} }

View file

@ -26,6 +26,7 @@ pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
pub const FMT_ARGUMENTS_NEWV1FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"]; pub const FMT_ARGUMENTS_NEWV1FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
@ -41,6 +42,7 @@ pub const INTO_ITERATOR: [&str; 4] = ["core", "iter", "traits", "IntoIterator"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"]; pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"]; pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
pub const LINT: [&str; 3] = ["rustc", "lint", "Lint"]; pub const LINT: [&str; 3] = ["rustc", "lint", "Lint"];
pub const LINT_ARRAY: [&str; 3] = ["rustc", "lint", "LintArray"]; pub const LINT_ARRAY: [&str; 3] = ["rustc", "lint", "LintArray"];