@@ -10,7 +10,6 @@ import (
10
10
"go/ast"
11
11
"go/token"
12
12
"go/types"
13
- "strings"
14
13
15
14
"golang.org/x/tools/go/ast/astutil"
16
15
"golang.org/x/tools/gopls/internal/lsp/protocol"
@@ -67,10 +66,27 @@ func highlightPath(path []ast.Node, file *ast.File, info *types.Info) (map[posRa
67
66
result := make (map [posRange ]struct {})
68
67
switch node := path [0 ].(type ) {
69
68
case * ast.BasicLit :
69
+ // Import path string literal?
70
70
if len (path ) > 1 {
71
- if _ , ok := path [1 ].(* ast.ImportSpec ); ok {
72
- err := highlightImportUses (path , info , result )
73
- return result , err
71
+ if imp , ok := path [1 ].(* ast.ImportSpec ); ok {
72
+ highlight := func (n ast.Node ) {
73
+ result [posRange {start : n .Pos (), end : n .End ()}] = struct {}{}
74
+ }
75
+
76
+ // Highlight the import itself...
77
+ highlight (imp )
78
+
79
+ // ...and all references to it in the file.
80
+ if pkgname , ok := ImportedPkgName (info , imp ); ok {
81
+ ast .Inspect (file , func (n ast.Node ) bool {
82
+ if id , ok := n .(* ast.Ident ); ok &&
83
+ info .Uses [id ] == pkgname {
84
+ highlight (id )
85
+ }
86
+ return true
87
+ })
88
+ }
89
+ return result , nil
74
90
}
75
91
}
76
92
highlightFuncControlFlow (path , result )
@@ -419,66 +435,46 @@ Outer:
419
435
})
420
436
}
421
437
422
- func highlightImportUses (path []ast.Node , info * types.Info , result map [posRange ]struct {}) error {
423
- basicLit , ok := path [0 ].(* ast.BasicLit )
424
- if ! ok {
425
- return fmt .Errorf ("highlightImportUses called with an ast.Node of type %T" , basicLit )
426
- }
427
- ast .Inspect (path [len (path )- 1 ], func (node ast.Node ) bool {
428
- if imp , ok := node .(* ast.ImportSpec ); ok && imp .Path == basicLit {
429
- result [posRange {start : node .Pos (), end : node .End ()}] = struct {}{}
430
- return false
431
- }
432
- n , ok := node .(* ast.Ident )
433
- if ! ok {
434
- return true
435
- }
436
- obj , ok := info .ObjectOf (n ).(* types.PkgName )
437
- if ! ok {
438
- return true
439
- }
440
- if ! strings .Contains (basicLit .Value , obj .Name ()) {
441
- return true
442
- }
438
+ func highlightIdentifier (id * ast.Ident , file * ast.File , info * types.Info , result map [posRange ]struct {}) {
439
+ highlight := func (n ast.Node ) {
443
440
result [posRange {start : n .Pos (), end : n .End ()}] = struct {}{}
444
- return false
445
- })
446
- return nil
447
- }
441
+ }
448
442
449
- func highlightIdentifier (id * ast.Ident , file * ast.File , info * types.Info , result map [posRange ]struct {}) {
450
- // TODO(rfindley): idObj may be nil. Note that returning early in this case
451
- // causes tests to fail (because the nObj == idObj check below was succeeded
452
- // for nil == nil!)
453
- //
454
- // Revisit this. If ObjectOf is nil, there are type errors, and it seems
455
- // reasonable for identifier highlighting not to work.
456
- idObj := info .ObjectOf (id )
457
- pkgObj , isImported := idObj .(* types.PkgName )
458
- ast .Inspect (file , func (node ast.Node ) bool {
459
- if imp , ok := node .(* ast.ImportSpec ); ok && isImported {
460
- highlightImport (pkgObj , imp , result )
461
- }
462
- n , ok := node .(* ast.Ident )
463
- if ! ok {
464
- return true
465
- }
466
- if n .Name != id .Name {
467
- return false
468
- }
469
- if nObj := info .ObjectOf (n ); nObj == idObj {
470
- result [posRange {start : n .Pos (), end : n .End ()}] = struct {}{}
443
+ // obj may be nil if the Ident is undefined.
444
+ // In this case, the behavior expected by tests is
445
+ // to match other undefined Idents of the same name.
446
+ obj := info .ObjectOf (id )
447
+
448
+ ast .Inspect (file , func (n ast.Node ) bool {
449
+ switch n := n .(type ) {
450
+ case * ast.Ident :
451
+ if n .Name == id .Name && info .ObjectOf (n ) == obj {
452
+ highlight (n )
453
+ }
454
+
455
+ case * ast.ImportSpec :
456
+ pkgname , ok := ImportedPkgName (info , n )
457
+ if ok && pkgname == obj {
458
+ if n .Name != nil {
459
+ highlight (n .Name )
460
+ } else {
461
+ highlight (n )
462
+ }
463
+ }
471
464
}
472
- return false
465
+ return true
473
466
})
474
467
}
475
468
476
- func highlightImport (obj * types.PkgName , imp * ast.ImportSpec , result map [posRange ]struct {}) {
477
- if imp .Name != nil || imp .Path == nil {
478
- return
479
- }
480
- if ! strings .Contains (imp .Path .Value , obj .Name ()) {
481
- return
469
+ // ImportedPkgName returns the PkgName object declared by an ImportSpec.
470
+ // TODO(adonovan): make this a method of types.Info.
471
+ func ImportedPkgName (info * types.Info , imp * ast.ImportSpec ) (* types.PkgName , bool ) {
472
+ var obj types.Object
473
+ if imp .Name != nil {
474
+ obj = info .Defs [imp .Name ]
475
+ } else {
476
+ obj = info .Implicits [imp ]
482
477
}
483
- result [posRange {start : imp .Path .Pos (), end : imp .Path .End ()}] = struct {}{}
478
+ pkgname , ok := obj .(* types.PkgName )
479
+ return pkgname , ok
484
480
}
0 commit comments