internal/lsp: tweak implementation tests

- Add test count to golden file so test count gets checked.
- Make @implementation note take a list of marks similar to completion
  tests.
- Get rid of unnecessary intermediate test data type.

Change-Id: I741eb14b77b0b8ed08e86c634ed39457116e8718
Reviewed-on: https://go-review.googlesource.com/c/tools/+/210278
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cmd/test/implementation.go b/internal/lsp/cmd/test/implementation.go
index 3bd4b5f..30c5f0d 100644
--- a/internal/lsp/cmd/test/implementation.go
+++ b/internal/lsp/cmd/test/implementation.go
@@ -9,13 +9,12 @@
 	"sort"
 	"testing"
 
-	"golang.org/x/tools/internal/lsp/tests"
 	"golang.org/x/tools/internal/span"
 )
 
-func (r *runner) Implementation(t *testing.T, spn span.Span, imp tests.Implementations) {
+func (r *runner) Implementation(t *testing.T, spn span.Span, imps []span.Span) {
 	var itemStrings []string
-	for _, i := range imp.Implementations {
+	for _, i := range imps {
 		itemStrings = append(itemStrings, fmt.Sprint(i))
 	}
 	sort.Strings(itemStrings)
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index c53a1b8..2a1033e 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -436,14 +436,14 @@
 	}
 }
 
-func (r *runner) Implementation(t *testing.T, spn span.Span, m tests.Implementations) {
-	sm, err := r.data.Mapper(m.Src.URI())
+func (r *runner) Implementation(t *testing.T, spn span.Span, impls []span.Span) {
+	sm, err := r.data.Mapper(spn.URI())
 	if err != nil {
 		t.Fatal(err)
 	}
-	loc, err := sm.Location(m.Src)
+	loc, err := sm.Location(spn)
 	if err != nil {
-		t.Fatalf("failed for %v: %v", m.Src, err)
+		t.Fatalf("failed for %v: %v", spn, err)
 	}
 	tdpp := protocol.TextDocumentPositionParams{
 		TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
@@ -455,10 +455,10 @@
 	}
 	locs, err = r.server.Implementation(r.ctx, params)
 	if err != nil {
-		t.Fatalf("failed for %v: %v", m.Src, err)
+		t.Fatalf("failed for %v: %v", spn, err)
 	}
-	if len(locs) != len(m.Implementations) {
-		t.Fatalf("got %d locations for implementation, expected %d", len(locs), len(m.Implementations))
+	if len(locs) != len(impls) {
+		t.Fatalf("got %d locations for implementation, expected %d", len(locs), len(impls))
 	}
 
 	var results []span.Span
@@ -478,12 +478,12 @@
 	sort.SliceStable(results, func(i, j int) bool {
 		return span.Compare(results[i], results[j]) == -1
 	})
-	sort.SliceStable(m.Implementations, func(i, j int) bool {
-		return span.Compare(m.Implementations[i], m.Implementations[j]) == -1
+	sort.SliceStable(impls, func(i, j int) bool {
+		return span.Compare(impls[i], impls[j]) == -1
 	})
 	for i := range results {
-		if results[i] != m.Implementations[i] {
-			t.Errorf("for %dth implementation of %v got %v want %v", i, m.Src, results[i], m.Implementations[i])
+		if results[i] != impls[i] {
+			t.Errorf("for %dth implementation of %v got %v want %v", i, spn, results[i], impls[i])
 		}
 	}
 }
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index de1408d..bdb3c66 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -548,31 +548,31 @@
 	}
 }
 
-func (r *runner) Implementation(t *testing.T, spn span.Span, m tests.Implementations) {
+func (r *runner) Implementation(t *testing.T, spn span.Span, impls []span.Span) {
 	ctx := r.ctx
-	f, err := r.view.GetFile(ctx, m.Src.URI())
+	f, err := r.view.GetFile(ctx, spn.URI())
 	if err != nil {
-		t.Fatalf("failed for %v: %v", m.Src, err)
+		t.Fatalf("failed for %v: %v", spn, err)
 	}
-	sm, err := r.data.Mapper(m.Src.URI())
+	sm, err := r.data.Mapper(spn.URI())
 	if err != nil {
 		t.Fatal(err)
 	}
-	loc, err := sm.Location(m.Src)
+	loc, err := sm.Location(spn)
 	if err != nil {
-		t.Fatalf("failed for %v: %v", m.Src, err)
+		t.Fatalf("failed for %v: %v", spn, err)
 	}
 	ident, err := source.Identifier(ctx, r.view.Snapshot(), f, loc.Range.Start)
 	if err != nil {
-		t.Fatalf("failed for %v: %v", m.Src, err)
+		t.Fatalf("failed for %v: %v", spn, err)
 	}
 	var locs []protocol.Location
 	locs, err = ident.Implementation(r.ctx)
 	if err != nil {
-		t.Fatalf("failed for %v: %v", m.Src, err)
+		t.Fatalf("failed for %v: %v", spn, err)
 	}
-	if len(locs) != len(m.Implementations) {
-		t.Fatalf("got %d locations for implementation, expected %d", len(locs), len(m.Implementations))
+	if len(locs) != len(impls) {
+		t.Fatalf("got %d locations for implementation, expected %d", len(locs), len(impls))
 	}
 	var results []span.Span
 	for i := range locs {
@@ -591,12 +591,12 @@
 	sort.SliceStable(results, func(i, j int) bool {
 		return span.Compare(results[i], results[j]) == -1
 	})
-	sort.SliceStable(m.Implementations, func(i, j int) bool {
-		return span.Compare(m.Implementations[i], m.Implementations[j]) == -1
+	sort.SliceStable(impls, func(i, j int) bool {
+		return span.Compare(impls[i], impls[j]) == -1
 	})
 	for i := range results {
-		if results[i] != m.Implementations[i] {
-			t.Errorf("for %dth implementation of %v got %v want %v", i, m.Src, results[i], m.Implementations[i])
+		if results[i] != impls[i] {
+			t.Errorf("for %dth implementation of %v got %v want %v", i, spn, results[i], impls[i])
 		}
 	}
 }
diff --git a/internal/lsp/testdata/implementation/implementation.go b/internal/lsp/testdata/implementation/implementation.go
index b4a98cc..c964b15 100644
--- a/internal/lsp/testdata/implementation/implementation.go
+++ b/internal/lsp/testdata/implementation/implementation.go
@@ -13,11 +13,11 @@
 }
 
 type ImpI interface { //@ImpI
-	Laugh() //@mark(LaughI, "Laugh"),implementations("augh", LaughP),implementations("augh", OtherLaughP),implementations("augh", LaughS),implementations("augh", LaughL),implementations("augh", OtherLaughI),implementations("augh", OtherLaughS)
+	Laugh() //@mark(LaughI, "Laugh"),implementations("Laugh", LaughP, OtherLaughP, LaughS, LaughL, OtherLaughI, OtherLaughS)
 }
 
-type Laugher interface { //@Laugher,implementations("augher", ImpP),implementations("augher", OtherImpP),implementations("augher", ImpI),implementations("augher", ImpS),implementations("augher", OtherImpI),implementations("augher", OtherImpS),
-	Laugh() //@mark(LaughL, "Laugh"),implementations("augh", LaughP),implementations("augh", OtherLaughP),implementations("augh", LaughI),implementations("augh", LaughS),implementations("augh", OtherLaughI),implementations("augh", OtherLaughS)
+type Laugher interface { //@implementations("Laugher", ImpP, OtherImpP, ImpI, ImpS, OtherImpI, OtherImpS)
+	Laugh() //@mark(LaughL, "Laugh"),implementations("Laugh", LaughP, OtherLaughP, LaughI, LaughS, OtherLaughI, OtherLaughS)
 }
 
 type Foo struct {
diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden
index ec01935..19f615c 100644
--- a/internal/lsp/testdata/summary.txt.golden
+++ b/internal/lsp/testdata/summary.txt.golden
@@ -20,4 +20,5 @@
 SymbolsCount = 1
 SignaturesCount = 22
 LinksCount = 6
+ImplementationsCount = 4
 
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 2b3e25b..e6e9804 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -53,7 +53,7 @@
 type Imports []span.Span
 type SuggestedFixes []span.Span
 type Definitions map[span.Span]Definition
-type Implementationses map[span.Span]Implementations
+type Implementations map[span.Span][]span.Span
 type Highlights map[span.Span][]span.Span
 type References map[span.Span][]span.Span
 type Renames map[span.Span]string
@@ -80,7 +80,7 @@
 	Imports                  Imports
 	SuggestedFixes           SuggestedFixes
 	Definitions              Definitions
-	Implementationses        Implementationses
+	Implementations          Implementations
 	Highlights               Highlights
 	References               References
 	Renames                  Renames
@@ -113,7 +113,7 @@
 	Import(*testing.T, span.Span)
 	SuggestedFix(*testing.T, span.Span)
 	Definition(*testing.T, span.Span, Definition)
-	Implementation(*testing.T, span.Span, Implementations)
+	Implementation(*testing.T, span.Span, []span.Span)
 	Highlight(*testing.T, span.Span, []span.Span)
 	References(*testing.T, span.Span, []span.Span)
 	Rename(*testing.T, span.Span, string)
@@ -130,11 +130,6 @@
 	Src, Def  span.Span
 }
 
-type Implementations struct {
-	Src             span.Span
-	Implementations []span.Span
-}
-
 type CompletionTestType int
 
 const (
@@ -214,7 +209,7 @@
 		RankCompletions:          make(RankCompletions),
 		CaseSensitiveCompletions: make(CaseSensitiveCompletions),
 		Definitions:              make(Definitions),
-		Implementationses:        make(Implementationses),
+		Implementations:          make(Implementations),
 		Highlights:               make(Highlights),
 		References:               make(References),
 		Renames:                  make(Renames),
@@ -478,7 +473,7 @@
 
 	t.Run("Implementation", func(t *testing.T) {
 		t.Helper()
-		for spn, m := range data.Implementationses {
+		for spn, m := range data.Implementations {
 			t.Run(spanName(spn), func(t *testing.T) {
 				t.Helper()
 				tests.Implementation(t, spn, m)
@@ -624,6 +619,7 @@
 	fmt.Fprintf(buf, "SymbolsCount = %v\n", len(data.Symbols))
 	fmt.Fprintf(buf, "SignaturesCount = %v\n", len(data.Signatures))
 	fmt.Fprintf(buf, "LinksCount = %v\n", linksCount)
+	fmt.Fprintf(buf, "ImplementationsCount = %v\n", len(data.Implementations))
 
 	want := string(data.Golden("summary", "summary.txt", func() ([]byte, error) {
 		return buf.Bytes(), nil
@@ -804,12 +800,8 @@
 	}
 }
 
-func (data *Data) collectImplementations(src, target span.Span) {
-	// Add target to the list of expected implementations for src
-	imps := data.Implementationses[src]
-	imps.Src = src // Src is already set if imps already exists, but then we're setting it to the same thing.
-	imps.Implementations = append(imps.Implementations, target)
-	data.Implementationses[src] = imps
+func (data *Data) collectImplementations(src span.Span, targets []span.Span) {
+	data.Implementations[src] = targets
 }
 
 func (data *Data) collectHoverDefinitions(src, target span.Span) {