@@ -34,7 +34,6 @@ import (
34
34
"golang.org/x/tools/gopls/internal/lsp/source"
35
35
"golang.org/x/tools/gopls/internal/lsp/tests"
36
36
"golang.org/x/tools/gopls/internal/lsp/tests/compare"
37
- "golang.org/x/tools/internal/diff"
38
37
"golang.org/x/tools/internal/jsonrpc2"
39
38
"golang.org/x/tools/internal/jsonrpc2/servertest"
40
39
"golang.org/x/tools/internal/testenv"
@@ -130,6 +129,10 @@ var update = flag.Bool("update", false, "if set, update test data during marker
130
129
// src location, and checks that the result is the dst location, with hover
131
130
// content matching "hover.md" in the golden data g.
132
131
//
132
+ // - implementations(src location, want ...location): makes a
133
+ // textDocument/implementation query at the src location and
134
+ // checks that the resulting set of locations matches want.
135
+ //
133
136
// - loc(name, location): specifies the name for a location in the source. These
134
137
// locations may be referenced by other markers.
135
138
//
@@ -258,7 +261,6 @@ var update = flag.Bool("update", false, "if set, update test data during marker
258
261
// - FunctionExtractions
259
262
// - MethodExtractions
260
263
// - Definitions
261
- // - Implementations
262
264
// - Highlights
263
265
// - Renames
264
266
// - PrepareRenames
@@ -428,9 +430,7 @@ func (mark marker) execute() {
428
430
if i < len (fn .converters ) {
429
431
convert = fn .converters [i ]
430
432
} else if ! fn .variadic {
431
- mark .errorf ("got %d arguments to %s, expect %d" ,
432
- len (mark .note .Args ), mark .note .Name , len (fn .converters ))
433
- return
433
+ goto arity // too many args
434
434
}
435
435
436
436
// Special handling for the blank identifier: treat it as the zero value.
@@ -447,8 +447,16 @@ func (mark marker) execute() {
447
447
}
448
448
args = append (args , reflect .ValueOf (out ))
449
449
}
450
+ if len (args ) < len (fn .converters ) {
451
+ goto arity // too few args
452
+ }
450
453
451
454
fn .fn .Call (args )
455
+ return
456
+
457
+ arity:
458
+ mark .errorf ("got %d arguments to %s, want %d" ,
459
+ len (mark .note .Args ), mark .note .Name , len (fn .converters ))
452
460
}
453
461
454
462
// Supported marker functions.
@@ -459,15 +467,16 @@ func (mark marker) execute() {
459
467
// Marker funcs should not mutate the test environment (e.g. via opening files
460
468
// or applying edits in the editor).
461
469
var markerFuncs = map [string ]markerFunc {
462
- "complete" : makeMarkerFunc (completeMarker ),
463
- "def" : makeMarkerFunc (defMarker ),
464
- "diag" : makeMarkerFunc (diagMarker ),
465
- "hover" : makeMarkerFunc (hoverMarker ),
466
- "loc" : makeMarkerFunc (locMarker ),
467
- "rename" : makeMarkerFunc (renameMarker ),
468
- "renameerr" : makeMarkerFunc (renameErrMarker ),
469
- "suggestedfix" : makeMarkerFunc (suggestedfixMarker ),
470
- "refs" : makeMarkerFunc (refsMarker ),
470
+ "complete" : makeMarkerFunc (completeMarker ),
471
+ "def" : makeMarkerFunc (defMarker ),
472
+ "diag" : makeMarkerFunc (diagMarker ),
473
+ "hover" : makeMarkerFunc (hoverMarker ),
474
+ "implementation" : makeMarkerFunc (implementationMarker ),
475
+ "loc" : makeMarkerFunc (locMarker ),
476
+ "rename" : makeMarkerFunc (renameMarker ),
477
+ "renameerr" : makeMarkerFunc (renameErrMarker ),
478
+ "suggestedfix" : makeMarkerFunc (suggestedfixMarker ),
479
+ "refs" : makeMarkerFunc (refsMarker ),
471
480
}
472
481
473
482
// markerTest holds all the test data extracted from a test txtar archive.
@@ -1354,37 +1363,17 @@ func suggestedfix(env *Env, loc protocol.Location, diag protocol.Diagnostic, act
1354
1363
// refsMarker implements the @refs marker.
1355
1364
func refsMarker (mark marker , src protocol.Location , want ... protocol.Location ) {
1356
1365
refs := func (includeDeclaration bool , want []protocol.Location ) error {
1357
- params := & protocol.ReferenceParams {
1366
+ got , err := mark . run . env . Editor . Server . References ( mark . run . env . Ctx , & protocol.ReferenceParams {
1358
1367
TextDocumentPositionParams : protocol .LocationTextDocumentPositionParams (src ),
1359
1368
Context : protocol.ReferenceContext {
1360
1369
IncludeDeclaration : includeDeclaration ,
1361
1370
},
1362
- }
1363
-
1364
- got , err := mark .run .env .Editor .Server .References (mark .run .env .Ctx , params )
1371
+ })
1365
1372
if err != nil {
1366
1373
return err
1367
1374
}
1368
1375
1369
- // Compare the sets of locations.
1370
- toString := func (locs []protocol.Location ) string {
1371
- // TODO(adonovan): use generic JoinValues(locs, fmtLoc).
1372
- strs := make ([]string , len (locs ))
1373
- for i , loc := range locs {
1374
- strs [i ] = mark .run .fmtLoc (loc )
1375
- }
1376
- sort .Strings (strs )
1377
- return strings .Join (strs , "\n " )
1378
- }
1379
- gotStr := toString (got )
1380
- wantStr := toString (want )
1381
- if gotStr != wantStr {
1382
- return fmt .Errorf ("incorrect references (got %d, want %d) at %s:\n %s" ,
1383
- len (got ), len (want ),
1384
- mark .run .fmtLoc (src ),
1385
- diff .Unified ("want" , "got" , wantStr , gotStr ))
1386
- }
1387
- return nil
1376
+ return compareLocations (mark , got , want )
1388
1377
}
1389
1378
1390
1379
for _ , includeDeclaration := range []bool {false , true } {
@@ -1401,3 +1390,35 @@ func refsMarker(mark marker, src protocol.Location, want ...protocol.Location) {
1401
1390
}
1402
1391
}
1403
1392
}
1393
+
1394
+ // implementationMarker implements the @implementation marker.
1395
+ func implementationMarker (mark marker , src protocol.Location , want ... protocol.Location ) {
1396
+ got , err := mark .run .env .Editor .Server .Implementation (mark .run .env .Ctx , & protocol.ImplementationParams {
1397
+ TextDocumentPositionParams : protocol .LocationTextDocumentPositionParams (src ),
1398
+ })
1399
+ if err != nil {
1400
+ mark .errorf ("implementation at %s failed: %v" , src , err )
1401
+ return
1402
+ }
1403
+ if err := compareLocations (mark , got , want ); err != nil {
1404
+ mark .errorf ("implementation: %v" , err )
1405
+ }
1406
+ }
1407
+
1408
+ // compareLocations returns an error message if got and want are not
1409
+ // the same set of locations. The marker is used only for fmtLoc.
1410
+ func compareLocations (mark marker , got , want []protocol.Location ) error {
1411
+ toStrings := func (locs []protocol.Location ) []string {
1412
+ strs := make ([]string , len (locs ))
1413
+ for i , loc := range locs {
1414
+ strs [i ] = mark .run .fmtLoc (loc )
1415
+ }
1416
+ sort .Strings (strs )
1417
+ return strs
1418
+ }
1419
+ if diff := cmp .Diff (toStrings (want ), toStrings (got )); diff != "" {
1420
+ return fmt .Errorf ("incorrect result locations: (got %d, want %d):\n %s" ,
1421
+ len (got ), len (want ), diff )
1422
+ }
1423
+ return nil
1424
+ }
0 commit comments