11use clippy_utils:: diagnostics:: span_lint;
22use clippy_utils:: is_from_proc_macro;
33use rustc_hir:: intravisit:: { walk_qpath, Visitor } ;
4- use rustc_hir:: { HirId , QPath } ;
4+ use rustc_hir:: { def_id :: LOCAL_CRATE , HirId , QPath } ;
55use rustc_lint:: { LateContext , LateLintPass } ;
66use rustc_middle:: hir:: nested_filter:: OnlyBodies ;
7- use rustc_session:: { declare_lint_pass , declare_tool_lint } ;
7+ use rustc_session:: { declare_tool_lint , impl_lint_pass } ;
88use rustc_span:: Span ;
9+ use std:: iter:: once;
910
1011declare_clippy_lint ! {
1112 /// ### What it does
@@ -39,16 +40,32 @@ declare_clippy_lint! {
3940 style,
4041 "checks for usage of a symbol without a `use` statement"
4142}
42- declare_lint_pass ! ( AbsoluteSymbolPaths => [ ABSOLUTE_SYMBOL_PATHS ] ) ;
43+ impl_lint_pass ! ( AbsoluteSymbolPaths => [ ABSOLUTE_SYMBOL_PATHS ] ) ;
44+
45+ pub struct AbsoluteSymbolPaths {
46+ pub absolute_symbol_paths_max_segments : u64 ,
47+ pub absolute_symbol_paths_allow_std : bool ,
48+ }
4349
4450impl LateLintPass < ' _ > for AbsoluteSymbolPaths {
4551 fn check_crate ( & mut self , cx : & LateContext < ' _ > ) {
46- cx. tcx . hir ( ) . visit_all_item_likes_in_crate ( & mut V { cx } ) ;
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+ } ) ;
4762 }
4863}
4964
5065struct V < ' a , ' tcx > {
5166 cx : & ' a LateContext < ' tcx > ,
67+ absolute_symbol_paths_max_segments : u64 ,
68+ absolute_symbol_paths_allow_std : bool ,
5269}
5370
5471impl < ' a , ' tcx > Visitor < ' tcx > for V < ' a , ' tcx > {
@@ -58,29 +75,43 @@ impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
5875 self . cx . tcx . hir ( )
5976 }
6077
78+ #[ expect( clippy:: cast_possible_truncation) ]
6179 fn visit_qpath ( & mut self , qpath : & ' tcx QPath < ' tcx > , hir_id : HirId , span : Span ) {
62- let Self { cx } = * self ;
80+ let Self {
81+ cx,
82+ absolute_symbol_paths_max_segments,
83+ absolute_symbol_paths_allow_std,
84+ } = * self ;
6385
6486 if !span. from_expansion ( )
6587 && let QPath :: Resolved ( _, path) = qpath
6688 && 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)
67108 {
68- let def_path = cx. tcx . def_path_str ( def_id) ;
69- let segments = def_path. split ( "::" ) ;
70-
71- // FIXME: I only allowed 3 segment paths because there's tons of them in clippy :D
72- // To my humble reviewer: thoughts?
73- if path. segments . len ( ) >= 4 // A 2 segment path seems okay, like `std::println!`
74- && segments. eq ( path. segments . iter ( ) . map ( |segment| segment. ident . name . as_str ( ) ) )
75- && !is_from_proc_macro ( cx, qpath)
76- {
77- span_lint (
78- cx,
79- ABSOLUTE_SYMBOL_PATHS ,
80- span,
81- "consider referring to this symbol by adding a `use` statement for consistent formatting" ,
82- ) ;
83- }
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+ ) ;
84115 }
85116
86117 walk_qpath ( self , qpath, hir_id) ;
0 commit comments