Skip to content

Commit b6707ff

Browse files
authored
Merge pull request #3187 from flip1995/internal_fn
New internal lint: compiler_lint_functions
2 parents 125907a + 144281c commit b6707ff

File tree

4 files changed

+100
-21
lines changed

4 files changed

+100
-21
lines changed

clippy_lints/src/double_parens.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::syntax::ast::*;
2-
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
2+
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
33
use crate::rustc::{declare_tool_lint, lint_array};
4+
use crate::utils::span_lint;
45

56
/// **What it does:** Checks for unnecessary double parentheses.
67
///
@@ -35,20 +36,20 @@ impl EarlyLintPass for DoubleParens {
3536
match expr.node {
3637
ExprKind::Paren(ref in_paren) => match in_paren.node {
3738
ExprKind::Paren(_) | ExprKind::Tup(_) => {
38-
cx.span_lint(DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses");
39+
span_lint(cx, DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses");
3940
},
4041
_ => {},
4142
},
4243
ExprKind::Call(_, ref params) => if params.len() == 1 {
4344
let param = &params[0];
4445
if let ExprKind::Paren(_) = param.node {
45-
cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
46+
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
4647
}
4748
},
4849
ExprKind::MethodCall(_, ref params) => if params.len() == 2 {
4950
let param = &params[1];
5051
if let ExprKind::Paren(_) = param.node {
51-
cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
52+
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
5253
}
5354
},
5455
_ => {},

clippy_lints/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
293293

294294
reg.register_late_lint_pass(box serde_api::Serde);
295295
reg.register_early_lint_pass(box utils::internal_lints::Clippy);
296-
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
296+
reg.register_late_lint_pass(box utils::internal_lints::CompilerLintFunctions::new());
297297
reg.register_early_lint_pass(box utils::internal_lints::DefaultHashTypes::default());
298+
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
298299
reg.register_late_lint_pass(box utils::inspector::Pass);
299300
reg.register_late_lint_pass(box utils::author::Pass);
300301
reg.register_late_lint_pass(box types::TypePass);
@@ -494,8 +495,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
494495

495496
reg.register_lint_group("clippy::internal", Some("clippy_internal"), vec![
496497
utils::internal_lints::CLIPPY_LINTS_INTERNAL,
497-
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
498+
utils::internal_lints::COMPILER_LINT_FUNCTIONS,
498499
utils::internal_lints::DEFAULT_HASH_TYPES,
500+
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
499501
]);
500502

501503
reg.register_lint_group("clippy::all", Some("clippy"), vec![

clippy_lints/src/utils/internal_lints.rs

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, EarlyContext, EarlyLintPass};
2-
use crate::rustc::{declare_tool_lint, lint_array};
3-
use crate::rustc::hir::*;
1+
use crate::utils::{
2+
match_qpath, match_type, paths, span_help_and_lint, span_lint, span_lint_and_sugg, walk_ptrs_ty,
3+
};
4+
use if_chain::if_chain;
45
use crate::rustc::hir;
56
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
7+
use crate::rustc::hir::*;
8+
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass};
9+
use crate::rustc::{declare_tool_lint, lint_array};
610
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
7-
use crate::utils::{match_qpath, paths, span_lint, span_lint_and_sugg};
8-
use crate::syntax::symbol::LocalInternedString;
911
use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name};
1012
use crate::syntax::source_map::Span;
11-
13+
use crate::syntax::symbol::LocalInternedString;
1214

1315
/// **What it does:** Checks for various things we like to keep tidy in clippy.
1416
///
@@ -23,7 +25,6 @@ declare_clippy_lint! {
2325
"various things that will negatively affect your clippy experience"
2426
}
2527

26-
2728
/// **What it does:** Ensures every lint is associated to a `LintPass`.
2829
///
2930
/// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without
@@ -53,7 +54,6 @@ declare_clippy_lint! {
5354
"declaring a lint without associating it in a LintPass"
5455
}
5556

56-
5757
/// **What it does:** Checks for the presence of the default hash types "HashMap" or "HashSet"
5858
/// and recommends the FxHash* variants.
5959
///
@@ -65,6 +65,29 @@ declare_clippy_lint! {
6565
"forbid HashMap and HashSet and suggest the FxHash* variants"
6666
}
6767

68+
/// **What it does:** Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
69+
/// variant of the function.
70+
///
71+
/// **Why is this bad?** The `utils::*` variants also add a link to the Clippy documentation to the
72+
/// warning/error messages.
73+
///
74+
/// **Known problems:** None.
75+
///
76+
/// **Example:**
77+
/// Bad:
78+
/// ```rust
79+
/// cx.span_lint(LINT_NAME, "message");
80+
/// ```
81+
///
82+
/// Good:
83+
/// ```rust
84+
/// utils::span_lint(cx, LINT_NAME, "message");
85+
/// ```
86+
declare_clippy_lint! {
87+
pub COMPILER_LINT_FUNCTIONS,
88+
internal,
89+
"usage of the lint functions of the compiler instead of the utils::* variant"
90+
}
6891

6992
#[derive(Copy, Clone)]
7093
pub struct Clippy;
@@ -119,7 +142,6 @@ pub struct LintWithoutLintPass {
119142
registered_lints: FxHashSet<Name>,
120143
}
121144

122-
123145
impl LintPass for LintWithoutLintPass {
124146
fn get_lints(&self) -> LintArray {
125147
lint_array!(LINT_WITHOUT_LINT_PASS)
@@ -171,7 +193,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
171193
}
172194
}
173195

174-
175196
fn is_lint_ref_type(ty: &Ty) -> bool {
176197
if let TyKind::Rptr(
177198
_,
@@ -188,7 +209,6 @@ fn is_lint_ref_type(ty: &Ty) -> bool {
188209
false
189210
}
190211

191-
192212
fn is_lint_array_type(ty: &Ty) -> bool {
193213
if let TyKind::Path(ref path) = ty.node {
194214
match_qpath(path, &paths::LINT_ARRAY)
@@ -224,8 +244,8 @@ pub struct DefaultHashTypes {
224244
impl DefaultHashTypes {
225245
pub fn default() -> Self {
226246
let mut map = FxHashMap::default();
227-
map.insert("HashMap".to_owned(), "FxHashMap".to_owned());
228-
map.insert("HashSet".to_owned(), "FxHashSet".to_owned());
247+
map.insert("HashMap".to_string(), "FxHashMap".to_string());
248+
map.insert("HashSet".to_string(), "FxHashSet".to_string());
229249
Self { map }
230250
}
231251
}
@@ -240,8 +260,62 @@ impl EarlyLintPass for DefaultHashTypes {
240260
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
241261
let ident_string = ident.to_string();
242262
if let Some(replace) = self.map.get(&ident_string) {
243-
let msg = format!("Prefer {} over {}, it has better performance and we don't need any collision prevention in clippy", replace, ident_string);
244-
span_lint_and_sugg(cx, DEFAULT_HASH_TYPES, ident.span, &msg, "use", replace.to_owned());
263+
let msg = format!("Prefer {} over {}, it has better performance \
264+
and we don't need any collision prevention in clippy",
265+
replace, ident_string);
266+
span_lint_and_sugg(
267+
cx,
268+
DEFAULT_HASH_TYPES,
269+
ident.span,
270+
&msg,
271+
"use",
272+
replace.to_string(),
273+
);
274+
}
275+
}
276+
}
277+
278+
#[derive(Clone, Default)]
279+
pub struct CompilerLintFunctions {
280+
map: FxHashMap<String, String>,
281+
}
282+
283+
impl CompilerLintFunctions {
284+
pub fn new() -> Self {
285+
let mut map = FxHashMap::default();
286+
map.insert("span_lint".to_string(), "utils::span_lint".to_string());
287+
map.insert("struct_span_lint".to_string(), "utils::span_lint".to_string());
288+
map.insert("lint".to_string(), "utils::span_lint".to_string());
289+
map.insert("span_lint_note".to_string(), "utils::span_note_and_lint".to_string());
290+
map.insert("span_lint_help".to_string(), "utils::span_help_and_lint".to_string());
291+
Self { map }
292+
}
293+
}
294+
295+
impl LintPass for CompilerLintFunctions {
296+
fn get_lints(&self) -> LintArray {
297+
lint_array!(COMPILER_LINT_FUNCTIONS)
298+
}
299+
}
300+
301+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
302+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
303+
if_chain! {
304+
if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
305+
let fn_name = path.ident.as_str().to_string();
306+
if let Some(sugg) = self.map.get(&fn_name);
307+
let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
308+
if match_type(cx, ty, &paths::EARLY_CONTEXT)
309+
|| match_type(cx, ty, &paths::LATE_CONTEXT);
310+
then {
311+
span_help_and_lint(
312+
cx,
313+
COMPILER_LINT_FUNCTIONS,
314+
path.ident.span,
315+
"usage of a compiler lint function",
316+
&format!("Please use the Clippy variant of this function: `{}`", sugg),
317+
);
318+
}
245319
}
246320
}
247321
}

clippy_lints/src/utils/paths.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
2626
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
2727
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
2828
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
29+
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
2930
pub const FMT_ARGUMENTS_NEWV1FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
3031
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
3132
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
@@ -41,6 +42,7 @@ pub const INTO_ITERATOR: [&str; 4] = ["core", "iter", "traits", "IntoIterator"];
4142
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
4243
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
4344
pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"];
45+
pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
4446
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
4547
pub const LINT: [&str; 3] = ["rustc", "lint", "Lint"];
4648
pub const LINT_ARRAY: [&str; 3] = ["rustc", "lint", "LintArray"];

0 commit comments

Comments
 (0)