Skip to content

Commit 38b871f

Browse files
committed
Make it only lint crate/<crate>
1 parent c709790 commit 38b871f

File tree

14 files changed

+127
-150
lines changed

14 files changed

+127
-150
lines changed
Lines changed: 39 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use clippy_utils::diagnostics::span_lint;
2-
use clippy_utils::is_from_proc_macro;
3-
use rustc_hir::intravisit::{walk_qpath, Visitor};
4-
use rustc_hir::{def_id::LOCAL_CRATE, HirId, QPath};
2+
use clippy_utils::source::snippet_opt;
3+
use rustc_data_structures::fx::FxHashSet;
4+
use rustc_hir::def::{DefKind, Res};
5+
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
6+
use rustc_hir::{HirId, ItemKind, Node, Path};
57
use rustc_lint::{LateContext, LateLintPass};
6-
use rustc_middle::hir::nested_filter::OnlyBodies;
78
use rustc_session::{declare_tool_lint, impl_lint_pass};
8-
use rustc_span::Span;
9-
use std::iter::once;
9+
use rustc_span::symbol::kw;
1010

1111
declare_clippy_lint! {
1212
/// ### What it does
@@ -37,83 +37,53 @@ declare_clippy_lint! {
3737
/// ```
3838
#[clippy::version = "1.72.0"]
3939
pub ABSOLUTE_SYMBOL_PATHS,
40-
style,
40+
restriction,
4141
"checks for usage of a symbol without a `use` statement"
4242
}
4343
impl_lint_pass!(AbsoluteSymbolPaths => [ABSOLUTE_SYMBOL_PATHS]);
4444

4545
pub struct AbsoluteSymbolPaths {
4646
pub absolute_symbol_paths_max_segments: u64,
47-
pub absolute_symbol_paths_allow_std: bool,
47+
pub absolute_symbol_paths_allowed_crates: FxHashSet<String>,
4848
}
4949

5050
impl LateLintPass<'_> for AbsoluteSymbolPaths {
51-
fn check_crate(&mut self, cx: &LateContext<'_>) {
52-
let Self {
53-
absolute_symbol_paths_max_segments,
54-
absolute_symbol_paths_allow_std,
55-
} = *self;
56-
57-
cx.tcx.hir().visit_all_item_likes_in_crate(&mut V {
58-
cx,
59-
absolute_symbol_paths_max_segments,
60-
absolute_symbol_paths_allow_std,
61-
});
62-
}
63-
}
64-
65-
struct V<'a, 'tcx> {
66-
cx: &'a LateContext<'tcx>,
67-
absolute_symbol_paths_max_segments: u64,
68-
absolute_symbol_paths_allow_std: bool,
69-
}
70-
71-
impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
72-
type NestedFilter = OnlyBodies;
73-
74-
fn nested_visit_map(&mut self) -> Self::Map {
75-
self.cx.tcx.hir()
76-
}
77-
51+
// We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath`
52+
// we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't
53+
// a `Use`
7854
#[expect(clippy::cast_possible_truncation)]
79-
fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span) {
55+
fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
8056
let Self {
81-
cx,
8257
absolute_symbol_paths_max_segments,
83-
absolute_symbol_paths_allow_std,
84-
} = *self;
58+
absolute_symbol_paths_allowed_crates,
59+
} = self;
8560

86-
if !span.from_expansion()
87-
&& let QPath::Resolved(_, path) = qpath
88-
&& let Some(def_id) = path.res.opt_def_id()
89-
&& let def_path = cx.tcx.def_path(def_id)
90-
&& let crate_name = cx.tcx.crate_name(def_path.krate)
91-
&& let segments = once(crate_name)
92-
.chain(def_path.data.iter().filter_map(|segment| segment.data.get_opt_name()))
93-
&& path.segments.len() > absolute_symbol_paths_max_segments as usize
94-
&& let is_std = matches!(crate_name.as_str(), "alloc" | "core" | "std")
95-
&& !(absolute_symbol_paths_allow_std && is_std)
96-
// If this is local, keep the crate name, if it is not, remove it, as we don't need to
97-
// check that (and results in FNs on reexports from one crate to another)
98-
//
99-
// `def_path_str` handles this for us, but unfortunately requires converting every
100-
// `Symbol` to a `&str`, which is a very slow operation.
101-
&& segments.skip(1).eq(
102-
path.segments.iter()
103-
// I love clippy :)
104-
.skip(usize::from(def_path.krate != LOCAL_CRATE))
105-
.map(|segment| segment.ident.name)
106-
)
107-
&& !is_from_proc_macro(cx, qpath)
61+
if !path.span.from_expansion()
62+
&& let Some(node) = cx.tcx.hir().find(hir_id)
63+
&& !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
64+
&& path.segments.len() > *absolute_symbol_paths_max_segments as usize
65+
&& let [first, ..] = path.segments
66+
&& let Some(first_snippet) = snippet_opt(cx, first.ident.span)
67+
&& first_snippet == first.ident.as_str()
10868
{
109-
span_lint(
110-
cx,
111-
ABSOLUTE_SYMBOL_PATHS,
112-
span,
113-
"consider referring to this symbol by adding a `use` statement for consistent formatting",
114-
);
115-
}
69+
let is_abs_external =
70+
matches!(first.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX);
71+
let is_abs_crate = first.ident.name == kw::Crate;
72+
73+
if is_abs_external && absolute_symbol_paths_allowed_crates.contains(first.ident.name.as_str())
74+
|| is_abs_crate && absolute_symbol_paths_allowed_crates.contains("crate")
75+
{
76+
return;
77+
}
11678

117-
walk_qpath(self, qpath, hir_id);
79+
if is_abs_external || is_abs_crate {
80+
span_lint(
81+
cx,
82+
ABSOLUTE_SYMBOL_PATHS,
83+
path.span,
84+
"consider referring to this symbol by adding a `use` statement for consistent formatting",
85+
);
86+
}
87+
}
11888
}
11989
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,11 +1086,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10861086
store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
10871087
store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
10881088
let absolute_symbol_paths_max_segments = conf.absolute_symbol_paths_max_segments;
1089-
let absolute_symbol_paths_allow_std = conf.absolute_symbol_paths_allow_std;
1089+
let absolute_symbol_paths_allowed_crates = conf.absolute_symbol_paths_allowed_crates.clone();
10901090
store.register_late_pass(move |_| {
10911091
Box::new(absolute_symbol_paths::AbsoluteSymbolPaths {
10921092
absolute_symbol_paths_max_segments,
1093-
absolute_symbol_paths_allow_std,
1093+
absolute_symbol_paths_allowed_crates: absolute_symbol_paths_allowed_crates.clone(),
10941094
})
10951095
});
10961096
// add lints here, do not remove this comment, it's used in `new_lint`

clippy_lints/src/utils/conf.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,9 @@ define_Conf! {
557557
(absolute_symbol_paths_max_segments: u64 = 3),
558558
/// Lint: ABSOLUTE_SYMBOL_PATHS.
559559
///
560-
/// Whether to allow paths originating from `core`/`std`/`alloc`
561-
(absolute_symbol_paths_allow_std: bool = false),
560+
/// Which crates to allow absolute symbols, `crate` will allow the local crate
561+
(absolute_symbol_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
562+
rustc_data_structures::fx::FxHashSet::default()),
562563
}
563564

564565
/// Search for the configuration file.

clippy_utils/src/check_proc_macro.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
304304
},
305305
AttrKind::DocComment(_kind @ CommentKind::Line, ..) => {
306306
if matches!(attr.style, AttrStyle::Outer) {
307-
(Pat::Str("///*"), Pat::Str(""))
307+
(Pat::Str("///"), Pat::Str(""))
308308
} else {
309309
(Pat::Str("//!"), Pat::Str(""))
310310
}

clippy_utils/src/usage.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
155155
}
156156

157157
pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
158-
let Some(block) = utils::get_enclosing_block(cx, local_id) else { return false };
158+
let Some(block) = utils::get_enclosing_block(cx, local_id) else {
159+
return false;
160+
};
159161

160162
// for _ in 1..3 {
161163
// local
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: consider referring to this symbol by adding a `use` statement for consistent formatting
2+
--> $DIR/absolute_symbol_paths.rs:40:5
3+
|
4+
LL | std::f32::MAX;
5+
| ^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::absolute-symbol-paths` implied by `-D warnings`
8+
9+
error: consider referring to this symbol by adding a `use` statement for consistent formatting
10+
--> $DIR/absolute_symbol_paths.rs:41:5
11+
|
12+
LL | core::f32::MAX;
13+
| ^^^^^^^^^^^^^^
14+
15+
error: aborting due to 2 previous errors
16+

tests/ui-toml/absolute_symbol_paths/absolute_symbol_paths.allow_std.stderr

Lines changed: 0 additions & 34 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,52 @@
11
error: consider referring to this symbol by adding a `use` statement for consistent formatting
2-
--> $DIR/absolute_symbol_paths.rs:38:5
2+
--> $DIR/absolute_symbol_paths.rs:40:5
33
|
44
LL | std::f32::MAX;
55
| ^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::absolute-symbol-paths` implied by `-D warnings`
88

99
error: consider referring to this symbol by adding a `use` statement for consistent formatting
10-
--> $DIR/absolute_symbol_paths.rs:39:5
10+
--> $DIR/absolute_symbol_paths.rs:41:5
1111
|
1212
LL | core::f32::MAX;
1313
| ^^^^^^^^^^^^^^
1414

1515
error: consider referring to this symbol by adding a `use` statement for consistent formatting
16-
--> $DIR/absolute_symbol_paths.rs:40:5
16+
--> $DIR/absolute_symbol_paths.rs:42:5
1717
|
18-
LL | a::b::c::C;
19-
| ^^^^^^^^^^
18+
LL | crate::a::b::c::C;
19+
| ^^^^^^^^^^^^^^^^^
2020

2121
error: consider referring to this symbol by adding a `use` statement for consistent formatting
22-
--> $DIR/absolute_symbol_paths.rs:41:5
22+
--> $DIR/absolute_symbol_paths.rs:43:5
2323
|
24-
LL | a::b::c::d::e::f::F;
25-
| ^^^^^^^^^^^^^^^^^^^
24+
LL | crate::a::b::c::d::e::f::F;
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
2626

2727
error: consider referring to this symbol by adding a `use` statement for consistent formatting
28-
--> $DIR/absolute_symbol_paths.rs:43:5
28+
--> $DIR/absolute_symbol_paths.rs:44:5
2929
|
30-
LL | a::b::B;
31-
| ^^^^^^^
30+
LL | crate::a::A;
31+
| ^^^^^^^^^^^
3232

3333
error: consider referring to this symbol by adding a `use` statement for consistent formatting
34-
--> $DIR/absolute_symbol_paths.rs:44:5
34+
--> $DIR/absolute_symbol_paths.rs:45:5
35+
|
36+
LL | crate::a::b::B;
37+
| ^^^^^^^^^^^^^^
38+
39+
error: consider referring to this symbol by adding a `use` statement for consistent formatting
40+
--> $DIR/absolute_symbol_paths.rs:46:5
3541
|
36-
LL | a::b::c::C::ZERO;
37-
| ^^^^^^^^^^
42+
LL | crate::a::b::c::C::ZERO;
43+
| ^^^^^^^^^^^^^^^^^
3844

3945
error: consider referring to this symbol by adding a `use` statement for consistent formatting
40-
--> $DIR/absolute_symbol_paths.rs:45:15
46+
--> $DIR/absolute_symbol_paths.rs:47:5
4147
|
42-
LL | fn b() -> a::b::B {
43-
| ^^^^^^^
48+
LL | helper::b::c::d::e::f();
49+
| ^^^^^^^^^^^^^^^^^^^^^
4450

45-
error: aborting due to 7 previous errors
51+
error: aborting due to 8 previous errors
4652

tests/ui-toml/absolute_symbol_paths/absolute_symbol_paths.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//@aux-build:../../ui/auxiliary/proc_macros.rs:proc-macro
2-
//@revisions: allow_std disallow_std
3-
//@[allow_std] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_symbol_paths/allow_std
4-
//@[disallow_std] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_symbol_paths/disallow_std
2+
//@aux-build:helper.rs
3+
//@revisions: allow_crates disallow_crates
4+
//@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_symbol_paths/allow_crates
5+
//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_symbol_paths/disallow_crates
56
#![allow(clippy::no_effect, unused)]
67
#![warn(clippy::absolute_symbol_paths)]
78
#![feature(decl_macro)]
89

10+
extern crate helper;
911
#[macro_use]
1012
extern crate proc_macros;
1113

@@ -37,17 +39,24 @@ fn main() {
3739
f32::max(1.0, 2.0);
3840
std::f32::MAX;
3941
core::f32::MAX;
40-
a::b::c::C;
41-
a::b::c::d::e::f::F;
42-
a::A;
43-
a::b::B;
44-
a::b::c::C::ZERO;
42+
crate::a::b::c::C;
43+
crate::a::b::c::d::e::f::F;
44+
crate::a::A;
45+
crate::a::b::B;
46+
crate::a::b::c::C::ZERO;
47+
helper::b::c::d::e::f();
4548
fn b() -> a::b::B {
4649
todo!()
4750
}
48-
// Does not lint
51+
std::println!("a");
52+
let x = 1;
53+
std::ptr::addr_of!(x);
54+
// Do not lint
55+
helper::a();
56+
use crate::a::b::c::C;
4957
use a::b;
50-
use a::b::c::C;
58+
use std::f32::MAX;
59+
a::b::c::d::e::f::F;
5160
b::c::C;
5261
fn a() -> a::A {
5362
todo!()
@@ -61,25 +70,21 @@ fn main() {
6170
todo!()
6271
}
6372
external! {
64-
a::b::c::C::ZERO;
73+
crate::a::b::c::C::ZERO;
6574
}
75+
// For some reason, `path.span.from_expansion()` takes care of this for us
6676
with_span! {
6777
span
68-
a::b::c::C::ZERO;
78+
crate::a::b::c::C::ZERO;
6979
}
7080
macro_rules! local_crate {
7181
() => {
72-
a::b::c::C::ZERO;
82+
crate::a::b::c::C::ZERO;
7383
};
7484
}
7585
macro local_crate_2_0() {
76-
a::b::c::C::ZERO;
86+
crate::a::b::c::C::ZERO;
7787
}
7888
local_crate!();
7989
local_crate_2_0!();
80-
// Macros are unfortunately tricky, as these are defined in `std::macros` but we have to access
81-
// them from `std::println!`, both due to privacy and because they're not macros 2.0
82-
std::println!("a");
83-
let x = 1;
84-
std::ptr::addr_of!(x);
8590
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
absolute-symbol-paths-max-segments = 2
2+
absolute-symbol-paths-allowed-crates = ["crate", "helper"]

0 commit comments

Comments
 (0)