@@ -41,15 +41,25 @@ impl LintPass for NonExpressiveNames {
41
41
}
42
42
}
43
43
44
+ struct ExistingName {
45
+ interned : InternedString ,
46
+ span : Span ,
47
+ len : usize ,
48
+ whitelist : & ' static [ & ' static str ] ,
49
+ }
50
+
44
51
struct SimilarNamesLocalVisitor < ' a , ' b : ' a > {
45
- names : Vec < ( InternedString , Span , usize ) > ,
52
+ names : Vec < ExistingName > ,
46
53
cx : & ' a EarlyContext < ' b > ,
47
54
lint : & ' a NonExpressiveNames ,
48
55
single_char_names : Vec < char > ,
49
56
}
50
57
51
- const WHITELIST : & ' static [ & ' static str ] = & [
52
- "lhs" , "rhs" ,
58
+ // this list contains lists of names that are allowed to be similar
59
+ // the assumption is that no name is ever contained in multiple lists.
60
+ const WHITELIST : & ' static [ & ' static [ & ' static str ] ] = & [
61
+ & [ "parsed" , "parser" ] ,
62
+ & [ "lhs" , "rhs" ] ,
53
63
] ;
54
64
55
65
struct SimilarNamesNameVisitor < ' a , ' b : ' a , ' c : ' b > ( & ' a mut SimilarNamesLocalVisitor < ' b , ' c > ) ;
@@ -63,21 +73,27 @@ impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c>
63
73
}
64
74
}
65
75
66
- fn whitelisted ( interned_name : & str ) -> bool {
76
+ fn get_whitelist ( interned_name : & str ) -> Option < & ' static [ & ' static str ] > {
67
77
for & allow in WHITELIST {
68
- if interned_name == allow {
69
- return true ;
78
+ if whitelisted ( interned_name, allow) {
79
+ return Some ( allow ) ;
70
80
}
71
- if interned_name. len ( ) <= allow. len ( ) {
72
- continue ;
73
- }
74
- // allow_*
75
- let allow_start = allow. chars ( ) . chain ( Some ( '_' ) ) ;
81
+ }
82
+ None
83
+ }
84
+
85
+ fn whitelisted ( interned_name : & str , list : & [ & str ] ) -> bool {
86
+ if list. iter ( ) . any ( |& name| interned_name == name) {
87
+ return true ;
88
+ }
89
+ for name in list {
90
+ // name_*
91
+ let allow_start = name. chars ( ) . chain ( Some ( '_' ) ) ;
76
92
if interned_name. chars ( ) . zip ( allow_start) . all ( |( l, r) | l == r) {
77
93
return true ;
78
94
}
79
- // *_allow
80
- let allow_end = Some ( '_' ) . into_iter ( ) . chain ( allow . chars ( ) ) ;
95
+ // *_name
96
+ let allow_end = Some ( '_' ) . into_iter ( ) . chain ( name . chars ( ) ) ;
81
97
if interned_name. chars ( ) . rev ( ) . zip ( allow_end. rev ( ) ) . all ( |( l, r) | l == r) {
82
98
return true ;
83
99
}
@@ -110,29 +126,28 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
110
126
}
111
127
let count = interned_name. chars ( ) . count ( ) ;
112
128
if count < 3 {
113
- if count != 1 {
114
- return ;
129
+ if count == 1 {
130
+ let c = interned_name. chars ( ) . next ( ) . expect ( "already checked" ) ;
131
+ self . check_short_name ( c, span) ;
115
132
}
116
- let c = interned_name. chars ( ) . next ( ) . expect ( "already checked" ) ;
117
- self . check_short_name ( c, span) ;
118
- return ;
119
- }
120
- if whitelisted ( & interned_name) {
121
133
return ;
122
134
}
123
- for & ( ref existing_name, sp, existing_len) in & self . 0 . names {
135
+ for existing_name in & self . 0 . names {
136
+ if whitelisted ( & interned_name, existing_name. whitelist ) {
137
+ continue ;
138
+ }
124
139
let mut split_at = None ;
125
- if existing_len > count {
126
- if existing_len - count != 1 || levenstein_not_1 ( & interned_name, & existing_name) {
140
+ if existing_name . len > count {
141
+ if existing_name . len - count != 1 || levenstein_not_1 ( & interned_name, & existing_name. interned ) {
127
142
continue ;
128
143
}
129
- } else if existing_len < count {
130
- if count - existing_len != 1 || levenstein_not_1 ( & existing_name, & interned_name) {
144
+ } else if existing_name . len < count {
145
+ if count - existing_name . len != 1 || levenstein_not_1 ( & existing_name. interned , & interned_name) {
131
146
continue ;
132
147
}
133
148
} else {
134
149
let mut interned_chars = interned_name. chars ( ) ;
135
- let mut existing_chars = existing_name. chars ( ) ;
150
+ let mut existing_chars = existing_name. interned . chars ( ) ;
136
151
let first_i = interned_chars. next ( ) . expect ( "we know we have at least one char" ) ;
137
152
let first_e = existing_chars. next ( ) . expect ( "we know we have at least one char" ) ;
138
153
let eq_or_numeric = |a : char , b : char | a == b || a. is_numeric ( ) && b. is_numeric ( ) ;
@@ -170,7 +185,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
170
185
span,
171
186
"binding's name is too similar to existing binding" ,
172
187
|diag| {
173
- diag. span_note ( sp , "existing binding defined here" ) ;
188
+ diag. span_note ( existing_name . span , "existing binding defined here" ) ;
174
189
if let Some ( split) = split_at {
175
190
diag. span_help ( span, & format ! ( "separate the discriminating character \
176
191
by an underscore like: `{}_{}`",
@@ -180,7 +195,12 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
180
195
} ) ;
181
196
return ;
182
197
}
183
- self . 0 . names . push ( ( interned_name, span, count) ) ;
198
+ self . 0 . names . push ( ExistingName {
199
+ whitelist : get_whitelist ( & interned_name) . unwrap_or ( & [ ] ) ,
200
+ interned : interned_name,
201
+ span : span,
202
+ len : count,
203
+ } ) ;
184
204
}
185
205
}
186
206
0 commit comments