@@ -21,7 +21,10 @@ use hir_def::{
21
21
AdtId , FunctionId , Lookup , ModuleDefId ,
22
22
} ;
23
23
use hir_expand:: { diagnostics:: DiagnosticSink , name:: Name } ;
24
- use syntax:: { ast:: NameOwner , AstPtr } ;
24
+ use syntax:: {
25
+ ast:: { self , NameOwner } ,
26
+ AstPtr ,
27
+ } ;
25
28
26
29
use crate :: {
27
30
db:: HirDatabase ,
@@ -122,14 +125,16 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
122
125
} else {
123
126
// We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic.
124
127
log:: error!(
125
- "Replacement was generated for a function without a name: {:?}" ,
128
+ "Replacement ({:?}) was generated for a function without a name: {:?}" ,
129
+ replacement,
126
130
fn_src
127
131
) ;
128
132
return ;
129
133
} ;
130
134
131
135
let diagnostic = IncorrectCase {
132
136
file : fn_src. file_id ,
137
+ ident_type : "Function" . to_string ( ) ,
133
138
ident : AstPtr :: new ( & ast_ptr) . into ( ) ,
134
139
expected_case : replacement. expected_case ,
135
140
ident_text : replacement. current_name . to_string ( ) ,
@@ -139,15 +144,71 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
139
144
self . sink . push ( diagnostic) ;
140
145
}
141
146
142
- // let item_tree = db.item_tree(loc.id.file_id);
143
- // let fn_def = &item_tree[fn_loc.id.value];
144
- // let (_, source_map) = db.body_with_source_map(func.into());
147
+ let fn_params_list = match fn_src. value . param_list ( ) {
148
+ Some ( params) => params,
149
+ None => {
150
+ if !fn_param_replacements. is_empty ( ) {
151
+ log:: error!(
152
+ "Replacements ({:?}) were generated for a function parameters which had no parameters list: {:?}" ,
153
+ fn_param_replacements, fn_src
154
+ ) ;
155
+ }
156
+ return ;
157
+ }
158
+ } ;
159
+ let mut fn_params_iter = fn_params_list. params ( ) ;
160
+ for param_to_rename in fn_param_replacements {
161
+ // We assume that parameters in replacement are in the same order as in the
162
+ // actual params list, but just some of them (ones that named correctly) are skipped.
163
+ let ast_ptr = loop {
164
+ match fn_params_iter. next ( ) {
165
+ Some ( element)
166
+ if pat_equals_to_name ( element. pat ( ) , & param_to_rename. current_name ) =>
167
+ {
168
+ break element. pat ( ) . unwrap ( )
169
+ }
170
+ Some ( _) => { }
171
+ None => {
172
+ log:: error!(
173
+ "Replacement ({:?}) was generated for a function parameter which was not found: {:?}" ,
174
+ param_to_rename, fn_src
175
+ ) ;
176
+ return ;
177
+ }
178
+ }
179
+ } ;
180
+
181
+ let diagnostic = IncorrectCase {
182
+ file : fn_src. file_id ,
183
+ ident_type : "Argument" . to_string ( ) ,
184
+ ident : AstPtr :: new ( & ast_ptr) . into ( ) ,
185
+ expected_case : param_to_rename. expected_case ,
186
+ ident_text : param_to_rename. current_name . to_string ( ) ,
187
+ suggested_text : param_to_rename. suggested_text ,
188
+ } ;
189
+
190
+ self . sink . push ( diagnostic) ;
191
+ }
145
192
}
146
193
147
194
fn validate_adt ( & mut self , db : & dyn HirDatabase , adt : AdtId ) { }
148
195
}
149
196
197
+ fn pat_equals_to_name ( pat : Option < ast:: Pat > , name : & Name ) -> bool {
198
+ if let Some ( ast:: Pat :: IdentPat ( ident) ) = pat {
199
+ ident. to_string ( ) == name. to_string ( )
200
+ } else {
201
+ false
202
+ }
203
+ }
204
+
150
205
fn to_lower_snake_case ( ident : & str ) -> Option < String > {
206
+ // First, assume that it's UPPER_SNAKE_CASE.
207
+ if let Some ( normalized) = to_lower_snake_case_from_upper_snake_case ( ident) {
208
+ return Some ( normalized) ;
209
+ }
210
+
211
+ // Otherwise, assume that it's CamelCase.
151
212
let lower_snake_case = stdx:: to_lower_snake_case ( ident) ;
152
213
153
214
if lower_snake_case == ident {
@@ -157,6 +218,17 @@ fn to_lower_snake_case(ident: &str) -> Option<String> {
157
218
}
158
219
}
159
220
221
+ fn to_lower_snake_case_from_upper_snake_case ( ident : & str ) -> Option < String > {
222
+ let is_upper_snake_case = ident. chars ( ) . all ( |c| c. is_ascii_uppercase ( ) || c == '_' ) ;
223
+
224
+ if is_upper_snake_case {
225
+ let string = ident. chars ( ) . map ( |c| c. to_ascii_lowercase ( ) ) . collect ( ) ;
226
+ Some ( string)
227
+ } else {
228
+ None
229
+ }
230
+ }
231
+
160
232
#[ cfg( test) ]
161
233
mod tests {
162
234
use crate :: diagnostics:: tests:: check_diagnostics;
@@ -166,7 +238,20 @@ mod tests {
166
238
check_diagnostics (
167
239
r#"
168
240
fn NonSnakeCaseName() {}
169
- // ^^^^^^^^^^^^^^^^ Argument `NonSnakeCaseName` should have a snake_case name, e.g. `non_snake_case_name`
241
+ // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have a snake_case name, e.g. `non_snake_case_name`
242
+ "# ,
243
+ ) ;
244
+ }
245
+
246
+ #[ test]
247
+ fn incorrect_function_params ( ) {
248
+ check_diagnostics (
249
+ r#"
250
+ fn foo(SomeParam: u8) {}
251
+ // ^^^^^^^^^ Argument `SomeParam` should have a snake_case name, e.g. `some_param`
252
+
253
+ fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
254
+ // ^^^^^^^^^^ Argument `CAPS_PARAM` should have a snake_case name, e.g. `caps_param`
170
255
"# ,
171
256
) ;
172
257
}
0 commit comments