@@ -14,6 +14,7 @@ mod str_helpers;
14
14
use std:: sync:: Arc ;
15
15
16
16
use hir_def:: {
17
+ adt:: VariantData ,
17
18
body:: Body ,
18
19
db:: DefDatabase ,
19
20
expr:: { Expr , ExprId , UnaryOp } ,
@@ -205,6 +206,133 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
205
206
206
207
fn validate_struct ( & mut self , db : & dyn HirDatabase , struct_id : StructId ) {
207
208
let data = db. struct_data ( struct_id) ;
209
+
210
+ // 1. Check the structure name.
211
+ let struct_name = data. name . to_string ( ) ;
212
+ let struct_name_replacement = if let Some ( new_name) = to_camel_case ( & struct_name) {
213
+ let replacement = Replacement {
214
+ current_name : data. name . clone ( ) ,
215
+ suggested_text : new_name,
216
+ expected_case : CaseType :: UpperCamelCase ,
217
+ } ;
218
+ Some ( replacement)
219
+ } else {
220
+ None
221
+ } ;
222
+
223
+ // 2. Check the field names.
224
+ let mut struct_fields_replacements = Vec :: new ( ) ;
225
+
226
+ if let VariantData :: Record ( fields) = data. variant_data . as_ref ( ) {
227
+ for ( _, field) in fields. iter ( ) {
228
+ let field_name = field. name . to_string ( ) ;
229
+ if let Some ( new_name) = to_lower_snake_case ( & field_name) {
230
+ let replacement = Replacement {
231
+ current_name : field. name . clone ( ) ,
232
+ suggested_text : new_name,
233
+ expected_case : CaseType :: LowerSnakeCase ,
234
+ } ;
235
+ struct_fields_replacements. push ( replacement) ;
236
+ }
237
+ }
238
+ }
239
+
240
+ // 3. If there is at least one element to spawn a warning on, go to the source map and generate a warning.
241
+ self . create_incorrect_case_diagnostic_for_struct (
242
+ struct_id,
243
+ db,
244
+ struct_name_replacement,
245
+ struct_fields_replacements,
246
+ )
247
+ }
248
+
249
+ /// Given the information about incorrect names in the struct declaration, looks up into the source code
250
+ /// for exact locations and adds diagnostics into the sink.
251
+ fn create_incorrect_case_diagnostic_for_struct (
252
+ & mut self ,
253
+ struct_id : StructId ,
254
+ db : & dyn HirDatabase ,
255
+ struct_name_replacement : Option < Replacement > ,
256
+ struct_fields_replacements : Vec < Replacement > ,
257
+ ) {
258
+ // XXX: only look at sources if we do have incorrect names
259
+ if struct_name_replacement. is_none ( ) && struct_fields_replacements. is_empty ( ) {
260
+ return ;
261
+ }
262
+
263
+ let struct_loc = struct_id. lookup ( db. upcast ( ) ) ;
264
+ let struct_src = struct_loc. source ( db. upcast ( ) ) ;
265
+
266
+ if let Some ( replacement) = struct_name_replacement {
267
+ let ast_ptr = if let Some ( name) = struct_src. value . name ( ) {
268
+ name
269
+ } else {
270
+ // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic.
271
+ log:: error!(
272
+ "Replacement ({:?}) was generated for a structure without a name: {:?}" ,
273
+ replacement,
274
+ struct_src
275
+ ) ;
276
+ return ;
277
+ } ;
278
+
279
+ let diagnostic = IncorrectCase {
280
+ file : struct_src. file_id ,
281
+ ident_type : "Structure" . to_string ( ) ,
282
+ ident : AstPtr :: new ( & ast_ptr) . into ( ) ,
283
+ expected_case : replacement. expected_case ,
284
+ ident_text : replacement. current_name . to_string ( ) ,
285
+ suggested_text : replacement. suggested_text ,
286
+ } ;
287
+
288
+ self . sink . push ( diagnostic) ;
289
+ }
290
+
291
+ // let fn_params_list = match fn_src.value.param_list() {
292
+ // Some(params) => params,
293
+ // None => {
294
+ // if !fn_param_replacements.is_empty() {
295
+ // log::error!(
296
+ // "Replacements ({:?}) were generated for a function parameters which had no parameters list: {:?}",
297
+ // fn_param_replacements, fn_src
298
+ // );
299
+ // }
300
+ // return;
301
+ // }
302
+ // };
303
+ // let mut fn_params_iter = fn_params_list.params();
304
+ // for param_to_rename in fn_param_replacements {
305
+ // // We assume that parameters in replacement are in the same order as in the
306
+ // // actual params list, but just some of them (ones that named correctly) are skipped.
307
+ // let ast_ptr = loop {
308
+ // match fn_params_iter.next() {
309
+ // Some(element)
310
+ // if pat_equals_to_name(element.pat(), ¶m_to_rename.current_name) =>
311
+ // {
312
+ // break element.pat().unwrap()
313
+ // }
314
+ // Some(_) => {}
315
+ // None => {
316
+ // log::error!(
317
+ // "Replacement ({:?}) was generated for a function parameter which was not found: {:?}",
318
+ // param_to_rename, fn_src
319
+ // );
320
+ // return;
321
+ // }
322
+ // }
323
+ // };
324
+
325
+ // let diagnostic = IncorrectCase {
326
+ // file: fn_src.file_id,
327
+ // ident_type: "Argument".to_string(),
328
+ // ident: AstPtr::new(&ast_ptr).into(),
329
+ // expected_case: param_to_rename.expected_case,
330
+ // ident_text: param_to_rename.current_name.to_string(),
331
+ // suggested_text: param_to_rename.suggested_text,
332
+ // };
333
+
334
+ // self.sink.push(diagnostic);
335
+ // }
208
336
}
209
337
210
338
fn validate_enum ( & mut self , db : & dyn HirDatabase , enum_id : EnumId ) {
@@ -243,6 +371,16 @@ fn foo(SomeParam: u8) {}
243
371
244
372
fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
245
373
// ^^^^^^^^^^ Argument `CAPS_PARAM` should have a snake_case name, e.g. `caps_param`
374
+ "# ,
375
+ ) ;
376
+ }
377
+
378
+ #[ test]
379
+ fn incorrect_struct_name ( ) {
380
+ check_diagnostics (
381
+ r#"
382
+ struct non_camel_case_name {}
383
+ // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have a CamelCase name, e.g. `NonCamelCaseName`
246
384
"# ,
247
385
) ;
248
386
}
0 commit comments