@@ -7,6 +7,8 @@ package misc
7
7
import (
8
8
"fmt"
9
9
"os"
10
+ "path/filepath"
11
+ "reflect"
10
12
"sort"
11
13
"strings"
12
14
"testing"
@@ -315,11 +317,11 @@ func _() {
315
317
// - inside the foo.mod/bar [foo.mod/bar.test] test variant package
316
318
// - from the foo.mod/bar_test [foo.mod/bar.test] x_test package
317
319
// - from the foo.mod/foo package
318
- {"Blah" , []string {"bar/bar.go" , "bar/bar_test.go" , "bar/bar_x_test.go" , "foo/foo.go" }},
320
+ {"Blah" , []string {"bar/bar.go:3 " , "bar/bar_test.go:7 " , "bar/bar_x_test.go:12 " , "foo/foo.go:12 " }},
319
321
320
322
// Foo is referenced in bar_x_test.go via the intermediate test variant
321
323
// foo.mod/foo [foo.mod/bar.test].
322
- {"Foo" , []string {"bar/bar_x_test.go" , "foo/foo.go" }},
324
+ {"Foo" , []string {"bar/bar_x_test.go:13 " , "foo/foo.go:5 " }},
323
325
}
324
326
325
327
for _ , test := range refTests {
@@ -339,11 +341,11 @@ func _() {
339
341
// InterfaceM is implemented both in foo.mod/bar [foo.mod/bar.test] (which
340
342
// doesn't import foo), and in foo.mod/bar_test [foo.mod/bar.test], which
341
343
// imports the test variant of foo.
342
- {"InterfaceM" , []string {"bar/bar_test.go" , "bar/bar_x_test.go" }},
344
+ {"InterfaceM" , []string {"bar/bar_test.go:3 " , "bar/bar_x_test.go:8 " }},
343
345
344
346
// A search within the ordinary package to should find implementations
345
347
// (Fer) within the augmented test package.
346
- {"InterfaceF" , []string {"foo/foo_test.go" }},
348
+ {"InterfaceF" , []string {"foo/foo_test.go:3 " }},
347
349
}
348
350
349
351
for _ , test := range implTests {
@@ -503,19 +505,78 @@ func F() {} // declaration
503
505
env .OpenFile ("a/a.go" )
504
506
refLoc := env .RegexpSearch ("a/a.go" , "F" )
505
507
got := fileLocations (env , env .References (refLoc ))
506
- want := []string {"a/a.go" , "b/b.go" , "lib/lib.go" }
508
+ want := []string {"a/a.go:5 " , "b/b.go:5 " , "lib/lib.go:3 " }
507
509
if diff := cmp .Diff (want , got ); diff != "" {
508
510
t .Errorf ("incorrect References (-want +got):\n %s" , diff )
509
511
}
510
512
})
511
513
}
512
514
513
- // fileLocations returns a new sorted array of the relative
514
- // file name of each location. Duplicates are not removed.
515
+ // Test an 'implementation' query on a type that implements 'error'.
516
+ // (Unfortunately builtin locations cannot be expressed using @loc
517
+ // in the marker test framework.)
518
+ func TestImplementationsOfError (t * testing.T ) {
519
+ const src = `
520
+ -- go.mod --
521
+ module example.com
522
+ go 1.12
523
+
524
+ -- a.go --
525
+ package a
526
+
527
+ type Error2 interface {
528
+ Error() string
529
+ }
530
+
531
+ type MyError int
532
+ func (MyError) Error() string { return "" }
533
+
534
+ type MyErrorPtr int
535
+ func (*MyErrorPtr) Error() string { return "" }
536
+ `
537
+ Run (t , src , func (t * testing.T , env * Env ) {
538
+ env .OpenFile ("a.go" )
539
+
540
+ for _ , test := range []struct {
541
+ re string
542
+ want []string
543
+ }{
544
+ // error type
545
+ {"Error2" , []string {"a.go:10" , "a.go:7" , "std:builtin/builtin.go" }},
546
+ {"MyError" , []string {"a.go:3" , "std:builtin/builtin.go" }},
547
+ {"MyErrorPtr" , []string {"a.go:3" , "std:builtin/builtin.go" }},
548
+ // error.Error method
549
+ {"(Error).. string" , []string {"a.go:11" , "a.go:8" , "std:builtin/builtin.go" }},
550
+ {"MyError. (Error)" , []string {"a.go:4" , "std:builtin/builtin.go" }},
551
+ {"MyErrorPtr. (Error)" , []string {"a.go:4" , "std:builtin/builtin.go" }},
552
+ } {
553
+ matchLoc := env .RegexpSearch ("a.go" , test .re )
554
+ impls := env .Implementations (matchLoc )
555
+ got := fileLocations (env , impls )
556
+ if ! reflect .DeepEqual (got , test .want ) {
557
+ t .Errorf ("Implementations(%q) = %q, want %q" ,
558
+ test .re , got , test .want )
559
+ }
560
+ }
561
+ })
562
+ }
563
+
564
+ // fileLocations returns a new sorted array of the
565
+ // relative file name and line number of each location.
566
+ // Duplicates are not removed.
567
+ // Standard library filenames are abstracted for robustness.
515
568
func fileLocations (env * regtest.Env , locs []protocol.Location ) []string {
516
569
got := make ([]string , 0 , len (locs ))
517
570
for _ , loc := range locs {
518
- got = append (got , env .Sandbox .Workdir .URIToPath (loc .URI ))
571
+ path := env .Sandbox .Workdir .URIToPath (loc .URI ) // (slashified)
572
+ if i := strings .Index (path , "/src/" ); i >= 0 && filepath .IsAbs (path ) {
573
+ // Absolute path with "src" segment: assume it's in GOROOT.
574
+ // Strip directory and don't add line/column since they are fragile.
575
+ path = "std:" + path [i + len ("/src/" ):]
576
+ } else {
577
+ path = fmt .Sprintf ("%s:%d" , path , loc .Range .Start .Line + 1 )
578
+ }
579
+ got = append (got , path )
519
580
}
520
581
sort .Strings (got )
521
582
return got
0 commit comments