1
1
use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_sugg} ;
2
2
use 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 } ;
4
5
use rustc_errors:: Applicability ;
5
6
use rustc_lint:: { EarlyContext , EarlyLintPass , LintContext } ;
6
7
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -55,7 +56,7 @@ impl EarlyLintPass for SingleComponentPathImports {
55
56
return ;
56
57
}
57
58
58
- self . check_mod ( cx , & krate. items ) ;
59
+ self . check_mod ( & krate. items ) ;
59
60
}
60
61
61
62
fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & Item ) {
@@ -84,8 +85,43 @@ impl EarlyLintPass for SingleComponentPathImports {
84
85
}
85
86
}
86
87
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
+
87
123
impl SingleComponentPathImports {
88
- fn check_mod ( & mut self , cx : & EarlyContext < ' _ > , items : & [ P < Item > ] ) {
124
+ fn check_mod ( & mut self , items : & [ P < Item > ] ) {
89
125
// keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example
90
126
// below. Removing the `use crypto_hash;` would make this a compile error
91
127
// ```
@@ -108,26 +144,23 @@ impl SingleComponentPathImports {
108
144
// ```
109
145
let mut macros = Vec :: new ( ) ;
110
146
147
+ let mut import_usage_visitor = ImportUsageVisitor :: default ( ) ;
111
148
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) ;
119
151
}
120
152
121
153
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
+ {
123
157
self . found . entry ( usage. item_id ) . or_default ( ) . push ( usage) ;
124
158
}
125
159
}
126
160
}
127
161
128
162
fn track_uses (
129
163
& mut self ,
130
- cx : & EarlyContext < ' _ > ,
131
164
item : & Item ,
132
165
imports_reused_with_self : & mut Vec < Symbol > ,
133
166
single_use_usages : & mut Vec < SingleUse > ,
@@ -139,7 +172,7 @@ impl SingleComponentPathImports {
139
172
140
173
match & item. kind {
141
174
ItemKind :: Mod ( _, ModKind :: Loaded ( ref items, ..) ) => {
142
- self . check_mod ( cx , items) ;
175
+ self . check_mod ( items) ;
143
176
} ,
144
177
ItemKind :: MacroDef ( MacroDef { macro_rules : true , .. } ) => {
145
178
macros. push ( item. ident . name ) ;
0 commit comments