4
4
"go/ast"
5
5
"go/token"
6
6
"go/types"
7
+ "sort"
7
8
"strings"
8
9
9
10
"golang.org/x/tools/go/analysis"
@@ -169,7 +170,7 @@ func (v *varNameLen) run(pass *analysis.Pass) {
169
170
}
170
171
171
172
// checkVariables applies v to variables in varToDist.
172
- func (v * varNameLen ) checkVariables (pass * analysis.Pass , varToDist map [variable ]int ) {
173
+ func (v * varNameLen ) checkVariables (pass * analysis.Pass , varToDist map [variable ]int ) { //nolint:gocognit // it's not that complicated
173
174
for variable , dist := range varToDist {
174
175
if v .ignoreNames .contains (variable .name ) {
175
176
continue
@@ -195,6 +196,10 @@ func (v *varNameLen) checkVariables(pass *analysis.Pass, varToDist map[variable]
195
196
continue
196
197
}
197
198
199
+ if variable .isConventional () {
200
+ continue
201
+ }
202
+
198
203
if variable .assign != nil {
199
204
pass .Reportf (variable .assign .Pos (), "%s name '%s' is too short for the scope of its usage" , variable .kindName (), variable .name )
200
205
continue
@@ -279,16 +284,23 @@ func (v *varNameLen) checkChannelReceiveOk(vari variable) bool {
279
284
280
285
// distances returns maps of variables, parameters, and return values mapping to their longest usage distances.
281
286
func (v * varNameLen ) distances (pass * analysis.Pass ) (map [variable ]int , map [parameter ]int , map [parameter ]int ) {
282
- assignIdents , valueSpecIdents , paramIdents , returnIdents , imports := v .identsAndImports (pass )
287
+ assignIdents , valueSpecIdents , paramIdents , returnIdents , imports , switches := v .identsAndImports (pass )
283
288
284
289
varToDist := map [variable ]int {}
285
290
286
291
for _ , ident := range assignIdents {
287
292
assign := ident .Obj .Decl .(* ast.AssignStmt ) //nolint:forcetypeassert // check is done in identsAndImports
288
293
294
+ var typ string
295
+ if isTypeSwitchAssign (assign , switches ) {
296
+ typ = "<type-switched>"
297
+ } else {
298
+ typ = shortTypeName (pass .TypesInfo .TypeOf (ident ), imports )
299
+ }
300
+
289
301
variable := variable {
290
302
name : ident .Name ,
291
- typ : shortTypeName ( pass . TypesInfo . TypeOf ( identAssignExpr ( ident , assign )), imports ) ,
303
+ typ : typ ,
292
304
assign : assign ,
293
305
}
294
306
@@ -303,7 +315,7 @@ func (v *varNameLen) distances(pass *analysis.Pass) (map[variable]int, map[param
303
315
variable := variable {
304
316
name : ident .Name ,
305
317
constant : ident .Obj .Kind == ast .Con ,
306
- typ : shortTypeName (pass .TypesInfo .TypeOf (valueSpec . Type ), imports ),
318
+ typ : shortTypeName (pass .TypesInfo .TypeOf (ident ), imports ),
307
319
valueSpec : valueSpec ,
308
320
}
309
321
@@ -335,7 +347,7 @@ func (v *varNameLen) distances(pass *analysis.Pass) (map[variable]int, map[param
335
347
336
348
param := parameter {
337
349
name : ident .Name ,
338
- typ : shortTypeName (pass .TypesInfo .TypeOf (field . Type ), imports ),
350
+ typ : shortTypeName (pass .TypesInfo .TypeOf (ident ), imports ),
339
351
field : field ,
340
352
}
341
353
@@ -348,18 +360,22 @@ func (v *varNameLen) distances(pass *analysis.Pass) (map[variable]int, map[param
348
360
}
349
361
350
362
// identsAndImports returns Idents referencing assign statements, value specifications, parameters, and return values, respectively,
351
- // as well as import declarations.
352
- func (v * varNameLen ) identsAndImports (pass * analysis.Pass ) ([]* ast.Ident , []* ast.Ident , []* ast.Ident , []* ast.Ident , []importDeclaration ) { //nolint:gocognit,cyclop // this is complex stuff
363
+ // as well as import declarations, and type switch statements .
364
+ func (v * varNameLen ) identsAndImports (pass * analysis.Pass ) ([]* ast.Ident , []* ast.Ident , []* ast.Ident , []* ast.Ident , []importDeclaration , [] * ast. TypeSwitchStmt ) { //nolint:gocognit,cyclop // this is complex stuff
353
365
inspector := pass .ResultOf [inspect .Analyzer ].(* inspector.Inspector ) //nolint:forcetypeassert // inspect.Analyzer always returns *inspector.Inspector
354
366
355
367
filter := []ast.Node {
356
368
(* ast .ImportSpec )(nil ),
357
369
(* ast .FuncDecl )(nil ),
370
+ (* ast .CompositeLit )(nil ),
371
+ (* ast .TypeSwitchStmt )(nil ),
358
372
(* ast .Ident )(nil ),
359
373
}
360
374
361
375
funcs := []* ast.FuncDecl {}
362
376
methods := []* ast.FuncDecl {}
377
+ compositeLits := []* ast.CompositeLit {}
378
+ switches := []* ast.TypeSwitchStmt {}
363
379
364
380
imports := []importDeclaration {}
365
381
assignIdents := []* ast.Ident {}
@@ -386,11 +402,21 @@ func (v *varNameLen) identsAndImports(pass *analysis.Pass) ([]*ast.Ident, []*ast
386
402
387
403
methods = append (methods , node2 )
388
404
405
+ case * ast.CompositeLit :
406
+ compositeLits = append (compositeLits , node2 )
407
+
408
+ case * ast.TypeSwitchStmt :
409
+ switches = append (switches , node2 )
410
+
389
411
case * ast.Ident :
390
412
if node2 .Obj == nil {
391
413
return
392
414
}
393
415
416
+ if isCompositeLitKey (node2 , compositeLits ) {
417
+ return
418
+ }
419
+
394
420
switch objDecl := node2 .Obj .Decl .(type ) {
395
421
case * ast.AssignStmt :
396
422
assignIdents = append (assignIdents , node2 )
@@ -399,7 +425,13 @@ func (v *varNameLen) identsAndImports(pass *analysis.Pass) ([]*ast.Ident, []*ast
399
425
valueSpecIdents = append (valueSpecIdents , node2 )
400
426
401
427
case * ast.Field :
402
- if isReceiver (objDecl , methods ) && ! v .checkReceiver {
428
+ if isReceiver (objDecl , methods ) {
429
+ if ! v .checkReceiver {
430
+ return
431
+ }
432
+
433
+ paramIdents = append (paramIdents , node2 )
434
+
403
435
return
404
436
}
405
437
@@ -423,7 +455,12 @@ func (v *varNameLen) identsAndImports(pass *analysis.Pass) ([]*ast.Ident, []*ast
423
455
self : true ,
424
456
})
425
457
426
- return assignIdents , valueSpecIdents , paramIdents , returnIdents , imports
458
+ sort .Slice (imports , func (a , b int ) bool {
459
+ // reversed: longest path first
460
+ return len (imports [a ].path ) > len (imports [b ].path )
461
+ })
462
+
463
+ return assignIdents , valueSpecIdents , paramIdents , returnIdents , imports , switches
427
464
}
428
465
429
466
func importSpecToDecl (spec * ast.ImportSpec , imports []* types.Package ) (importDeclaration , bool ) {
@@ -555,6 +592,18 @@ func (v variable) isChannelReceiveOk() bool {
555
592
return true
556
593
}
557
594
595
+ // isConventional returns true if v matches a conventional Go variable/parameter name and type,
596
+ // such as "ctx context.Context" or "t *testing.T".
597
+ func (v variable ) isConventional () bool {
598
+ for _ , decl := range conventionalDecls {
599
+ if v .match (decl ) {
600
+ return true
601
+ }
602
+ }
603
+
604
+ return false
605
+ }
606
+
558
607
// match returns true if v matches decl.
559
608
func (v variable ) match (decl declaration ) bool {
560
609
if v .name != decl .name {
@@ -615,8 +664,41 @@ func isReturn(field *ast.Field, funcs []*ast.FuncDecl) bool {
615
664
return false
616
665
}
617
666
618
- // isConventional returns true if p is a conventional Go parameter, such as "ctx context.Context" or
619
- // "t *testing.T".
667
+ // isKeyValueKey returns true if ident is a key of any of the given key/value expressions.
668
+ func isCompositeLitKey (ident * ast.Ident , compositeLits []* ast.CompositeLit ) bool {
669
+ for _ , cl := range compositeLits {
670
+ if _ , ok := cl .Type .(* ast.MapType ); ok {
671
+ continue
672
+ }
673
+
674
+ for _ , kvExpr := range cl .Elts {
675
+ kv , ok := kvExpr .(* ast.KeyValueExpr )
676
+ if ! ok {
677
+ continue
678
+ }
679
+
680
+ if kv .Key == ident {
681
+ return true
682
+ }
683
+ }
684
+ }
685
+
686
+ return false
687
+ }
688
+
689
+ // isTypeSwitchAssign returns true if assign is an assign statement of any of the given type switch statements.
690
+ func isTypeSwitchAssign (assign * ast.AssignStmt , switches []* ast.TypeSwitchStmt ) bool {
691
+ for _ , s := range switches {
692
+ if s .Assign == assign {
693
+ return true
694
+ }
695
+ }
696
+
697
+ return false
698
+ }
699
+
700
+ // isConventional returns true if v matches a conventional Go variable/parameter name and type,
701
+ // such as "ctx context.Context" or "t *testing.T".
620
702
func (p parameter ) isConventional () bool {
621
703
for _ , decl := range conventionalDecls {
622
704
if p .match (decl ) {
@@ -658,17 +740,6 @@ func (d declaration) matchType(typ string) bool {
658
740
return d .typ == typ
659
741
}
660
742
661
- // identAssignExpr returns the expression that is assigned to ident.
662
- //
663
- // TODO: This currently only works for simple one-to-one assignments without the use of multi-values.
664
- func identAssignExpr (_ * ast.Ident , assign * ast.AssignStmt ) ast.Expr {
665
- if len (assign .Lhs ) != 1 || len (assign .Rhs ) != 1 {
666
- return nil
667
- }
668
-
669
- return assign .Rhs [0 ]
670
- }
671
-
672
743
// shortTypeName returns the short name of typ, with respect to imports.
673
744
// For example, if package github.com/matryer/is is imported with alias "x",
674
745
// and typ represents []*github.com/matryer/is.I, shortTypeName will return "[]*x.I".
@@ -683,12 +754,12 @@ func shortTypeName(typ types.Type, imports []importDeclaration) string {
683
754
for _ , imp := range imports {
684
755
prefix := imp .path + "."
685
756
686
- if imp . self {
687
- typStr = strings . ReplaceAll ( typStr , prefix , "" )
688
- continue
757
+ replace := ""
758
+ if ! imp . self {
759
+ replace = imp . name + "."
689
760
}
690
761
691
- typStr = strings .ReplaceAll (typStr , prefix , imp . name + "." )
762
+ typStr = strings .ReplaceAll (typStr , prefix , replace )
692
763
}
693
764
694
765
return typStr
0 commit comments