Skip to content

Commit 142f0f5

Browse files
committed
Auto merge of #6448 - mikerite:interning_defined_symbol, r=Manishearth
New internal lint: Interning defined symbol New internal lint: interning_defined_symbol changelog: none
2 parents 6c83e56 + f732cc5 commit 142f0f5

11 files changed

+194
-10
lines changed

clippy_lints/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
511511
#[cfg(feature = "internal-lints")]
512512
&utils::internal_lints::DEFAULT_LINT,
513513
#[cfg(feature = "internal-lints")]
514+
&utils::internal_lints::INTERNING_DEFINED_SYMBOL,
515+
#[cfg(feature = "internal-lints")]
514516
&utils::internal_lints::INVALID_PATHS,
515517
#[cfg(feature = "internal-lints")]
516518
&utils::internal_lints::LINT_WITHOUT_LINT_PASS,
@@ -958,6 +960,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
958960
store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
959961
store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
960962
store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
963+
store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
961964
store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
962965
store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
963966
store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
@@ -1349,6 +1352,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13491352
LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
13501353
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
13511354
LintId::of(&utils::internal_lints::DEFAULT_LINT),
1355+
LintId::of(&utils::internal_lints::INTERNING_DEFINED_SYMBOL),
13521356
LintId::of(&utils::internal_lints::INVALID_PATHS),
13531357
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
13541358
LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),

clippy_lints/src/manual_ok_or.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_lint::LintContext;
88
use rustc_lint::{LateContext, LateLintPass};
99
use rustc_middle::lint::in_external_macro;
1010
use rustc_session::{declare_lint_pass, declare_tool_lint};
11+
use rustc_span::symbol::sym;
1112

1213
declare_clippy_lint! {
1314
/// **What it does:**
@@ -51,7 +52,7 @@ impl LateLintPass<'_> for ManualOkOr {
5152
if args.len() == 3;
5253
let method_receiver = &args[0];
5354
let ty = cx.typeck_results().expr_ty(method_receiver);
54-
if is_type_diagnostic_item(cx, ty, sym!(option_type));
55+
if is_type_diagnostic_item(cx, ty, sym::option_type);
5556
let or_expr = &args[1];
5657
if is_ok_wrapping(cx, &args[2]);
5758
if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;

clippy_lints/src/methods/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
15681568
lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
15691569

15701570
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
1571-
if args.len() == 1 && method_call.ident.name == sym!(clone) {
1571+
if args.len() == 1 && method_call.ident.name == sym::clone {
15721572
lint_clone_on_copy(cx, expr, &args[0], self_ty);
15731573
lint_clone_on_ref_ptr(cx, expr, &args[0]);
15741574
}
@@ -1592,7 +1592,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
15921592
}
15931593
}
15941594
},
1595-
ty::Ref(..) if method_call.ident.name == sym!(into_iter) => {
1595+
ty::Ref(..) if method_call.ident.name == sym::into_iter => {
15961596
lint_into_iter(cx, expr, self_ty, *method_span);
15971597
},
15981598
_ => (),
@@ -2647,9 +2647,9 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E
26472647
fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
26482648
let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
26492649

2650-
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
2650+
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
26512651
Some((EXPECT_USED, "an Option", "None"))
2652-
} else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
2652+
} else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) {
26532653
Some((EXPECT_USED, "a Result", "Err"))
26542654
} else {
26552655
None
@@ -3142,7 +3142,7 @@ fn lint_search_is_some<'tcx>(
31423142
else if search_method == "find" {
31433143
let is_string_or_str_slice = |e| {
31443144
let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
3145-
if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
3145+
if is_type_diagnostic_item(cx, self_ty, sym::string_type) {
31463146
true
31473147
} else {
31483148
*self_ty.kind() == ty::Str

clippy_lints/src/ref_option_ref.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::utils::{last_path_segment, snippet, span_lint_and_sugg};
22
use rustc_hir::{GenericArg, Mutability, Ty, TyKind};
33
use rustc_lint::{LateContext, LateLintPass};
44
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
use rustc_span::symbol::sym;
56

67
use if_chain::if_chain;
78
use rustc_errors::Applicability;
@@ -41,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
4142
if let Some(res) = last.res;
4243
if let Some(def_id) = res.opt_def_id();
4344

44-
if cx.tcx.is_diagnostic_item(sym!(option_type), def_id);
45+
if cx.tcx.is_diagnostic_item(sym::option_type, def_id);
4546
if let Some(ref params) = last_path_segment(qpath).args ;
4647
if !params.parenthesized;
4748
if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {

clippy_lints/src/strings.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl LateLintPass<'_> for StringToString {
372372
if let ExprKind::MethodCall(path, _, args, _) = &expr.kind;
373373
if path.ident.name == sym!(to_string);
374374
let ty = cx.typeck_results().expr_ty(&args[0]);
375-
if is_type_diagnostic_item(cx, ty, sym!(string_type));
375+
if is_type_diagnostic_item(cx, ty, sym::string_type);
376376
then {
377377
span_lint_and_help(
378378
cx,

clippy_lints/src/unnecessary_wraps.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::ty::subst::GenericArgKind;
1111
use rustc_session::{declare_lint_pass, declare_tool_lint};
12+
use rustc_span::symbol::sym;
1213
use rustc_span::Span;
1314

1415
declare_clippy_lint! {
@@ -82,9 +83,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
8283
}
8384
}
8485

85-
let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
86+
let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::option_type) {
8687
("Option", &paths::OPTION_SOME)
87-
} else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
88+
} else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
8889
("Result", &paths::RESULT_OK)
8990
} else {
9091
return;

clippy_lints/src/utils/internal_lints.rs

+78
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
1515
use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind};
1616
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
1717
use rustc_middle::hir::map::Map;
18+
use rustc_middle::mir::interpret::ConstValue;
1819
use rustc_middle::ty;
1920
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
2021
use rustc_span::source_map::{Span, Spanned};
@@ -247,6 +248,30 @@ declare_clippy_lint! {
247248
"invalid path"
248249
}
249250

251+
declare_clippy_lint! {
252+
/// **What it does:**
253+
/// Checks for interning symbols that have already been pre-interned and defined as constants.
254+
///
255+
/// **Why is this bad?**
256+
/// It's faster and easier to use the symbol constant.
257+
///
258+
/// **Known problems:** None.
259+
///
260+
/// **Example:**
261+
/// Bad:
262+
/// ```rust,ignore
263+
/// let _ = sym!(f32);
264+
/// ```
265+
///
266+
/// Good:
267+
/// ```rust,ignore
268+
/// let _ = sym::f32;
269+
/// ```
270+
pub INTERNING_DEFINED_SYMBOL,
271+
internal,
272+
"interning a symbol that is pre-interned and defined as a constant"
273+
}
274+
250275
declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
251276

252277
impl EarlyLintPass for ClippyLintsInternal {
@@ -840,3 +865,56 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
840865
}
841866
}
842867
}
868+
869+
#[derive(Default)]
870+
pub struct InterningDefinedSymbol {
871+
// Maps the symbol value to the constant name.
872+
symbol_map: FxHashMap<u32, String>,
873+
}
874+
875+
impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL]);
876+
877+
impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
878+
fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
879+
if !self.symbol_map.is_empty() {
880+
return;
881+
}
882+
883+
if let Some(Res::Def(_, def_id)) = path_to_res(cx, &paths::SYM_MODULE) {
884+
for item in cx.tcx.item_children(def_id).iter() {
885+
if_chain! {
886+
if let Res::Def(DefKind::Const, item_def_id) = item.res;
887+
let ty = cx.tcx.type_of(item_def_id);
888+
if match_type(cx, ty, &paths::SYMBOL);
889+
if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
890+
if let Ok(value) = value.to_u32();
891+
then {
892+
self.symbol_map.insert(value, item.ident.to_string());
893+
}
894+
}
895+
}
896+
}
897+
}
898+
899+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
900+
if_chain! {
901+
if let ExprKind::Call(func, [arg]) = &expr.kind;
902+
if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
903+
if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
904+
if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
905+
let value = Symbol::intern(&arg).as_u32();
906+
if let Some(symbol_const) = self.symbol_map.get(&value);
907+
then {
908+
span_lint_and_sugg(
909+
cx,
910+
INTERNING_DEFINED_SYMBOL,
911+
is_expn_of(expr.span, "sym").unwrap_or(expr.span),
912+
"interning a defined symbol",
913+
"try",
914+
format!("rustc_span::symbol::sym::{}", symbol_const),
915+
Applicability::MachineApplicable,
916+
);
917+
}
918+
}
919+
}
920+
}

clippy_lints/src/utils/paths.rs

+6
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
146146
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
147147
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
148148
#[cfg(feature = "internal-lints")]
149+
pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
150+
#[cfg(feature = "internal-lints")]
151+
pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
152+
#[cfg(feature = "internal-lints")]
153+
pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
154+
#[cfg(feature = "internal-lints")]
149155
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
150156
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
151157
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// run-rustfix
2+
#![deny(clippy::internal)]
3+
#![feature(rustc_private)]
4+
5+
extern crate rustc_span;
6+
7+
use rustc_span::symbol::Symbol;
8+
9+
macro_rules! sym {
10+
($tt:tt) => {
11+
rustc_span::symbol::Symbol::intern(stringify!($tt))
12+
};
13+
}
14+
15+
fn main() {
16+
// Direct use of Symbol::intern
17+
let _ = rustc_span::symbol::sym::f32;
18+
19+
// Using a sym macro
20+
let _ = rustc_span::symbol::sym::f32;
21+
22+
// Correct suggestion when symbol isn't stringified constant name
23+
let _ = rustc_span::symbol::sym::proc_dash_macro;
24+
25+
// Interning a symbol that is not defined
26+
let _ = Symbol::intern("xyz123");
27+
let _ = sym!(xyz123);
28+
29+
// Using a different `intern` function
30+
let _ = intern("f32");
31+
}
32+
33+
fn intern(_: &str) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// run-rustfix
2+
#![deny(clippy::internal)]
3+
#![feature(rustc_private)]
4+
5+
extern crate rustc_span;
6+
7+
use rustc_span::symbol::Symbol;
8+
9+
macro_rules! sym {
10+
($tt:tt) => {
11+
rustc_span::symbol::Symbol::intern(stringify!($tt))
12+
};
13+
}
14+
15+
fn main() {
16+
// Direct use of Symbol::intern
17+
let _ = Symbol::intern("f32");
18+
19+
// Using a sym macro
20+
let _ = sym!(f32);
21+
22+
// Correct suggestion when symbol isn't stringified constant name
23+
let _ = Symbol::intern("proc-macro");
24+
25+
// Interning a symbol that is not defined
26+
let _ = Symbol::intern("xyz123");
27+
let _ = sym!(xyz123);
28+
29+
// Using a different `intern` function
30+
let _ = intern("f32");
31+
}
32+
33+
fn intern(_: &str) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: interning a defined symbol
2+
--> $DIR/interning_defined_symbol.rs:17:13
3+
|
4+
LL | let _ = Symbol::intern("f32");
5+
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::sym::f32`
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/interning_defined_symbol.rs:2:9
9+
|
10+
LL | #![deny(clippy::internal)]
11+
| ^^^^^^^^^^^^^^^^
12+
= note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]`
13+
14+
error: interning a defined symbol
15+
--> $DIR/interning_defined_symbol.rs:20:13
16+
|
17+
LL | let _ = sym!(f32);
18+
| ^^^^^^^^^ help: try: `rustc_span::symbol::sym::f32`
19+
20+
error: interning a defined symbol
21+
--> $DIR/interning_defined_symbol.rs:23:13
22+
|
23+
LL | let _ = Symbol::intern("proc-macro");
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::sym::proc_dash_macro`
25+
26+
error: aborting due to 3 previous errors
27+

0 commit comments

Comments
 (0)