11use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_sugg} ;
22use rustc_ast:: node_id:: { NodeId , NodeMap } ;
3- use rustc_ast:: { ptr:: P , Crate , Item , ItemKind , MacroDef , ModKind , UseTreeKind } ;
3+ use rustc_ast:: visit:: { walk_expr, Visitor } ;
4+ use rustc_ast:: { ptr:: P , Crate , Expr , ExprKind , Item , ItemKind , MacroDef , ModKind , Ty , TyKind , UseTreeKind } ;
45use rustc_errors:: Applicability ;
56use rustc_lint:: { EarlyContext , EarlyLintPass , LintContext } ;
67use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -55,7 +56,7 @@ impl EarlyLintPass for SingleComponentPathImports {
5556 return ;
5657 }
5758
58- self . check_mod ( cx , & krate. items ) ;
59+ self . check_mod ( & krate. items ) ;
5960 }
6061
6162 fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & Item ) {
@@ -84,8 +85,43 @@ impl EarlyLintPass for SingleComponentPathImports {
8485 }
8586}
8687
88+ #[ derive( Default ) ]
89+ struct ImportUsageVisitor {
90+ // keep track of imports reused with `self` keyword, such as `self::std` in the example below.
91+ // Removing the `use std;` would make this a compile error (#10549)
92+ // ```
93+ // use std;
94+ //
95+ // fn main() {
96+ // let _ = self::std::io::stdout();
97+ // }
98+ // ```
99+ imports_referenced_with_self : Vec < Symbol > ,
100+ }
101+
102+ impl < ' tcx > Visitor < ' tcx > for ImportUsageVisitor {
103+ fn visit_expr ( & mut self , expr : & Expr ) {
104+ if let ExprKind :: Path ( _, path) = & expr. kind
105+ && path. segments . len ( ) > 1
106+ && path. segments [ 0 ] . ident . name == kw:: SelfLower
107+ {
108+ self . imports_referenced_with_self . push ( path. segments [ 1 ] . ident . name ) ;
109+ }
110+ walk_expr ( self , expr) ;
111+ }
112+
113+ fn visit_ty ( & mut self , ty : & Ty ) {
114+ if let TyKind :: Path ( _, path) = & ty. kind
115+ && path. segments . len ( ) > 1
116+ && path. segments [ 0 ] . ident . name == kw:: SelfLower
117+ {
118+ self . imports_referenced_with_self . push ( path. segments [ 1 ] . ident . name ) ;
119+ }
120+ }
121+ }
122+
87123impl SingleComponentPathImports {
88- fn check_mod ( & mut self , cx : & EarlyContext < ' _ > , items : & [ P < Item > ] ) {
124+ fn check_mod ( & mut self , items : & [ P < Item > ] ) {
89125 // keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example
90126 // below. Removing the `use crypto_hash;` would make this a compile error
91127 // ```
@@ -108,26 +144,23 @@ impl SingleComponentPathImports {
108144 // ```
109145 let mut macros = Vec :: new ( ) ;
110146
147+ let mut import_usage_visitor = ImportUsageVisitor :: default ( ) ;
111148 for item in items {
112- self . track_uses (
113- cx,
114- item,
115- & mut imports_reused_with_self,
116- & mut single_use_usages,
117- & mut macros,
118- ) ;
149+ self . track_uses ( item, & mut imports_reused_with_self, & mut single_use_usages, & mut macros) ;
150+ import_usage_visitor. visit_item ( item) ;
119151 }
120152
121153 for usage in single_use_usages {
122- if !imports_reused_with_self. contains ( & usage. name ) {
154+ if !imports_reused_with_self. contains ( & usage. name )
155+ && !import_usage_visitor. imports_referenced_with_self . contains ( & usage. name )
156+ {
123157 self . found . entry ( usage. item_id ) . or_default ( ) . push ( usage) ;
124158 }
125159 }
126160 }
127161
128162 fn track_uses (
129163 & mut self ,
130- cx : & EarlyContext < ' _ > ,
131164 item : & Item ,
132165 imports_reused_with_self : & mut Vec < Symbol > ,
133166 single_use_usages : & mut Vec < SingleUse > ,
@@ -139,7 +172,7 @@ impl SingleComponentPathImports {
139172
140173 match & item. kind {
141174 ItemKind :: Mod ( _, ModKind :: Loaded ( ref items, ..) ) => {
142- self . check_mod ( cx , items) ;
175+ self . check_mod ( items) ;
143176 } ,
144177 ItemKind :: MacroDef ( MacroDef { macro_rules : true , .. } ) => {
145178 macros. push ( item. ident . name ) ;
0 commit comments