1diff -urN a/gopls/api-diff/api_diff.go b/gopls/api-diff/api_diff.go 2--- a/gopls/api-diff/api_diff.go 2000-01-01 00:00:00.000000000 -0000 3+++ b/gopls/api-diff/api_diff.go 1970-01-01 00:00:00.000000000 +0000 4@@ -1,89 +0,0 @@ 5-// Copyright 2021 The Go Authors. All rights reserved. 6-// Use of this source code is governed by a BSD-style 7-// license that can be found in the LICENSE file. 8- 9-//go:build go1.18 10-// +build go1.18 11- 12-package main 13- 14-import ( 15- "bytes" 16- "context" 17- "encoding/json" 18- "flag" 19- "fmt" 20- "log" 21- "os" 22- "os/exec" 23- 24- "github.com/google/go-cmp/cmp" 25- "golang.org/x/tools/gopls/internal/lsp/source" 26-) 27- 28-const usage = `api-diff <previous version> [<current version>] 29- 30-Compare the API of two gopls versions. If the second argument is provided, it 31-will be used as the new version to compare against. Otherwise, compare against 32-the current API. 33-` 34- 35-func main() { 36- flag.Parse() 37- 38- if flag.NArg() < 1 || flag.NArg() > 2 { 39- fmt.Fprint(os.Stderr, usage) 40- os.Exit(2) 41- } 42- 43- oldVer := flag.Arg(0) 44- newVer := "" 45- if flag.NArg() == 2 { 46- newVer = flag.Arg(1) 47- } 48- 49- apiDiff, err := diffAPI(oldVer, newVer) 50- if err != nil { 51- log.Fatal(err) 52- } 53- fmt.Println("\n" + apiDiff) 54-} 55- 56-func diffAPI(oldVer, newVer string) (string, error) { 57- ctx := context.Background() 58- previousAPI, err := loadAPI(ctx, oldVer) 59- if err != nil { 60- return "", fmt.Errorf("loading %s: %v", oldVer, err) 61- } 62- var currentAPI *source.APIJSON 63- if newVer == "" { 64- currentAPI = source.GeneratedAPIJSON 65- } else { 66- var err error 67- currentAPI, err = loadAPI(ctx, newVer) 68- if err != nil { 69- return "", fmt.Errorf("loading %s: %v", newVer, err) 70- } 71- } 72- 73- return cmp.Diff(previousAPI, currentAPI), nil 74-} 75- 76-func loadAPI(ctx context.Context, version string) (*source.APIJSON, error) { 77- ver := fmt.Sprintf("golang.org/x/tools/gopls@%s", version) 78- cmd := exec.Command("go", "run", ver, "api-json") 79- 80- stdout := &bytes.Buffer{} 81- stderr := &bytes.Buffer{} 82- cmd.Stdout = stdout 83- cmd.Stderr = stderr 84- 85- if err := cmd.Run(); err != nil { 86- return nil, fmt.Errorf("go run failed: %v; stderr:\n%s", err, stderr) 87- } 88- apiJson := &source.APIJSON{} 89- if err := json.Unmarshal(stdout.Bytes(), apiJson); err != nil { 90- return nil, fmt.Errorf("unmarshal: %v", err) 91- } 92- return apiJson, nil 93-} 94diff -urN a/gopls/doc/advanced.md b/gopls/doc/advanced.md 95--- a/gopls/doc/advanced.md 2000-01-01 00:00:00.000000000 -0000 96+++ b/gopls/doc/advanced.md 1970-01-01 00:00:00.000000000 +0000 97@@ -1,69 +0,0 @@ 98-# Advanced topics 99- 100-This documentation is for advanced `gopls` users, who may want to test 101-unreleased versions or try out special features. 102- 103-## Installing unreleased versions 104- 105-To get a specific version of `gopls` (for example, to test a prerelease 106-version), run: 107- 108-```sh 109-GO111MODULE=on go install golang.org/x/tools/gopls@vX.Y.Z 110-``` 111- 112-Where `vX.Y.Z` is the desired version. 113- 114-### Unstable versions 115- 116-To update `gopls` to the latest **unstable** version, use the following 117-commands. 118- 119-```sh 120-# Create an empty go.mod file, only for tracking requirements. 121-cd $(mktemp -d) 122-go mod init gopls-unstable 123- 124-# Use 'go get' to add requirements and to ensure they work together. 125-go get -d golang.org/x/tools/gopls@master golang.org/x/tools@master 126- 127-go install golang.org/x/tools/gopls 128-``` 129- 130-## Working on the Go source distribution 131- 132-If you are working on the [Go project] itself, the `go` command that `gopls` 133-invokes will have to correspond to the version of the source you are working 134-on. That is, if you have checked out the Go project to `$HOME/go`, your `go` 135-command should be the `$HOME/go/bin/go` executable that you built with 136-`make.bash` or equivalent. 137- 138-You can achieve this by adding the right version of `go` to your `PATH` 139-(`export PATH=$HOME/go/bin:$PATH` on Unix systems) or by configuring your 140-editor. 141- 142-## Working with generic code 143- 144-Gopls has support for editing generic Go code. To enable this support, you need 145-to **install gopls using Go 1.18 or later**. The easiest way to do this is by 146-[installing Go 1.18+](https://go.dev/dl) and then using this Go version to 147-install gopls: 148- 149-``` 150-$ go install golang.org/x/tools/gopls@latest 151-``` 152- 153-It is strongly recommended that you install the latest version of `gopls`, or 154-the latest **unstable** version as [described above](#installing-unreleased-versions). 155-We're still working on improving our generics support. 156- 157-The `gopls` built with these instructions understands generic code. See the 158-[generics tutorial](https://go.dev/doc/tutorial/generics) for more information 159-on how to use generics in Go! 160- 161-### Known issues 162- 163- * [`staticcheck`](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#staticcheck-bool) 164- on generic code is not supported yet. 165- 166-[Go project]: https://go.googlesource.com/go 167diff -urN a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md 168--- a/gopls/doc/analyzers.md 2000-01-01 00:00:00.000000000 -0000 169+++ b/gopls/doc/analyzers.md 1970-01-01 00:00:00.000000000 +0000 170@@ -1,762 +0,0 @@ 171-# Analyzers 172- 173-This document describes the analyzers that `gopls` uses inside the editor. 174- 175-Details about how to enable/disable these analyses can be found 176-[here](settings.md#analyses). 177- 178-<!-- BEGIN Analyzers: DO NOT MANUALLY EDIT THIS SECTION --> 179-## **asmdecl** 180- 181-report mismatches between assembly files and Go declarations 182- 183-**Enabled by default.** 184- 185-## **assign** 186- 187-check for useless assignments 188- 189-This checker reports assignments of the form x = x or a[i] = a[i]. 190-These are almost always useless, and even when they aren't they are 191-usually a mistake. 192- 193-**Enabled by default.** 194- 195-## **atomic** 196- 197-check for common mistakes using the sync/atomic package 198- 199-The atomic checker looks for assignment statements of the form: 200- 201- x = atomic.AddUint64(&x, 1) 202- 203-which are not atomic. 204- 205-**Enabled by default.** 206- 207-## **atomicalign** 208- 209-check for non-64-bits-aligned arguments to sync/atomic functions 210- 211-**Enabled by default.** 212- 213-## **bools** 214- 215-check for common mistakes involving boolean operators 216- 217-**Enabled by default.** 218- 219-## **buildtag** 220- 221-check //go:build and // +build directives 222- 223-**Enabled by default.** 224- 225-## **cgocall** 226- 227-detect some violations of the cgo pointer passing rules 228- 229-Check for invalid cgo pointer passing. 230-This looks for code that uses cgo to call C code passing values 231-whose types are almost always invalid according to the cgo pointer 232-sharing rules. 233-Specifically, it warns about attempts to pass a Go chan, map, func, 234-or slice to C, either directly, or via a pointer, array, or struct. 235- 236-**Enabled by default.** 237- 238-## **composites** 239- 240-check for unkeyed composite literals 241- 242-This analyzer reports a diagnostic for composite literals of struct 243-types imported from another package that do not use the field-keyed 244-syntax. Such literals are fragile because the addition of a new field 245-(even if unexported) to the struct will cause compilation to fail. 246- 247-As an example, 248- 249- err = &net.DNSConfigError{err} 250- 251-should be replaced by: 252- 253- err = &net.DNSConfigError{Err: err} 254- 255- 256-**Enabled by default.** 257- 258-## **copylocks** 259- 260-check for locks erroneously passed by value 261- 262-Inadvertently copying a value containing a lock, such as sync.Mutex or 263-sync.WaitGroup, may cause both copies to malfunction. Generally such 264-values should be referred to through a pointer. 265- 266-**Enabled by default.** 267- 268-## **deepequalerrors** 269- 270-check for calls of reflect.DeepEqual on error values 271- 272-The deepequalerrors checker looks for calls of the form: 273- 274- reflect.DeepEqual(err1, err2) 275- 276-where err1 and err2 are errors. Using reflect.DeepEqual to compare 277-errors is discouraged. 278- 279-**Enabled by default.** 280- 281-## **directive** 282- 283-check Go toolchain directives such as //go:debug 284- 285-This analyzer checks for problems with known Go toolchain directives 286-in all Go source files in a package directory, even those excluded by 287-//go:build constraints, and all non-Go source files too. 288- 289-For //go:debug (see https://go.dev/doc/godebug), the analyzer checks 290-that the directives are placed only in Go source files, only above the 291-package comment, and only in package main or *_test.go files. 292- 293-Support for other known directives may be added in the future. 294- 295-This analyzer does not check //go:build, which is handled by the 296-buildtag analyzer. 297- 298- 299-**Enabled by default.** 300- 301-## **embed** 302- 303-check for //go:embed directive import 304- 305-This analyzer checks that the embed package is imported when source code contains //go:embed comment directives. 306-The embed package must be imported for //go:embed directives to function.import _ "embed". 307- 308-**Enabled by default.** 309- 310-## **errorsas** 311- 312-report passing non-pointer or non-error values to errors.As 313- 314-The errorsas analysis reports calls to errors.As where the type 315-of the second argument is not a pointer to a type implementing error. 316- 317-**Enabled by default.** 318- 319-## **fieldalignment** 320- 321-find structs that would use less memory if their fields were sorted 322- 323-This analyzer find structs that can be rearranged to use less memory, and provides 324-a suggested edit with the most compact order. 325- 326-Note that there are two different diagnostics reported. One checks struct size, 327-and the other reports "pointer bytes" used. Pointer bytes is how many bytes of the 328-object that the garbage collector has to potentially scan for pointers, for example: 329- 330- struct { uint32; string } 331- 332-have 16 pointer bytes because the garbage collector has to scan up through the string's 333-inner pointer. 334- 335- struct { string; *uint32 } 336- 337-has 24 pointer bytes because it has to scan further through the *uint32. 338- 339- struct { string; uint32 } 340- 341-has 8 because it can stop immediately after the string pointer. 342- 343-Be aware that the most compact order is not always the most efficient. 344-In rare cases it may cause two variables each updated by its own goroutine 345-to occupy the same CPU cache line, inducing a form of memory contention 346-known as "false sharing" that slows down both goroutines. 347- 348- 349-**Disabled by default. Enable it by setting `"analyses": {"fieldalignment": true}`.** 350- 351-## **httpresponse** 352- 353-check for mistakes using HTTP responses 354- 355-A common mistake when using the net/http package is to defer a function 356-call to close the http.Response Body before checking the error that 357-determines whether the response is valid: 358- 359- resp, err := http.Head(url) 360- defer resp.Body.Close() 361- if err != nil { 362- log.Fatal(err) 363- } 364- // (defer statement belongs here) 365- 366-This checker helps uncover latent nil dereference bugs by reporting a 367-diagnostic for such mistakes. 368- 369-**Enabled by default.** 370- 371-## **ifaceassert** 372- 373-detect impossible interface-to-interface type assertions 374- 375-This checker flags type assertions v.(T) and corresponding type-switch cases 376-in which the static type V of v is an interface that cannot possibly implement 377-the target interface T. This occurs when V and T contain methods with the same 378-name but different signatures. Example: 379- 380- var v interface { 381- Read() 382- } 383- _ = v.(io.Reader) 384- 385-The Read method in v has a different signature than the Read method in 386-io.Reader, so this assertion cannot succeed. 387- 388- 389-**Enabled by default.** 390- 391-## **infertypeargs** 392- 393-check for unnecessary type arguments in call expressions 394- 395-Explicit type arguments may be omitted from call expressions if they can be 396-inferred from function arguments, or from other type arguments: 397- 398- func f[T any](T) {} 399- 400- func _() { 401- f[string]("foo") // string could be inferred 402- } 403- 404- 405-**Enabled by default.** 406- 407-## **loopclosure** 408- 409-check references to loop variables from within nested functions 410- 411-This analyzer reports places where a function literal references the 412-iteration variable of an enclosing loop, and the loop calls the function 413-in such a way (e.g. with go or defer) that it may outlive the loop 414-iteration and possibly observe the wrong value of the variable. 415- 416-In this example, all the deferred functions run after the loop has 417-completed, so all observe the final value of v. 418- 419- for _, v := range list { 420- defer func() { 421- use(v) // incorrect 422- }() 423- } 424- 425-One fix is to create a new variable for each iteration of the loop: 426- 427- for _, v := range list { 428- v := v // new var per iteration 429- defer func() { 430- use(v) // ok 431- }() 432- } 433- 434-The next example uses a go statement and has a similar problem. 435-In addition, it has a data race because the loop updates v 436-concurrent with the goroutines accessing it. 437- 438- for _, v := range elem { 439- go func() { 440- use(v) // incorrect, and a data race 441- }() 442- } 443- 444-A fix is the same as before. The checker also reports problems 445-in goroutines started by golang.org/x/sync/errgroup.Group. 446-A hard-to-spot variant of this form is common in parallel tests: 447- 448- func Test(t *testing.T) { 449- for _, test := range tests { 450- t.Run(test.name, func(t *testing.T) { 451- t.Parallel() 452- use(test) // incorrect, and a data race 453- }) 454- } 455- } 456- 457-The t.Parallel() call causes the rest of the function to execute 458-concurrent with the loop. 459- 460-The analyzer reports references only in the last statement, 461-as it is not deep enough to understand the effects of subsequent 462-statements that might render the reference benign. 463-("Last statement" is defined recursively in compound 464-statements such as if, switch, and select.) 465- 466-See: https://golang.org/doc/go_faq.html#closures_and_goroutines 467- 468-**Enabled by default.** 469- 470-## **lostcancel** 471- 472-check cancel func returned by context.WithCancel is called 473- 474-The cancellation function returned by context.WithCancel, WithTimeout, 475-and WithDeadline must be called or the new context will remain live 476-until its parent context is cancelled. 477-(The background context is never cancelled.) 478- 479-**Enabled by default.** 480- 481-## **nilfunc** 482- 483-check for useless comparisons between functions and nil 484- 485-A useless comparison is one like f == nil as opposed to f() == nil. 486- 487-**Enabled by default.** 488- 489-## **nilness** 490- 491-check for redundant or impossible nil comparisons 492- 493-The nilness checker inspects the control-flow graph of each function in 494-a package and reports nil pointer dereferences, degenerate nil 495-pointers, and panics with nil values. A degenerate comparison is of the form 496-x==nil or x!=nil where x is statically known to be nil or non-nil. These are 497-often a mistake, especially in control flow related to errors. Panics with nil 498-values are checked because they are not detectable by 499- 500- if r := recover(); r != nil { 501- 502-This check reports conditions such as: 503- 504- if f == nil { // impossible condition (f is a function) 505- } 506- 507-and: 508- 509- p := &v 510- ... 511- if p != nil { // tautological condition 512- } 513- 514-and: 515- 516- if p == nil { 517- print(*p) // nil dereference 518- } 519- 520-and: 521- 522- if p == nil { 523- panic(p) 524- } 525- 526- 527-**Disabled by default. Enable it by setting `"analyses": {"nilness": true}`.** 528- 529-## **printf** 530- 531-check consistency of Printf format strings and arguments 532- 533-The check applies to known functions (for example, those in package fmt) 534-as well as any detected wrappers of known functions. 535- 536-A function that wants to avail itself of printf checking but is not 537-found by this analyzer's heuristics (for example, due to use of 538-dynamic calls) can insert a bogus call: 539- 540- if false { 541- _ = fmt.Sprintf(format, args...) // enable printf checking 542- } 543- 544-The -funcs flag specifies a comma-separated list of names of additional 545-known formatting functions or methods. If the name contains a period, 546-it must denote a specific function using one of the following forms: 547- 548- dir/pkg.Function 549- dir/pkg.Type.Method 550- (*dir/pkg.Type).Method 551- 552-Otherwise the name is interpreted as a case-insensitive unqualified 553-identifier such as "errorf". Either way, if a listed name ends in f, the 554-function is assumed to be Printf-like, taking a format string before the 555-argument list. Otherwise it is assumed to be Print-like, taking a list 556-of arguments with no format string. 557- 558- 559-**Enabled by default.** 560- 561-## **shadow** 562- 563-check for possible unintended shadowing of variables 564- 565-This analyzer check for shadowed variables. 566-A shadowed variable is a variable declared in an inner scope 567-with the same name and type as a variable in an outer scope, 568-and where the outer variable is mentioned after the inner one 569-is declared. 570- 571-(This definition can be refined; the module generates too many 572-false positives and is not yet enabled by default.) 573- 574-For example: 575- 576- func BadRead(f *os.File, buf []byte) error { 577- var err error 578- for { 579- n, err := f.Read(buf) // shadows the function variable 'err' 580- if err != nil { 581- break // causes return of wrong value 582- } 583- foo(buf) 584- } 585- return err 586- } 587- 588- 589-**Disabled by default. Enable it by setting `"analyses": {"shadow": true}`.** 590- 591-## **shift** 592- 593-check for shifts that equal or exceed the width of the integer 594- 595-**Enabled by default.** 596- 597-## **simplifycompositelit** 598- 599-check for composite literal simplifications 600- 601-An array, slice, or map composite literal of the form: 602- []T{T{}, T{}} 603-will be simplified to: 604- []T{{}, {}} 605- 606-This is one of the simplifications that "gofmt -s" applies. 607- 608-**Enabled by default.** 609- 610-## **simplifyrange** 611- 612-check for range statement simplifications 613- 614-A range of the form: 615- for x, _ = range v {...} 616-will be simplified to: 617- for x = range v {...} 618- 619-A range of the form: 620- for _ = range v {...} 621-will be simplified to: 622- for range v {...} 623- 624-This is one of the simplifications that "gofmt -s" applies. 625- 626-**Enabled by default.** 627- 628-## **simplifyslice** 629- 630-check for slice simplifications 631- 632-A slice expression of the form: 633- s[a:len(s)] 634-will be simplified to: 635- s[a:] 636- 637-This is one of the simplifications that "gofmt -s" applies. 638- 639-**Enabled by default.** 640- 641-## **sortslice** 642- 643-check the argument type of sort.Slice 644- 645-sort.Slice requires an argument of a slice type. Check that 646-the interface{} value passed to sort.Slice is actually a slice. 647- 648-**Enabled by default.** 649- 650-## **stdmethods** 651- 652-check signature of methods of well-known interfaces 653- 654-Sometimes a type may be intended to satisfy an interface but may fail to 655-do so because of a mistake in its method signature. 656-For example, the result of this WriteTo method should be (int64, error), 657-not error, to satisfy io.WriterTo: 658- 659- type myWriterTo struct{...} 660- func (myWriterTo) WriteTo(w io.Writer) error { ... } 661- 662-This check ensures that each method whose name matches one of several 663-well-known interface methods from the standard library has the correct 664-signature for that interface. 665- 666-Checked method names include: 667- Format GobEncode GobDecode MarshalJSON MarshalXML 668- Peek ReadByte ReadFrom ReadRune Scan Seek 669- UnmarshalJSON UnreadByte UnreadRune WriteByte 670- WriteTo 671- 672- 673-**Enabled by default.** 674- 675-## **stringintconv** 676- 677-check for string(int) conversions 678- 679-This checker flags conversions of the form string(x) where x is an integer 680-(but not byte or rune) type. Such conversions are discouraged because they 681-return the UTF-8 representation of the Unicode code point x, and not a decimal 682-string representation of x as one might expect. Furthermore, if x denotes an 683-invalid code point, the conversion cannot be statically rejected. 684- 685-For conversions that intend on using the code point, consider replacing them 686-with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the 687-string representation of the value in the desired base. 688- 689- 690-**Enabled by default.** 691- 692-## **structtag** 693- 694-check that struct field tags conform to reflect.StructTag.Get 695- 696-Also report certain struct tags (json, xml) used with unexported fields. 697- 698-**Enabled by default.** 699- 700-## **testinggoroutine** 701- 702-report calls to (*testing.T).Fatal from goroutines started by a test. 703- 704-Functions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and 705-Skip{,f,Now} methods of *testing.T, must be called from the test goroutine itself. 706-This checker detects calls to these functions that occur within a goroutine 707-started by the test. For example: 708- 709-func TestFoo(t *testing.T) { 710- go func() { 711- t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine 712- }() 713-} 714- 715- 716-**Enabled by default.** 717- 718-## **tests** 719- 720-check for common mistaken usages of tests and examples 721- 722-The tests checker walks Test, Benchmark and Example functions checking 723-malformed names, wrong signatures and examples documenting non-existent 724-identifiers. 725- 726-Please see the documentation for package testing in golang.org/pkg/testing 727-for the conventions that are enforced for Tests, Benchmarks, and Examples. 728- 729-**Enabled by default.** 730- 731-## **timeformat** 732- 733-check for calls of (time.Time).Format or time.Parse with 2006-02-01 734- 735-The timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm) 736-format. Internationally, "yyyy-dd-mm" does not occur in common calendar date 737-standards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended. 738- 739- 740-**Enabled by default.** 741- 742-## **unmarshal** 743- 744-report passing non-pointer or non-interface values to unmarshal 745- 746-The unmarshal analysis reports calls to functions such as json.Unmarshal 747-in which the argument type is not a pointer or an interface. 748- 749-**Enabled by default.** 750- 751-## **unreachable** 752- 753-check for unreachable code 754- 755-The unreachable analyzer finds statements that execution can never reach 756-because they are preceded by an return statement, a call to panic, an 757-infinite loop, or similar constructs. 758- 759-**Enabled by default.** 760- 761-## **unsafeptr** 762- 763-check for invalid conversions of uintptr to unsafe.Pointer 764- 765-The unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer 766-to convert integers to pointers. A conversion from uintptr to 767-unsafe.Pointer is invalid if it implies that there is a uintptr-typed 768-word in memory that holds a pointer value, because that word will be 769-invisible to stack copying and to the garbage collector. 770- 771-**Enabled by default.** 772- 773-## **unusedparams** 774- 775-check for unused parameters of functions 776- 777-The unusedparams analyzer checks functions to see if there are 778-any parameters that are not being used. 779- 780-To reduce false positives it ignores: 781-- methods 782-- parameters that do not have a name or are underscored 783-- functions in test files 784-- functions with empty bodies or those with just a return stmt 785- 786-**Disabled by default. Enable it by setting `"analyses": {"unusedparams": true}`.** 787- 788-## **unusedresult** 789- 790-check for unused results of calls to some functions 791- 792-Some functions like fmt.Errorf return a result and have no side effects, 793-so it is always a mistake to discard the result. This analyzer reports 794-calls to certain functions in which the result of the call is ignored. 795- 796-The set of functions may be controlled using flags. 797- 798-**Enabled by default.** 799- 800-## **unusedwrite** 801- 802-checks for unused writes 803- 804-The analyzer reports instances of writes to struct fields and 805-arrays that are never read. Specifically, when a struct object 806-or an array is copied, its elements are copied implicitly by 807-the compiler, and any element write to this copy does nothing 808-with the original object. 809- 810-For example: 811- 812- type T struct { x int } 813- func f(input []T) { 814- for i, v := range input { // v is a copy 815- v.x = i // unused write to field x 816- } 817- } 818- 819-Another example is about non-pointer receiver: 820- 821- type T struct { x int } 822- func (t T) f() { // t is a copy 823- t.x = i // unused write to field x 824- } 825- 826- 827-**Disabled by default. Enable it by setting `"analyses": {"unusedwrite": true}`.** 828- 829-## **useany** 830- 831-check for constraints that could be simplified to "any" 832- 833-**Disabled by default. Enable it by setting `"analyses": {"useany": true}`.** 834- 835-## **fillreturns** 836- 837-suggest fixes for errors due to an incorrect number of return values 838- 839-This checker provides suggested fixes for type errors of the 840-type "wrong number of return values (want %d, got %d)". For example: 841- func m() (int, string, *bool, error) { 842- return 843- } 844-will turn into 845- func m() (int, string, *bool, error) { 846- return 0, "", nil, nil 847- } 848- 849-This functionality is similar to https://github.com/sqs/goreturns. 850- 851- 852-**Enabled by default.** 853- 854-## **nonewvars** 855- 856-suggested fixes for "no new vars on left side of :=" 857- 858-This checker provides suggested fixes for type errors of the 859-type "no new vars on left side of :=". For example: 860- z := 1 861- z := 2 862-will turn into 863- z := 1 864- z = 2 865- 866- 867-**Enabled by default.** 868- 869-## **noresultvalues** 870- 871-suggested fixes for unexpected return values 872- 873-This checker provides suggested fixes for type errors of the 874-type "no result values expected" or "too many return values". 875-For example: 876- func z() { return nil } 877-will turn into 878- func z() { return } 879- 880- 881-**Enabled by default.** 882- 883-## **undeclaredname** 884- 885-suggested fixes for "undeclared name: <>" 886- 887-This checker provides suggested fixes for type errors of the 888-type "undeclared name: <>". It will either insert a new statement, 889-such as: 890- 891-"<> := " 892- 893-or a new function declaration, such as: 894- 895-func <>(inferred parameters) { 896- panic("implement me!") 897-} 898- 899- 900-**Enabled by default.** 901- 902-## **unusedvariable** 903- 904-check for unused variables 905- 906-The unusedvariable analyzer suggests fixes for unused variables errors. 907- 908- 909-**Disabled by default. Enable it by setting `"analyses": {"unusedvariable": true}`.** 910- 911-## **fillstruct** 912- 913-note incomplete struct initializations 914- 915-This analyzer provides diagnostics for any struct literals that do not have 916-any fields initialized. Because the suggested fix for this analysis is 917-expensive to compute, callers should compute it separately, using the 918-SuggestedFix function below. 919- 920- 921-**Enabled by default.** 922- 923-## **stubmethods** 924- 925-stub methods analyzer 926- 927-This analyzer generates method stubs for concrete types 928-in order to implement a target interface 929- 930-**Enabled by default.** 931- 932-<!-- END Analyzers: DO NOT MANUALLY EDIT THIS SECTION --> 933diff -urN a/gopls/doc/command-line.md b/gopls/doc/command-line.md 934--- a/gopls/doc/command-line.md 2000-01-01 00:00:00.000000000 -0000 935+++ b/gopls/doc/command-line.md 1970-01-01 00:00:00.000000000 +0000 936@@ -1,15 +0,0 @@ 937-# Command line 938- 939-**Note: The `gopls` command-line is still experimental and subject to change at any point.** 940- 941-`gopls` exposes some (but not all) features on the command-line. This can be useful for debugging `gopls` itself. 942- 943-<!--TODO(rstambler): Generate this file.--> 944- 945-Learn about available commands and flags by running `gopls help`. 946- 947-Much of the functionality of `gopls` is available through a command line interface. 948- 949-There are two main reasons for this. The first is that we do not want users to rely on separate command line tools when they wish to do some task outside of an editor. The second is that the CLI assists in debugging. It is easier to reproduce behavior via single command. 950- 951-It is not a goal of `gopls` to be a high performance command line tool. Its command line is intended for single file/package user interaction speeds, not bulk processing. 952diff -urN a/gopls/doc/commands.md b/gopls/doc/commands.md 953--- a/gopls/doc/commands.md 2000-01-01 00:00:00.000000000 -0000 954+++ b/gopls/doc/commands.md 1970-01-01 00:00:00.000000000 +0000 955@@ -1,467 +0,0 @@ 956-# Commands 957- 958-This document describes the LSP-level commands supported by `gopls`. They cannot be invoked directly by users, and all the details are subject to change, so nobody should rely on this information. 959- 960-<!-- BEGIN Commands: DO NOT MANUALLY EDIT THIS SECTION --> 961-### **Add a dependency** 962-Identifier: `gopls.add_dependency` 963- 964-Adds a dependency to the go.mod file for a module. 965- 966-Args: 967- 968-``` 969-{ 970- // The go.mod file URI. 971- "URI": string, 972- // Additional args to pass to the go command. 973- "GoCmdArgs": []string, 974- // Whether to add a require directive. 975- "AddRequire": bool, 976-} 977-``` 978- 979-### **Add an import** 980-Identifier: `gopls.add_import` 981- 982-Ask the server to add an import path to a given Go file. The method will 983-call applyEdit on the client so that clients don't have to apply the edit 984-themselves. 985- 986-Args: 987- 988-``` 989-{ 990- // ImportPath is the target import path that should 991- // be added to the URI file 992- "ImportPath": string, 993- // URI is the file that the ImportPath should be 994- // added to 995- "URI": string, 996-} 997-``` 998- 999-### **Apply a fix** 1000-Identifier: `gopls.apply_fix` 1001- 1002-Applies a fix to a region of source code. 1003- 1004-Args: 1005- 1006-``` 1007-{ 1008- // The fix to apply. 1009- "Fix": string, 1010- // The file URI for the document to fix. 1011- "URI": string, 1012- // The document range to scan for fixes. 1013- "Range": { 1014- "start": { 1015- "line": uint32, 1016- "character": uint32, 1017- }, 1018- "end": { 1019- "line": uint32, 1020- "character": uint32, 1021- }, 1022- }, 1023-} 1024-``` 1025- 1026-### **Check for upgrades** 1027-Identifier: `gopls.check_upgrades` 1028- 1029-Checks for module upgrades. 1030- 1031-Args: 1032- 1033-``` 1034-{ 1035- // The go.mod file URI. 1036- "URI": string, 1037- // The modules to check. 1038- "Modules": []string, 1039-} 1040-``` 1041- 1042-### **Run go mod edit -go=version** 1043-Identifier: `gopls.edit_go_directive` 1044- 1045-Runs `go mod edit -go=version` for a module. 1046- 1047-Args: 1048- 1049-``` 1050-{ 1051- // Any document URI within the relevant module. 1052- "URI": string, 1053- // The version to pass to `go mod edit -go`. 1054- "Version": string, 1055-} 1056-``` 1057- 1058-### **Get known vulncheck result** 1059-Identifier: `gopls.fetch_vulncheck_result` 1060- 1061-Fetch the result of latest vulnerability check (`govulncheck`). 1062- 1063-Args: 1064- 1065-``` 1066-{ 1067- // The file URI. 1068- "URI": string, 1069-} 1070-``` 1071- 1072-Result: 1073- 1074-``` 1075-map[golang.org/x/tools/gopls/internal/lsp/protocol.DocumentURI]*golang.org/x/tools/gopls/internal/govulncheck.Result 1076-``` 1077- 1078-### **Toggle gc_details** 1079-Identifier: `gopls.gc_details` 1080- 1081-Toggle the calculation of gc annotations. 1082- 1083-Args: 1084- 1085-``` 1086-string 1087-``` 1088- 1089-### **Run go generate** 1090-Identifier: `gopls.generate` 1091- 1092-Runs `go generate` for a given directory. 1093- 1094-Args: 1095- 1096-``` 1097-{ 1098- // URI for the directory to generate. 1099- "Dir": string, 1100- // Whether to generate recursively (go generate ./...) 1101- "Recursive": bool, 1102-} 1103-``` 1104- 1105-### **go get a package** 1106-Identifier: `gopls.go_get_package` 1107- 1108-Runs `go get` to fetch a package. 1109- 1110-Args: 1111- 1112-``` 1113-{ 1114- // Any document URI within the relevant module. 1115- "URI": string, 1116- // The package to go get. 1117- "Pkg": string, 1118- "AddRequire": bool, 1119-} 1120-``` 1121- 1122-### **List imports of a file and its package** 1123-Identifier: `gopls.list_imports` 1124- 1125-Retrieve a list of imports in the given Go file, and the package it 1126-belongs to. 1127- 1128-Args: 1129- 1130-``` 1131-{ 1132- // The file URI. 1133- "URI": string, 1134-} 1135-``` 1136- 1137-Result: 1138- 1139-``` 1140-{ 1141- // Imports is a list of imports in the requested file. 1142- "Imports": []{ 1143- "Path": string, 1144- "Name": string, 1145- }, 1146- // PackageImports is a list of all imports in the requested file's package. 1147- "PackageImports": []{ 1148- "Path": string, 1149- }, 1150-} 1151-``` 1152- 1153-### **List known packages** 1154-Identifier: `gopls.list_known_packages` 1155- 1156-Retrieve a list of packages that are importable from the given URI. 1157- 1158-Args: 1159- 1160-``` 1161-{ 1162- // The file URI. 1163- "URI": string, 1164-} 1165-``` 1166- 1167-Result: 1168- 1169-``` 1170-{ 1171- // Packages is a list of packages relative 1172- // to the URIArg passed by the command request. 1173- // In other words, it omits paths that are already 1174- // imported or cannot be imported due to compiler 1175- // restrictions. 1176- "Packages": []string, 1177-} 1178-``` 1179- 1180-### **fetch memory statistics** 1181-Identifier: `gopls.mem_stats` 1182- 1183-Call runtime.GC multiple times and return memory statistics as reported by 1184-runtime.MemStats. 1185- 1186-This command is used for benchmarking, and may change in the future. 1187- 1188-Result: 1189- 1190-``` 1191-{ 1192- "HeapAlloc": uint64, 1193- "HeapInUse": uint64, 1194-} 1195-``` 1196- 1197-### **Regenerate cgo** 1198-Identifier: `gopls.regenerate_cgo` 1199- 1200-Regenerates cgo definitions. 1201- 1202-Args: 1203- 1204-``` 1205-{ 1206- // The file URI. 1207- "URI": string, 1208-} 1209-``` 1210- 1211-### **Remove a dependency** 1212-Identifier: `gopls.remove_dependency` 1213- 1214-Removes a dependency from the go.mod file of a module. 1215- 1216-Args: 1217- 1218-``` 1219-{ 1220- // The go.mod file URI. 1221- "URI": string, 1222- // The module path to remove. 1223- "ModulePath": string, 1224- "OnlyDiagnostic": bool, 1225-} 1226-``` 1227- 1228-### **Reset go.mod diagnostics** 1229-Identifier: `gopls.reset_go_mod_diagnostics` 1230- 1231-Reset diagnostics in the go.mod file of a module. 1232- 1233-Args: 1234- 1235-``` 1236-{ 1237- "URIArg": { 1238- "URI": string, 1239- }, 1240- // Optional: source of the diagnostics to reset. 1241- // If not set, all resettable go.mod diagnostics will be cleared. 1242- "DiagnosticSource": string, 1243-} 1244-``` 1245- 1246-### **Run govulncheck.** 1247-Identifier: `gopls.run_govulncheck` 1248- 1249-Run vulnerability check (`govulncheck`). 1250- 1251-Args: 1252- 1253-``` 1254-{ 1255- // Any document in the directory from which govulncheck will run. 1256- "URI": string, 1257- // Package pattern. E.g. "", ".", "./...". 1258- "Pattern": string, 1259-} 1260-``` 1261- 1262-Result: 1263- 1264-``` 1265-{ 1266- // Token holds the progress token for LSP workDone reporting of the vulncheck 1267- // invocation. 1268- "Token": interface{}, 1269-} 1270-``` 1271- 1272-### **Run test(s)** 1273-Identifier: `gopls.run_tests` 1274- 1275-Runs `go test` for a specific set of test or benchmark functions. 1276- 1277-Args: 1278- 1279-``` 1280-{ 1281- // The test file containing the tests to run. 1282- "URI": string, 1283- // Specific test names to run, e.g. TestFoo. 1284- "Tests": []string, 1285- // Specific benchmarks to run, e.g. BenchmarkFoo. 1286- "Benchmarks": []string, 1287-} 1288-``` 1289- 1290-### **Start the gopls debug server** 1291-Identifier: `gopls.start_debugging` 1292- 1293-Start the gopls debug server if it isn't running, and return the debug 1294-address. 1295- 1296-Args: 1297- 1298-``` 1299-{ 1300- // Optional: the address (including port) for the debug server to listen on. 1301- // If not provided, the debug server will bind to "localhost:0", and the 1302- // full debug URL will be contained in the result. 1303- // 1304- // If there is more than one gopls instance along the serving path (i.e. you 1305- // are using a daemon), each gopls instance will attempt to start debugging. 1306- // If Addr specifies a port, only the daemon will be able to bind to that 1307- // port, and each intermediate gopls instance will fail to start debugging. 1308- // For this reason it is recommended not to specify a port (or equivalently, 1309- // to specify ":0"). 1310- // 1311- // If the server was already debugging this field has no effect, and the 1312- // result will contain the previously configured debug URL(s). 1313- "Addr": string, 1314-} 1315-``` 1316- 1317-Result: 1318- 1319-``` 1320-{ 1321- // The URLs to use to access the debug servers, for all gopls instances in 1322- // the serving path. For the common case of a single gopls instance (i.e. no 1323- // daemon), this will be exactly one address. 1324- // 1325- // In the case of one or more gopls instances forwarding the LSP to a daemon, 1326- // URLs will contain debug addresses for each server in the serving path, in 1327- // serving order. The daemon debug address will be the last entry in the 1328- // slice. If any intermediate gopls instance fails to start debugging, no 1329- // error will be returned but the debug URL for that server in the URLs slice 1330- // will be empty. 1331- "URLs": []string, 1332-} 1333-``` 1334- 1335-### **Run test(s) (legacy)** 1336-Identifier: `gopls.test` 1337- 1338-Runs `go test` for a specific set of test or benchmark functions. 1339- 1340-Args: 1341- 1342-``` 1343-string, 1344-[]string, 1345-[]string 1346-``` 1347- 1348-### **Run go mod tidy** 1349-Identifier: `gopls.tidy` 1350- 1351-Runs `go mod tidy` for a module. 1352- 1353-Args: 1354- 1355-``` 1356-{ 1357- // The file URIs. 1358- "URIs": []string, 1359-} 1360-``` 1361- 1362-### **Toggle gc_details** 1363-Identifier: `gopls.toggle_gc_details` 1364- 1365-Toggle the calculation of gc annotations. 1366- 1367-Args: 1368- 1369-``` 1370-{ 1371- // The file URI. 1372- "URI": string, 1373-} 1374-``` 1375- 1376-### **Update go.sum** 1377-Identifier: `gopls.update_go_sum` 1378- 1379-Updates the go.sum file for a module. 1380- 1381-Args: 1382- 1383-``` 1384-{ 1385- // The file URIs. 1386- "URIs": []string, 1387-} 1388-``` 1389- 1390-### **Upgrade a dependency** 1391-Identifier: `gopls.upgrade_dependency` 1392- 1393-Upgrades a dependency in the go.mod file for a module. 1394- 1395-Args: 1396- 1397-``` 1398-{ 1399- // The go.mod file URI. 1400- "URI": string, 1401- // Additional args to pass to the go command. 1402- "GoCmdArgs": []string, 1403- // Whether to add a require directive. 1404- "AddRequire": bool, 1405-} 1406-``` 1407- 1408-### **Run go mod vendor** 1409-Identifier: `gopls.vendor` 1410- 1411-Runs `go mod vendor` for a module. 1412- 1413-Args: 1414- 1415-``` 1416-{ 1417- // The file URI. 1418- "URI": string, 1419-} 1420-``` 1421- 1422-<!-- END Commands: DO NOT MANUALLY EDIT THIS SECTION --> 1423diff -urN a/gopls/doc/contributing.md b/gopls/doc/contributing.md 1424--- a/gopls/doc/contributing.md 2000-01-01 00:00:00.000000000 -0000 1425+++ b/gopls/doc/contributing.md 1970-01-01 00:00:00.000000000 +0000 1426@@ -1,119 +0,0 @@ 1427-# Documentation for contributors 1428- 1429-This documentation augments the general documentation for contributing to the 1430-x/tools repository, described at the [repository root](../../CONTRIBUTING.md). 1431- 1432-Contributions are welcome, but since development is so active, we request that 1433-you file an issue and claim it before starting to work on something. Otherwise, 1434-it is likely that we might already be working on a fix for your issue. 1435- 1436-## Finding issues 1437- 1438-All `gopls` issues are labeled as such (see the [`gopls` label][issue-gopls]). 1439-Issues that are suitable for contributors are additionally tagged with the 1440-[`help-wanted` label][issue-wanted]. 1441- 1442-Before you begin working on an issue, please leave a comment that you are 1443-claiming it. 1444- 1445-## Getting started 1446- 1447-Most of the `gopls` logic is in the `golang.org/x/tools/gopls/internal/lsp` 1448-directory. 1449- 1450-## Build 1451- 1452-To build a version of `gopls` with your changes applied: 1453- 1454-```bash 1455-cd /path/to/tools/gopls 1456-go install 1457-``` 1458- 1459-To confirm that you are testing with the correct `gopls` version, check that 1460-your `gopls` version looks like this: 1461- 1462-```bash 1463-$ gopls version 1464-golang.org/x/tools/gopls master 1465- golang.org/x/tools/gopls@(devel) 1466-``` 1467- 1468-## Getting help 1469- 1470-The best way to contact the gopls team directly is via the 1471-[#gopls-dev](https://app.slack.com/client/T029RQSE6/CRWSN9NCD) channel on the 1472-gophers slack. Please feel free to ask any questions about your contribution or 1473-about contributing in general. 1474- 1475-## Testing 1476- 1477-To run tests for just `gopls/`, run, 1478- 1479-```bash 1480-cd /path/to/tools/gopls 1481-go test ./... 1482-``` 1483- 1484-But, much of the gopls work involves `internal/lsp` too, so you will want to 1485-run both: 1486- 1487-```bash 1488-cd /path/to/tools 1489-cd gopls && go test ./... 1490-cd .. 1491-go test ./internal/lsp/... 1492-``` 1493- 1494-There is additional information about the `internal/lsp` tests in the 1495-[internal/lsp/tests `README`](https://github.com/golang/tools/blob/master/internal/lsp/tests/README.md). 1496- 1497-### Regtests 1498- 1499-gopls has a suite of regression tests defined in the `./gopls/internal/regtest` 1500-directory. Each of these tests writes files to a temporary directory, starts a 1501-separate gopls session, and scripts interactions using an editor-like API. As a 1502-result of this overhead they can be quite slow, particularly on systems where 1503-file operations are costly. 1504- 1505-Due to the asynchronous nature of the LSP, regtests assertions are written 1506-as 'expectations' that the editor state must achieve _eventually_. This can 1507-make debugging the regtests difficult. To aid with debugging, the regtests 1508-output their LSP logs on any failure. If your CL gets a test failure while 1509-running the regtests, please do take a look at the description of the error and 1510-the LSP logs, but don't hesitate to [reach out](#getting-help) to the gopls 1511-team if you need help. 1512- 1513-### CI 1514- 1515-When you mail your CL and you or a fellow contributor assigns the 1516-`Run-TryBot=1` label in Gerrit, the 1517-[TryBots](https://golang.org/doc/contribute.html#trybots) will run tests in 1518-both the `golang.org/x/tools` and `golang.org/x/tools/gopls` modules, as 1519-described above. 1520- 1521-Furthermore, an additional "gopls-CI" pass will be run by _Kokoro_, which is a 1522-Jenkins-like Google infrastructure for running Dockerized tests. This allows us 1523-to run gopls tests in various environments that would be difficult to add to 1524-the TryBots. Notably, Kokoro runs tests on 1525-[older Go versions](../README.md#supported-go-versions) that are no longer supported 1526-by the TryBots. Per that that policy, support for these older Go versions is 1527-best-effort, and test failures may be skipped rather than fixed. 1528- 1529-Kokoro runs are triggered by the `Run-TryBot=1` label, just like TryBots, but 1530-unlike TryBots they do not automatically re-run if the "gopls-CI" result is 1531-removed in Gerrit. To force a re-run of the Kokoro CI on a CL containing the 1532-`Run-TryBot=1` label, you can reply in Gerrit with the comment "kokoro rerun". 1533- 1534-## Debugging 1535- 1536-The easiest way to debug your change is to run a single `gopls` test with a 1537-debugger. 1538- 1539-See also [Troubleshooting](troubleshooting.md#troubleshooting). 1540- 1541-<!--TODO(rstambler): Add more details about the debug server and viewing 1542-telemetry.--> 1543- 1544-[issue-gopls]: https://github.com/golang/go/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Agopls "gopls issues" 1545-[issue-wanted]: https://github.com/golang/go/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Agopls+label%3A"help+wanted" "help wanted" 1546diff -urN a/gopls/doc/daemon.md b/gopls/doc/daemon.md 1547--- a/gopls/doc/daemon.md 2000-01-01 00:00:00.000000000 -0000 1548+++ b/gopls/doc/daemon.md 1970-01-01 00:00:00.000000000 +0000 1549@@ -1,183 +0,0 @@ 1550-# Running gopls as a daemon 1551- 1552-**Note: this feature is new. If you encounter bugs, please [file an 1553-issue](troubleshooting.md#file-an-issue).** 1554- 1555-If you just want to try this out, skip ahead to the [quickstart](#quickstart). 1556- 1557-## Background: gopls execution modes 1558- 1559-Gopls was originally implemented as an LSP sidecar: a process started by 1560-editors or editor plugins, and communicated with using jsonrpc 2.0 over 1561-stdin/stdout. By executing as a stateful process, gopls can maintain a 1562-significant amount of cache and can eagerly perform analysis on the source code 1563-being edited. 1564- 1565-This execution mode does not work as well when there are many separate editor 1566-processes or when editor processes are short-lived, as is often the case for 1567-users of non-IDE editors such as Vim or Emacs. Having many processes means 1568-having many caches, consuming a significant amount of system resources. Using 1569-short-lived sessions means paying a start-up cost each time a session is 1570-created. 1571- 1572-To support these types of workflows, a new mode of gopls execution is supported 1573-wherein a single, persistent, shared gopls "daemon" process is responsible for 1574-managing all gopls sessions. In this mode, editors still start a gopls sidecar, 1575-but this sidecar merely acts as a thin "forwarder", responsible for forwarding 1576-the LSP to the shared gopls instance and recording metrics, logs, and rpc 1577-traces. 1578- 1579-## Quickstart 1580- 1581-To use a shared gopls instance you must either manage the daemon process 1582-yourself, or let the gopls forwarder processes start the shared daemon as 1583-needed. 1584- 1585-### Running with `-remote=auto` 1586- 1587-Automatic management of the daemon is easiest, and can be done by passing the 1588-flag `-remote=auto` to the gopls process started by your editor. This will 1589-cause this process to auto-start the gopls daemon if needed, connect to it, and 1590-forward the LSP. For example, here is a reasonable gopls invocation, that sets 1591-some additional flags for easier [debugging](#debugging): 1592- 1593-```bash 1594-gopls -remote=auto -logfile=auto -debug=:0 -remote.debug=:0 -rpc.trace 1595-``` 1596- 1597-Note that the shared gopls process will automatically shut down after one 1598-minute with no connected clients. 1599- 1600-### Managing the daemon manually 1601- 1602-To manage the gopls daemon process via external means rather than having the 1603-forwarders manage it, you must start a gopls daemon process with the 1604-`-listen=<addr>` flag, and then pass `-remote=<addr>` to the gopls processes 1605-started by your editor. 1606- 1607-For example, to host the daemon on the TCP port `37374`, do: 1608- 1609-```bash 1610-gopls -listen=:37374 -logfile=auto -debug=:0 1611-``` 1612- 1613-And then from the editor, run 1614- 1615-```bash 1616-gopls -remote=:37374 -logfile=auto -debug=:0 -rpc.trace 1617-``` 1618- 1619-If you are on a POSIX system, you can also use unix domain sockets by prefixing 1620-the flag values with `unix;`. For example: 1621- 1622-```bash 1623-gopls -listen="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0 1624-``` 1625- 1626-And connect via: 1627- 1628-```bash 1629-gopls -remote="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0 -rpc.trace 1630-``` 1631- 1632-(Note that these flag values MUST be enclosed in quotes, because ';' is a 1633-special shell character. For this reason, this syntax is subject to change in 1634-the future.) 1635- 1636-## Debugging 1637- 1638-Debugging a shared gopls session is more complicated than a singleton session, 1639-because there are now two gopls processes involved with handling the LSP. Here 1640-are some tips: 1641- 1642-### Finding logfiles and debug addresses 1643- 1644-When running in daemon mode, you can use the `gopls inspect sessions` command 1645-to find the logfile and debug port for your gopls daemon instance (as well as 1646-for all its connected clients). By default, this inspects the default daemon 1647-(i.e. `-remote=auto`). To inspect a different daemon, use the `-remote` flag 1648-explicitly: `gopls -remote=localhost:12345 inspect sessions`. 1649- 1650-This works whether or not you have enabled `-remote.debug`. 1651- 1652-### Traversing debug pages 1653- 1654-When `-debug=:0` is passed to gopls, it runs a webserver that serves stateful 1655-debug pages (see [troubleshooting.md](troubleshooting.md)). You can find the 1656-actual port hosting these pages by either using the `gopls inspect sessions` 1657-command, or by checking the start of the logfile -- it will be one of the first 1658-log messages. For example, if using `-logfile=auto`, find the debug address by 1659-checking `head /tmp/gopls-<pid>.log`. 1660- 1661-By default, the gopls daemon is not started with `-debug`. To enable it, set 1662-the `-remote.debug` flag on the forwarder instance, so that it invokes gopls 1663-with `-debug` when starting the daemon. 1664- 1665-The debug pages of the forwarder process will have a link to the debug pages of 1666-the daemon server process. Correspondingly, the debug pages of the daemon 1667-process will have a link to each of its clients. 1668- 1669-This can help you find metrics, traces, and log files for all of the various 1670-servers and clients. 1671- 1672-### Using logfiles 1673- 1674-The gopls daemon is started with logging disabled by default. To customize 1675-this, pass `-remote.logfile` to the gopls forwarder. Using 1676-`-remote.logfile=auto`, the daemon will log to a default location (on posix 1677-systems: `/tmp/gopls-daemon-<pid>.log`). 1678- 1679-The gopls daemon does not log session-scoped messages: those are instead 1680-reflected back to the forwarder so that they can be accessed by the editor. 1681-Daemon logs will only contain global messages, for example logs when sessions 1682-connect and disconnect. 1683- 1684-It is recommended to start the forwarder gopls process with `-rpc.trace`, so 1685-that its logfile will contain rpc trace logs specific to the LSP session. 1686- 1687-## Using multiple shared gopls instances 1688- 1689-There may be environments where it is desirable to have more than one shared 1690-gopls instance. If managing the daemon manually, this can be done by simply 1691-choosing different `-listen` addresses for each distinct daemon process. 1692- 1693-On POSIX systems, there is also support for automatic management of distinct 1694-shared gopls processes: distinct daemons can be selected by passing 1695-`-remote="auto;<id>"`. Any gopls forwarder passing the same value for `<id>` 1696-will use the same shared daemon. 1697- 1698-## FAQ 1699- 1700-**Q: Why am I not saving as much memory as I expected when using a shared gopls?** 1701- 1702-A: As described in [implementation.md](design/implementation.md), gopls has a 1703-concept of view/session/cache. Each session and view map onto exactly one 1704-editor session (because they contain things like edited but unsaved buffers). 1705-The cache contains things that are independent of any editor session, and can 1706-therefore be shared. 1707- 1708-When, for example, three editor session are sharing a single gopls process, 1709-they will share the cache but will each have their own session and view. The 1710-memory savings in this mode, when compared to three separate gopls processes, 1711-corresponds to the amount of cache overlap across sessions. 1712- 1713-Because this hasn't mattered much in the past, it is likely that there is state 1714-that can be moved out of the session/view, and into the cache, thereby 1715-increasing the amount of memory savings in the shared mode. 1716- 1717-**Q: How do I customize the daemon instance when using `-remote=auto`?** 1718- 1719-The daemon may be customized using flags of the form `-remote.*` on the 1720-forwarder gopls. This causes the forwarder to invoke gopls with these settings 1721-when starting the daemon. As of writing, we expose the following configuration: 1722- 1723-* `-remote.logfile`: the location of the daemon logfile 1724-* `-remote.debug`: the daemon's debug address 1725-* `-remote.listen.timeout`: the amount of time the daemon should wait for new 1726- connections while there are no current connections, before shutting down. 1727- Must be set to a valid `time.Duration` (e.g. `30s` or `5m`). If `0`, listen 1728- indefinitely. Default: `1m`. 1729- 1730-Note that once the daemon is already running, setting these flags will not 1731-change its configuration. These flags only matter for the forwarder process 1732-that actually starts the daemon. 1733diff -urN a/gopls/doc/design/design.md b/gopls/doc/design/design.md 1734--- a/gopls/doc/design/design.md 2000-01-01 00:00:00.000000000 -0000 1735+++ b/gopls/doc/design/design.md 1970-01-01 00:00:00.000000000 +0000 1736@@ -1,394 +0,0 @@ 1737-# `gopls` design documentation 1738- 1739-## Goals 1740- 1741-* `gopls` should **become the default editor backend** for the major editors used by Go programmers, fully supported by the Go team. 1742-* `gopls` will be a **full implementation of LSP**, as described in the [LSP specification], to standardize as many of its features as possible. 1743-* `gopls` will be **clean and extensible** so that it can encompass additional features in the future, allowing Go tooling to become best in class once more. 1744-* `gopls` will **support alternate build systems and file layouts**, allowing Go development to be simpler and more powerful in any environment. 1745- 1746-## Context 1747- 1748-While Go has a number of excellent and useful command-line tools that enhance the developer experience, it has become clear that integrating these tools with IDEs can pose challenges. 1749- 1750-Support of these tools has relied on the goodwill of community members, and they have been put under a large burden of support at times as the language, toolchain and environments change. As a result many tools have ceased to work, have had support problems, or become confusing with forks and replacements, or provided an experience that is not as good as it could be. 1751-See the section below on [existing solutions](#existing-solutions) for more problems and details. 1752- 1753-This is fine for tools used occasionally, but for core IDE features, this is not acceptable. 1754-Autocompletion, jump to definition, formatting, and other such features should always work, as they are key for Go development. 1755- 1756-The Go team will create an editor backend that works in any build system. 1757-It will also be able to improve upon the latency of Go tools, since each tool will no longer have to individually run the type-checker on each invocation, instead there will be a long-running process and data can be shared between the definitions, completions, diagnostics, and other features. 1758- 1759-By taking ownership of these tools and packaging them together in the form of gopls, the Go team will ensure that the Go development experience isn’t unnecessarily complicated for Go users. 1760-Having one editor backend will simplify the lives of Go developers, the Go team, and the maintainers of Go editor plugins. 1761- 1762-See Rebecca's excellent GopherCon keynote [talk] and [slides] for some more context. 1763- 1764-## Non-Goals 1765- 1766-* Command line speed 1767- 1768- Although gopls will have a command line mode, it will be optimized for long running and not command responsiveness, as such it may not be the right tool for things like CI systems. 1769- For such cases there will have to be an alternate tool using the same underlying libraries for consistency. 1770- 1771-* Low memory environments 1772- 1773- In order to do a good job of processing large projects with very low latencies gopls will be holding a lot of information in memory. 1774- It is presumed that developers are normally working on systems with significant RAM and this will not be a problem. 1775- In general this is upheld by the large memory usage of existing IDE solutions (like IntelliJ) 1776- 1777-* Syntax highlighting 1778- 1779- At the moment there is no editor that delegates this functionality to a separate binary, and no standard way of doing it. 1780- 1781-## Existing solutions 1782- 1783-Every year the Go team conducts a survey, asking developers about their experiences with the language. 1784- 1785-One question that is asked is “How do you feel about your editor?”. 1786- 1787-The responses told a very negative story. Some categorized quotes: 1788- 1789-* Setup 1790- * "Hard to install and configure" 1791- * "Inadequate documentation" 1792-* Performance 1793- * "Performance is very poor" 1794- * "Pretty slow in large projects" 1795-* Reliability 1796- * "Features work one day, but not the next" 1797- * "Tooling is not updated with new language features" 1798- 1799-Each editor has its own plugin that shells out to a variety of tools, many of which break with new Go releases or because they are no longer maintained. 1800- 1801-The individual tools each have to do the work to understand the code and all its transitive dependencies. 1802- 1803-Each feature is a different tool, with a different set of patterns for its command line, a different way to accept input and parse output, a different way of specifying source code locations. 1804-To support its existing feature set, VSCode installed 24 different command line tools, many of which have options or forks to configure. When looking at the set of tools that needed to be migrated to modules, across all the editors, there were 63 separate tools. 1805- 1806-All these tools need to understand the code, and they use the same standard libraries to do it. Those libraries are optimized for these kinds of tools, but even so processing that much code takes a lot of time time. Almost none of the tools are capable of returning results within 100ms. 1807-As developers type in their editor, multiple of these features need to activate, which means they are not just paying the cost once, but many times. The overall effect is an editing experience that feels sluggish, and features that are either not enabled or sometimes produce results that appear so slowly they are no longer useful when they arrive. This is a problem that increases with the size of the code base, which means it is getting worse over time, and is especially bad for the kinds of large code bases companies are dealing with as they use Go for more major tasks. 1808- 1809-## Requirements 1810- 1811-### Complete feature set 1812- 1813-For gopls to be considered a success it has to implement the full feature set discussed [below](#Features). 1814-This is the set of features that users need in order to feel as productive as they were with the tooling it is replacing. It does not include every feature of previous implementations, there are some features that are almost never used that should be dropped (like guru's pointer analysis) and some other features that do not easily fit and will have to be worked around (replacing the save hook/linter). 1815- 1816-### Equivalent or better experience 1817- 1818-For all of those features, the user experience must match or exceed the current one available in all editors. 1819-This is an easy statement to make, but a hard one to validate or measure. Many of the possible measures fail to capture the experience. 1820- 1821-For instance, if an attempt was made to measure the latency of a jump to definition call, the results would be fairly consistent from the old godef tool. From the gopls implementation there may be a much larger range of latencies, with the best being orders of magnitude faster, and the worse slightly worse, because gopls attempts to do far more work, but manages to cache it across calls. 1822- 1823-Or for a completion call, it might be slower but produce a better first match such that users accept it more often, resulting in an overall better experience. 1824- 1825-For the most part this has to rely on user reports. If users are refusing to switch because the experience is not better, it is clearly not done, if they are switching but most people are complaining, there are probably enough areas that are better to make the switch compelling but other areas which are worse. If most people are switching and either staying silent or being positive, it is probably done. When writing tools, the user is all that matters. 1826- 1827-### Solid community of contributors 1828- 1829-The scope and scale of the problem gopls is trying to solve is untenable for the core Go team, it is going to require a strong community to make it all happen. 1830- 1831-This implies the code must be easy to contribute to, and easy for many developers to work on in parallel. The functionality needs to be well decoupled, and have a thorough testing story. 1832- 1833-### Latencies that fall within user tolerance 1834- 1835-There has been a lot of research on acceptable latencies for user actions. 1836-<!-- TODO: research links --> 1837-The main result that affects gopls is that feedback in direct response to continuous user actions needs to be under 100ms to be imperceptible, and anything above 200ms aggravates the user. 1838-This means in general the aim has to be <100ms for anything that happens as the developer types. 1839-There will always be cases where gopls fails to meet this deadline, and there needs to be ways to make the user experience okay in those cases, but in general the point of this deadline is to inform the basic architecture design, any solution that cannot theoretically meet this goal in the long term is the wrong answer. 1840- 1841-### Easy to configure 1842- 1843-Developers are very particular, and have very differing desires in their coding experience. gopls is going to have to support a significant amount of flexibility, in order to meet those desires. 1844-The default settings however with no configuration at all must be the one that is best experience for most users, and where possible the features must be flexible without configuration so that the client can easily make the choices about treatment without changing its communication with gopls. 1845- 1846-## Difficulties 1847- 1848-### Volume of data 1849- 1850-<!-- TODO: project sizes --> 1851-* Small: 1852-* Medium: 1853-* Large: 1854-* Corporate mono-repo: Much much bigger 1855- 1856-Parsing and type checking large amounts of code is quite expensive, and the converted forms use a lot of space. As gopls has to keep updating this information while the developer types, it needs to manage how it caches the converted forms very carefully to balance memory use vs speed. 1857- 1858-### Cache invalidation 1859- 1860-The basic unit of operation for the type checking is the package, but the basic unit of operation for an editor is the file. 1861-gopls needs to be able to map files to packages efficiently, so that when files change it knows which packages need to be updated (along with any other packages that transitively depended on them). 1862-This is made especially difficult by the fact that changing the content of a file can modify which packages it is considered part of (either by changing the package declaration or the build tags), a file can be in more than one package, and changes can be made to files without using the editor, in which case it will not notify us of the changes. 1863- 1864-### Inappropriate core functionality 1865- 1866-The base libraries for Go (things like [go/token], [go/ast] and [go/types]) are all designed for compiler-like applications. 1867-They tend to worry more about throughput than memory use, they have structures that are intended to grow and then be thrown away at program exit, and they are not designed to keep going in the presence of errors in the source they are handling. 1868-They also have no abilities to do incremental changes. 1869- 1870-Making a long running service work well with those libraries is a very large challenge, but writing new libraries would be far more work, and cause a significant long term cost as both sets of libraries would have to be maintained. Right now it is more important to get a working tool into the hands of users. In the long term this decision may have to be revisited, new low level libraries may be the only way to keep pushing the capabilities forwards. 1871- 1872-### Build system capabilities 1873- 1874-gopls is supposed to be build system agnostic, but it must use the build system to discover how files map to packages. When it tries to do so, even when the functionality is the same, the costs (in time, CPU and memory) are very different, and can significantly impact the user experience. Designing how gopls interacts with the build system to try to minimize or hide these differences is hard. 1875- 1876-### Build tags 1877- 1878-The build tag system in Go is quite powerful, and has many use cases. Source files can exclude themselves using powerful boolean logic on the set of active tags. 1879-It is however designed for specifying the set of active tags on the command line, and the libraries are all designed to cope with only one valid combination at a time. There is also no way to work out the set of valid combinations. 1880- 1881-Type checking a file requires knowledge of all the other files in the same package, and that set of files is modified by the build tags. The set of exported identifiers of a package is also affected by which files are in the package, and thus its build tags. 1882- 1883-This means that even for files or packages that have no build tag controls it is not possible to produce correct results without knowing the set of build tags to consider. 1884-This makes it very hard to produce useful results when viewing a file. 1885- 1886-### Features not supported by LSP 1887- 1888-There are some things it would be good to be able to do that do not fit easily into the existing LSP protocol. 1889-For instance, displaying control flow information, automatic struct tags, complex refactoring... 1890- 1891-Each feature will have to be considered carefully, and either propose a change to LSP, or add a way to have gopls specific extensions to the protocol that are still easy to use in all the editor plugins. 1892- 1893-To avoid these at the start, only core LSP features will be implemented, as they are sufficient to meet the baseline requirements anyway, but the potential features need to be kept in mind in the core architecture. 1894- 1895-### Distribution 1896- 1897-Making sure that users are using the right version of gopls is going to be a problem. Each editor plugin is probably going to install the tools in its own way, some will choose to install it system wide, some will keep their own copy. 1898- 1899-Because it is a brand new tool, it will be changing rapidly. If users are not informed they are on an old version they will be experiencing problems that have already been fixed, which is worse for them, and then probably reporting them, which wastes time for the gopls team. There needs to be a mechanism for gopls to check if is up to date, and a recommended way to install an up to date version. 1900- 1901-### Debugging user problems 1902- 1903-gopls is essentially a very stateful long running server on the developer's machine. Its basic operation is affected by many things, from the users environment to the contents of the local build cache. The data it is operating on is often a confidential code base that cannot be shared. 1904-All of these things make it hard for users to report a bug usefully, or create a minimal reproduction. 1905- 1906-There needs to be easy ways for users to report what information they can, and ways to attempt to reproduce problems without their entire state. This is also needed to produce regression tests. 1907- 1908-## Basic design decisions 1909- 1910-There are some fundamental architecture decisions that affect much of the rest of the design of the tool, making fundamental trade offs that impact the user experience. 1911- 1912-### Process lifetime: *managed by the editor* 1913- 1914-Processing a large code base to fully type check and then analyze it within the latency requirements is not feasible, and is one of the primary problems with the existing solutions. This remains true even if the computed information was cached on disk, as running analyzers and type checkers ends up requiring the full AST of all files in the dependency graph. 1915-It is theoretically possible to do better, but only with a major re-write of the existing parsing and type checking libraries, something that is not feasible at this time. 1916- 1917-This implies that gopls should be a long running process, that is able to cache and pre-calculate results in memory so that when a request arrives it can produce the answer much faster. 1918- 1919-It could run as a daemon on the user's machine, but there are a lot of issues with managing a daemon. It may well be the right choice in the long term, and it should be allowed for in the fundamental architecture design, but to start with it will instead have a process that lasts as long as the editor that starts it, and that can easily be restarted. 1920- 1921-### Caching: *in memory* 1922- 1923-Persistent disk caches are very expensive to maintain, and require solving a lot of extra problems. 1924-Although building the information required is expensive compared to the latencies required of the requests, it is fairly minor compared to the startup times of an editor, so it is expected that rebuilding the information when gopls is restarted will be acceptable. 1925- 1926-The advantage gained from this is that gopls becomes stateless across restarts which means if it has issues or gets its state confused, a simple restart will often fix the problem. 1927-It also means that when users report problems, the entire state of the on disk cache is not needed to diagnose and reproduce the issue. 1928- 1929-### Communication: *stdin/stdout JSON* 1930- 1931-The LSP specification defines the JSON messages that are normally used, but it does not define how those message should be sent, and there are implementations of the LSP that do not use JSON (for instance, Protocol buffers are an option). 1932- 1933-The constraints on gopls are that it must be easy to integrate into *every editor* on *all operating systems*, and that it should not have large external dependencies. 1934- 1935-JSON is part of the Go standard library, and is also the native language of LSP, so it makes the most sense. By far the best supported communication mechanism is the standard input and output of a process, and the common client implementations all have ways of using [JSON rpc 2] in this mode. There were no complete and low dependency implementations of this protocol in Go, but it is a fairly small protocol on top of the JSON library that can be implemented with a moderate effort, and would be a generally useful library to have anyway. 1936- 1937-In the future it is expected to run in separated client server mode, so writing it in a way that could use sockets instead of stdin/stdout from the start was the best way to make sure it remained possible. It was also a huge debugging aid to be able to run the gopls server by hand and watch/debug it outside the editor. 1938- 1939-### Running other tools: *no* 1940- 1941-<!--- TODO: subprocess discuss ---> 1942- 1943-## Features 1944- 1945-<!--TODO(rstambler): Generate a file that lists all of the supported features.--> 1946- 1947-There is a set of features that gopls needs to expose to be a comprehensive IDE solution. 1948-The following is the minimum set of features, along with their existing solutions and how they should map to the LSP. 1949- 1950-### Introspection 1951- 1952-Introspection features tell developers information about their code while they work. They do not make or suggest changes. 1953- 1954---- 1955-Diagnostics | Static analysis results of the code, including compilation and lint errors 1956------------ | --- 1957-Requires | Full go/analysis run, which needs full AST, type and SSA information 1958-LSP | [`textDocument/publishDiagnostics`] 1959-Previous | `go build`, `go vet`, `golint`, [errcheck], [staticcheck] <!-- TODO: and all the rest --> 1960-| | This is one of the most important IDE features, allowing fast turn around without having to run compilers and checkers in the shell. Often used to power problem lists, gutter markers and squiggle underlines in the IDE. <br/> There is some complicated design work to do in order to let users customize the set of checks being run, preferably without having to recompile the main LSP binary. 1961- 1962---- 1963-Hover | Information about the code under the cursor. 1964--------- | --- 1965-Requires | AST and type information for the file and all dependencies 1966-LSP | [`textDocument/hover`] 1967-Previous | [godoc], [gogetdoc] 1968-| | Used when reading code to display information known to the compiler but not always obvious from the code. For instance it may return the types of identifiers, or the documentation. 1969- 1970---- 1971-Signature help | Function parameter information and documentation 1972--------------- | --- 1973-Requires | AST and type information for the file and all dependencies 1974-LSP | [`textDocument/signatureHelp`] 1975-Previous | [gogetdoc] 1976-| | As a function call is being typed into code, it is helpful to know the parameters of that call to enable the developer to call it correctly. 1977- 1978-### Navigation 1979- 1980-Navigation features are designed to make it easier for a developer to find their way round a code base. 1981- 1982---- 1983-Definition | Select an identifier, and jump to the code where that identifier was defined. 1984----------- | --- 1985-Requires | Full type information for file and all dependencies 1986-LSP | [`textDocument/declaration`] 1987-| | [`textDocument/definition`] 1988-| | [`textDocument/typeDefinition`] 1989-Previous | [godef] | 1990-| | Asking the editor to open the place where a symbol was defined is one of the most commonly used code navigation tools inside an IDE when available. It is especially valuable when exploring an unfamiliar code base.<br/>Due to a limitation of the compiler output, it is not possible to use the binary data for this task (specifically it does not know column information) and thus it must parse from source. 1991- 1992---- 1993-Implementation | Reports the types that implement an interface 1994--------------- | --- 1995-Requires | Full workspace type knowledge 1996-LSP | [`textDocument/implementation`] 1997-Previous | [impl] 1998-| | This feature is hard to scale up to large code bases, and is going to take thought to get right. It may be feasible to implemented a more limited form in the meantime. 1999- 2000---- 2001-Document symbols | Provides the set of top level symbols in the current file. 2002----------------- | --- 2003-Requires | AST of the current file only 2004-LSP | [`textDocument/documentSymbol`] 2005-Previous | [go-outline], [go-symbols] 2006-| | Used to drive things like outline mode. 2007- 2008---- 2009-References | Find all references to the symbol under the cursor. 2010----------- | --- 2011-Requires | AST and type information for the **reverse** transitive closure 2012-LSP | [`textDocument/references`] 2013-Previous | [guru] 2014-| | This requires knowledge of every package that could possible depend on any packages the current file is part of. In the past this has been implemented either by global knowledge, which does not scale, or by specifying a "scope" which confused users to the point where they just did not use the tools. gopls is probably going to need a more powerful solution in the long term, but to start with automatically limiting the scope may produce acceptable results. This would probably be the module if known, or some sensible parent directory otherwise. 2015- 2016---- 2017-Folding | Report logical hierarchies of blocks 2018--------- | --- 2019-Requires | AST of the current file only 2020-LSP | [`textDocument/foldingRange`] 2021-Previous | [go-outline] 2022-| | This is normally used to provide expand and collapse behavior in editors. 2023- 2024---- 2025-Selection | Report regions of logical selection around the cursor 2026---------- | --- 2027-Requires | AST of the current file only 2028-LSP | [`textDocument/selectionRange`] 2029-Previous | [guru] 2030-| | Used in editor features like expand selection. 2031- 2032- 2033-### Edit assistance 2034- 2035-These features suggest or apply edits to the code for the user, including refactoring features, for which there are many potential use cases. 2036-Refactoring is one of the places where Go tools could potentially be very strong, but have not been so far, and thus there is huge potential for improvements in the developer experience. 2037-There is not yet a clear understanding of the kinds of refactoring people need or how they should express them however, and there are weaknesses in the LSP protocol around this. 2038-This means it may be much more of a research project. 2039- 2040- 2041---- 2042-Format | Fix the formatting of the file 2043--------- | --- 2044-Requires | AST of current file 2045-LSP | [`textDocument/formatting`] 2046-| | [`textDocument/rangeFormatting`] 2047-| | [`textDocument/onTypeFormatting`] 2048-Previous | [gofmt], [goimports], [goreturns] 2049-| | It will use the standard format package. <br/> Current limitations are that it does not work on malformed code. It may need some very careful changes to the formatter to allow for formatting an invalid AST or changes to force the AST to a valid mode. These changes would improve range and file mode as well, but are basically vital to onTypeFormatting 2050- 2051---- 2052-Imports | Rewrite the imports block automatically to match the symbols used. 2053--------- | --- 2054-Requires | AST of the current file and full symbol knowledge for all candidate packages. 2055-LSP | [`textDocument/codeAction`] 2056-Previous | [goimports], [goreturns] 2057-| | This needs knowledge of packages that are not yet in use, and the ability to find those packages by name. <br/> It also needs exported symbol information for all the packages it discovers. <br/> It should be implemented using the standard imports package, but there may need to be exposed a more fine grained API than just a file rewrite for some of the interactions. 2058- 2059---- 2060-Autocompletion | Makes suggestions to complete the entity currently being typed. 2061--------------- | --- 2062-Requires | AST and type information for the file and all dependencies<br/> Also full exported symbol knowledge for all packages. 2063-LSP | [`textDocument/completion`] 2064-| | [`completionItem/resolve`] 2065-Previous | [gocode] 2066-| | Autocomplete is one of the most complicated features, and the more it knows the better its suggestions can be. For instance it can autocomplete into packages that are not yet being imported if it has their public symbols. It can make better suggestions of options if it knows what kind of program you are writing. It can suggest better arguments if it knows how you normally call a function. It can suggest entire patterns of code if it knows they are common. Unlike many other features, which have a specific task, and once it is doing that task the feature is done, autocomplete will never be finished. Balancing and improving both the candidates and how they are ranked will be a research problem for a long time to come. 2067- 2068---- 2069-Rename | Rename an identifier 2070--------- | --- 2071-Requires | AST and type information for the **reverse** transitive closure 2072-LSP | [`textDocument/rename`] 2073-| | [`textDocument/prepareRename`] 2074-Previous | [gorename] 2075-| | This uses the same information that find references does, with all the same problems and limitations. It is slightly worse because the changes it suggests make it intolerant of incorrect results. It is also dangerous using it to change the public API of a package. 2076- 2077---- 2078-Suggested fixes | Suggestions that can be manually or automatically accepted to change the code 2079---------------- | --- 2080-Requires | Full go/analysis run, which needs full AST, type and SSA information 2081-LSP | [`textDocument/codeAction`] 2082-Previous | N/A 2083-| | This is a brand new feature powered by the new go/analysis engine, and it should allow a huge amount of automated refactoring. 2084- 2085-[LSP specification]: https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/ 2086-[talk]: TODO 2087-[slides]: https://github.com/gophercon/2019-talks/blob/master/RebeccaStambler-GoPleaseStopBreakingMyEditor/slides.pdf "Go, please stop breaking my editor!" 2088-[JSON rpc 2]: https://www.jsonrpc.org/specification 2089- 2090-[errcheck]: https://github.com/kisielk/errcheck 2091-[go-outline]: https://github.com/lukehoban/go-outline 2092-[go-symbols]: https://github.com/acroca/go-symbols 2093-[gocode]: https://github.com/stamblerre/gocode 2094-[godef]: https://github.com/rogpeppe/godef 2095-[godoc]: https://golang.org/cmd/godoc 2096-[gofmt]: https://golang.org/cmd/gofmt 2097-[gogetdoc]: https://github.com/zmb3/gogetdoc 2098-[goimports]: https://pkg.go.dev/golang.org/x/tools/cmd/goimports 2099-[gorename]: https://pkg.go.dev/golang.org/x/tools/cmd/gorename 2100-[goreturns]: https://github.com/sqs/goreturns 2101-[gotags]: https://github.com/jstemmer/gotags 2102-[guru]: https://pkg.go.dev/golang.org/x/tools/cmd/guru 2103-[impl]: https://github.com/josharian/impl 2104-[staticcheck]: https://staticcheck.io/docs/ 2105-[go/types]: https://golang.org/pkg/go/types/ 2106-[go/ast]: https://golang.org/pkg/go/ast/ 2107-[go/token]: https://golang.org/pkg/go/token/ 2108- 2109-[`completionItem/resolve`]:https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#completionItem_resolve 2110-[`textDocument/codeAction`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_codeAction 2111-[`textDocument/completion`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_completion 2112-[`textDocument/declaration`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_declaration 2113-[`textDocument/definition`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_definition 2114-[`textDocument/documentLink`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_documentLink 2115-[`textDocument/documentSymbol`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_documentSymbol 2116-[`textDocument/foldingRange`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_foldingRange 2117-[`textDocument/formatting`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_formatting 2118-[`textDocument/highlight`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_highlight 2119-[`textDocument/hover`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_hover 2120-[`textDocument/implementation`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_implementation 2121-[`textDocument/onTypeFormatting`]:https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_onTypeFormatting 2122-[`textDocument/prepareRename`]:https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_prepareRename 2123-[`textDocument/publishDiagnostics`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_publishDiagnostics 2124-[`textDocument/rangeFormatting`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_rangeFormatting 2125-[`textDocument/references`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_references 2126-[`textDocument/rename`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_rename 2127-[`textDocument/selectionRange`]:https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_selectionRange 2128-[`textDocument/signatureHelp`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_signatureHelp 2129-[`textDocument/typeDefinition`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_typeDefinition 2130-[`workspace/didChangeWatchedFiles`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#workspace_didChangeWatchedFiles 2131diff -urN a/gopls/doc/design/implementation.md b/gopls/doc/design/implementation.md 2132--- a/gopls/doc/design/implementation.md 2000-01-01 00:00:00.000000000 -0000 2133+++ b/gopls/doc/design/implementation.md 1970-01-01 00:00:00.000000000 +0000 2134@@ -1,48 +0,0 @@ 2135-# gopls implementation documentation 2136- 2137-This is not intended as a complete description of the implementation, for the most the part the package godoc, code comments and the code itself hold that. 2138-Instead this is meant to be a guide into finding parts of the implementation, and understanding some core concepts used throughout the implementation. 2139- 2140-## View/Session/Cache 2141- 2142-Throughout the code there are references to these three concepts, and they build on each other. 2143- 2144-At the base is the *Cache*. This is the level at which we hold information that is global in nature, for instance information about the file system and its contents. 2145- 2146-Above that is the *Session*, which holds information for a connection to an editor. This layer hold things like the edited files (referred to as overlays). 2147- 2148-The top layer is called the *View*. This holds the configuration, and the mapping to configured packages. 2149- 2150-The purpose of this layering is to allow a single editor session to have multiple views active whilst still sharing as much information as possible for efficiency. 2151-In theory if only the View layer existed, the results would be identical, but slower and using more memory. 2152- 2153-## Code location 2154- 2155-gopls will be developed in the [x/tools] Go repository; the core packages are in [internal/lsp], and the binary and integration tests are located in [gopls]. 2156- 2157-Below is a list of the core packages of gopls, and their primary purpose: 2158- 2159-Package | Description 2160---- | --- 2161-[gopls] | the main binary, plugins and integration tests 2162-[internal/lsp] | the core message handling package 2163-[internal/lsp/cache] | the cache layer 2164-[internal/lsp/cmd] | the gopls command line layer 2165-[internal/lsp/debug] | features to aid in debugging gopls 2166-[internal/lsp/protocol] | the types of LSP request and response messages 2167-[internal/lsp/source] | the core feature implementations 2168-[internal/span] | a package for dealing with source file locations 2169-[internal/memoize] | a function invocation cache used to reduce the work done 2170-[internal/jsonrpc2] | an implementation of the JSON RPC2 specification 2171- 2172-[gopls]: https://github.com/golang/tools/tree/master/gopls 2173-[internal/jsonrpc2]: https://github.com/golang/tools/tree/master/internal/jsonrpc2 2174-[internal/lsp]: https://github.com/golang/tools/tree/master/internal/lsp 2175-[internal/lsp/cache]: https://github.com/golang/tools/tree/master/internal/lsp/cache 2176-[internal/lsp/cmd]: https://github.com/golang/tools/tree/master/internal/lsp/cmd 2177-[internal/lsp/debug]: https://github.com/golang/tools/tree/master/internal/lsp/debug 2178-[internal/lsp/protocol]: https://github.com/golang/tools/tree/master/internal/lsp/protocol 2179-[internal/lsp/source]: https://github.com/golang/tools/tree/master/internal/lsp/source 2180-[internal/memoize]: https://github.com/golang/tools/tree/master/internal/memoize 2181-[internal/span]: https://github.com/golang/tools/tree/master/internal/span 2182-[x/tools]: https://github.com/golang/tools 2183diff -urN a/gopls/doc/design/integrating.md b/gopls/doc/design/integrating.md 2184--- a/gopls/doc/design/integrating.md 2000-01-01 00:00:00.000000000 -0000 2185+++ b/gopls/doc/design/integrating.md 1970-01-01 00:00:00.000000000 +0000 2186@@ -1,91 +0,0 @@ 2187-# Documentation for plugin authors 2188- 2189-If you are integrating `gopls` into an editor by writing an editor plugin, there are quite a few semantics of the communication between the editor and `gopls` that are not specified by the [LSP specification]. 2190- 2191-We attempt to document those details along with any other information that has been helpful to other plugin authors here. 2192- 2193-If you are implementing a plugin yourself and have questions this page does not answer, please reach out to us to ask, and then also contribute your findings back to this page. 2194- 2195-## Supported features 2196- 2197-For the most part you should look at the [list](status.md#supported-features) in the current status document to know if gopls supports a feature. 2198-For a truly authoritative answer you should check the [result][InitializeResult] of the [initialize] request, where gopls enumerates its support in the [ServerCapabilities]. 2199- 2200- 2201-## Positions and ranges 2202- 2203-Many LSP requests pass position or range information. This is described in the [LSP specification][lsp-text-documents]: 2204- 2205-> A position inside a document (see Position definition below) is expressed as a zero-based line and character offset. The offsets are based on a UTF-16 string representation. So a string of the form ab the character offset of the character a is 0, the character offset of is 1 and the character offset of b is 3 since is represented using two code units in UTF-16. 2206- 2207-This means that integrators will need to calculate UTF-16 based column offsets. 2208- 2209-[`golang.org/x/tools/gopls/internal/span`] has the code to do this in go. 2210-[#31080] tracks making `span` and other useful packages non-internal. 2211- 2212-## Edits 2213- 2214-In order to deliver changes from gopls to the editor, the LSP supports arrays of [`TextEdit`][lsp-textedit]s in responses. 2215-The spec specifies exactly how these should be applied: 2216- 2217-> All text edits ranges refer to positions in the original document. Text edits ranges must never overlap, that means no part of the original document must be manipulated by more than one edit. However, it is possible that multiple edits have the same start position: multiple inserts, or any number of inserts followed by a single remove or replace edit. If multiple inserts have the same position, the order in the array defines the order in which the inserted strings appear in the resulting text. 2218- 2219-All `[]TextEdit` are sorted such that applying the array of deltas received in reverse order achieves the desired result that holds with the spec. 2220- 2221-## Errors 2222- 2223-Various error codes are described in the [LSP specification][lsp-response]. We are still determining what it means for a method to return an error; are errors only for low-level LSP/transport issues or can other conditions cause errors to be returned? See some of this discussion on [#31526]. 2224- 2225-The method chosen is currently influenced by the exact treatment in the currently popular editor integrations. It may well change, and ideally would become more coherent across requests. 2226- 2227-* [`textDocument/codeAction`]: Return error if there was an error computing code actions. 2228-* [`textDocument/completion`]: Log errors, return empty result list. 2229-* [`textDocument/definition`]: Return error if there was an error computing the definition for the position. 2230-* [`textDocument/typeDefinition`]: Return error if there was an error computing the type definition for the position. 2231-* [`textDocument/formatting`]: Return error if there was an error formatting the file. 2232-* [`textDocument/highlight`]: Log errors, return empty result. 2233-* [`textDocument/hover`]: Return empty result. 2234-* [`textDocument/documentLink`]: Log errors, return nil result. 2235-* [`textDocument/publishDiagnostics`]: Log errors if there were any while computing diagnostics. 2236-* [`textDocument/references`]: Log errors, return empty result. 2237-* [`textDocument/rename`]: Return error if there was an error computing renames. 2238-* [`textDocument/signatureHelp`]: Log errors, return nil result. 2239-* [`textDocument/documentSymbols`]: Return error if there was an error computing document symbols. 2240- 2241-## Watching files 2242- 2243-It is fairly normal for files that affect `gopls` to be modified outside of the editor it is associated with. 2244- 2245-For instance, files that are needed to do correct type checking are modified by switching branches in git, or updated by a code generator. 2246- 2247-Monitoring files inside gopls directly has a lot of awkward problems, but the [LSP specification] has methods that allow gopls to request that the client notify it of file system changes, specifically [`workspace/didChangeWatchedFiles`]. 2248-This is currently being added to gopls by a community member, and tracked in [#31553] 2249- 2250-[InitializeResult]: https://pkg.go.dev/golang.org/x/tools/gopls/internal/lsp/protocol#InitializeResult 2251-[ServerCapabilities]: https://pkg.go.dev/golang.org/x/tools/gopls/internal/lsp/protocol#ServerCapabilities 2252-[`golang.org/x/tools/gopls/internal/span`]: https://pkg.go.dev/golang.org/x/tools/internal/span#NewPoint 2253- 2254-[LSP specification]: https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/ 2255-[lsp-response]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#response-message 2256-[initialize]: https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#initialize 2257-[lsp-text-documents]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#text-documents 2258-[lsp-textedit]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textedit 2259- 2260-[`textDocument/codeAction`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_codeAction 2261-[`textDocument/completion`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_completion 2262-[`textDocument/definition`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_definition 2263-[`textDocument/typeDefinition`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_typeDefinition 2264-[`textDocument/formatting`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_formatting 2265-[`textDocument/highlight`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_highlight 2266-[`textDocument/hover`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_hover 2267-[`textDocument/documentLink`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_documentLink 2268-[`textDocument/publishDiagnostics`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_publishDiagnostics 2269-[`textDocument/references`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_references 2270-[`textDocument/rename`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_rename 2271-[`textDocument/signatureHelp`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_signatureHelp 2272-[`textDocument/documentSymbols`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#textDocument_documentSymbols 2273-[`workspace/didChangeWatchedFiles`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#workspace_didChangeWatchedFiles 2274- 2275-[#31080]: https://github.com/golang/go/issues/31080 2276-[#31553]: https://github.com/golang/go/issues/31553 2277-[#31526]: https://github.com/golang/go/issues/31526 2278diff -urN a/gopls/doc/emacs.md b/gopls/doc/emacs.md 2279--- a/gopls/doc/emacs.md 2000-01-01 00:00:00.000000000 -0000 2280+++ b/gopls/doc/emacs.md 1970-01-01 00:00:00.000000000 +0000 2281@@ -1,183 +0,0 @@ 2282-# Emacs 2283- 2284-## Installing `gopls` 2285- 2286-To use `gopls` with Emacs, you must first 2287-[install the `gopls` binary](../README.md#installation) and ensure that the directory 2288-containing the resulting binary (either `$(go env GOBIN)` or `$(go env 2289-GOPATH)/bin`) is in your `PATH`. 2290- 2291-## Choosing an Emacs LSP client 2292- 2293-To use `gopls` with Emacs, you will need to choose and install an Emacs LSP 2294-client package. Two popular client packages are [LSP Mode] and [Eglot]. 2295- 2296-LSP Mode takes a batteries-included approach, with many integrations enabled 2297-“out of the box” and several additional behaviors provided by `lsp-mode` itself. 2298- 2299-Eglot takes a minimally-intrusive approach, focusing on smooth integration with 2300-other established packages. It provides a few of its own `eglot-` commands but 2301-no additional keybindings by default. 2302- 2303-Once you have selected which client you want to use, install it per the packages 2304-instructions: see [Eglot 1-2-3](https://github.com/joaotavora/eglot#1-2-3) or 2305-[LSP Mode Installation](https://emacs-lsp.github.io/lsp-mode/page/installation/). 2306- 2307-## Common configuration 2308- 2309-Both Eglot and LSP Mode can integrate with popular packages in the Emacs 2310-ecosystem: 2311- 2312-* The built-in [`xref`] package provides cross-references. 2313-* The built-in [Flymake] package provides an on-the-fly diagnostic overlay. 2314-* [Company] mode displays code completion candidates (with a richer UI than 2315- the built-in [`completion-at-point`]). 2316- 2317-Eglot provides documentation using the built-in [ElDoc] minor mode, while LSP 2318-Mode by default provides documentation using its own [`lsp-ui`] mode. 2319- 2320-Eglot by default locates the project root using the [`project`] package. In LSP 2321-Mode, this behavior can be configured using the `lsp-auto-guess-root` setting. 2322- 2323-## Configuring LSP Mode 2324- 2325-### Loading LSP Mode in `.emacs` 2326- 2327-```elisp 2328-(require 'lsp-mode) 2329-(add-hook 'go-mode-hook #'lsp-deferred) 2330- 2331-;; Set up before-save hooks to format buffer and add/delete imports. 2332-;; Make sure you don't have other gofmt/goimports hooks enabled. 2333-(defun lsp-go-install-save-hooks () 2334- (add-hook 'before-save-hook #'lsp-format-buffer t t) 2335- (add-hook 'before-save-hook #'lsp-organize-imports t t)) 2336-(add-hook 'go-mode-hook #'lsp-go-install-save-hooks) 2337-``` 2338- 2339-### Configuring `gopls` via LSP Mode 2340- 2341-See [settings] for information about available gopls settings. 2342- 2343-Stable gopls settings have corresponding configuration variables in `lsp-mode`. 2344-For example, `(setq lsp-gopls-use-placeholders nil)` will disable placeholders 2345-in completion snippets. See [`lsp-go`] for a list of available variables. 2346- 2347-Experimental settings can be configured via `lsp-register-custom-settings`: 2348- 2349-```lisp 2350-(lsp-register-custom-settings 2351- '(("gopls.completeUnimported" t t) 2352- ("gopls.staticcheck" t t))) 2353-``` 2354- 2355-Note that after changing settings you must restart gopls using e.g. `M-x 2356-lsp-restart-workspace`. 2357- 2358-## Configuring Eglot 2359- 2360-### Configuring `project` for Go modules in `.emacs` 2361- 2362-Eglot uses the built-in `project` package to identify the LSP workspace for a 2363-newly-opened buffer. The `project` package does not natively know about `GOPATH` 2364-or Go modules. Fortunately, you can give it a custom hook to tell it to look for 2365-the nearest parent `go.mod` file (that is, the root of the Go module) as the 2366-project root. 2367- 2368-```elisp 2369-(require 'project) 2370- 2371-(defun project-find-go-module (dir) 2372- (when-let ((root (locate-dominating-file dir "go.mod"))) 2373- (cons 'go-module root))) 2374- 2375-(cl-defmethod project-root ((project (head go-module))) 2376- (cdr project)) 2377- 2378-(add-hook 'project-find-functions #'project-find-go-module) 2379-``` 2380- 2381-### Loading Eglot in `.emacs` 2382- 2383-```elisp 2384-;; Optional: load other packages before eglot to enable eglot integrations. 2385-(require 'company) 2386-(require 'yasnippet) 2387- 2388-(require 'go-mode) 2389-(require 'eglot) 2390-(add-hook 'go-mode-hook 'eglot-ensure) 2391- 2392-;; Optional: install eglot-format-buffer as a save hook. 2393-;; The depth of -10 places this before eglot's willSave notification, 2394-;; so that that notification reports the actual contents that will be saved. 2395-(defun eglot-format-buffer-on-save () 2396- (add-hook 'before-save-hook #'eglot-format-buffer -10 t)) 2397-(add-hook 'go-mode-hook #'eglot-format-buffer-on-save) 2398-``` 2399- 2400-### Configuring `gopls` via Eglot 2401- 2402-See [settings] for information about available gopls settings. 2403- 2404-LSP server settings are controlled by the `eglot-workspace-configuration` 2405-variable, which can be set either globally in `.emacs` or in a `.dir-locals.el` file in the project root. 2406- 2407-`.emacs`: 2408-```elisp 2409-(setq-default eglot-workspace-configuration 2410- '((:gopls . 2411- ((staticcheck . t) 2412- (matcher . "CaseSensitive"))))) 2413-``` 2414- 2415-`.dir-locals.el`: 2416-```elisp 2417-((nil (eglot-workspace-configuration . ((gopls . ((staticcheck . t) 2418- (matcher . "CaseSensitive"))))))) 2419-``` 2420- 2421-### Organizing imports with Eglot 2422- 2423-`gopls` provides the import-organizing functionality of `goimports` as an LSP 2424-code action, which you can invoke as needed by running `M-x eglot-code-actions` 2425-(or a key of your choice bound to the `eglot-code-actions` function) and 2426-selecting `Organize Imports` at the prompt. 2427- 2428-Eglot does not currently support a standalone function to execute a specific 2429-code action (see 2430-[joaotavora/eglot#411](https://github.com/joaotavora/eglot/issues/411)), nor an 2431-option to organize imports as a `before-save-hook` (see 2432-[joaotavora/eglot#574](https://github.com/joaotavora/eglot/issues/574)). In the 2433-meantime, see those issues for discussion and possible workarounds. 2434- 2435-## Troubleshooting 2436- 2437-Common errors: 2438- 2439-* When prompted by Emacs for your project folder, if you are using modules you 2440- must select the module's root folder (i.e. the directory with the "go.mod"). 2441- If you are using GOPATH, select your $GOPATH as your folder. 2442-* Emacs must have your environment set properly (PATH, GOPATH, etc). You can 2443- run `M-x getenv <RET> PATH <RET>` to see if your PATH is set in Emacs. If 2444- not, you can try starting Emacs from your terminal, using [this 2445- package][exec-path-from-shell], or moving your shell config from `.bashrc` 2446- into `.profile` and logging out and back in. 2447-* Make sure only one LSP client mode is installed. (For example, if using 2448- `lsp-mode`, ensure that you are not _also_ enabling `eglot`.) 2449-* Look for errors in the `*lsp-log*` buffer or run `M-x eglot-events-buffer`. 2450-* Ask for help in the `#emacs` channel on the [Gophers slack]. 2451- 2452-[LSP Mode]: https://emacs-lsp.github.io/lsp-mode/ 2453-[Eglot]: https://github.com/joaotavora/eglot/blob/master/README.md 2454-[`xref`]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html 2455-[Flymake]: https://www.gnu.org/software/emacs/manual/html_node/flymake/Using-Flymake.html#Using-Flymake 2456-[Company]: https://company-mode.github.io/ 2457-[`completion-at-point`]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html 2458-[ElDoc]: https://elpa.gnu.org/packages/eldoc.html 2459-[`lsp-ui`]: https://emacs-lsp.github.io/lsp-ui/ 2460-[`lsp-go`]: https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-go.el 2461-[`use-package`]: https://github.com/jwiegley/use-package 2462-[`exec-path-from-shell`]: https://github.com/purcell/exec-path-from-shell 2463-[settings]: settings.md 2464-[Gophers slack]: https://invite.slack.golangbridge.org/ 2465diff -urN a/gopls/doc/features.md b/gopls/doc/features.md 2466--- a/gopls/doc/features.md 2000-01-01 00:00:00.000000000 -0000 2467+++ b/gopls/doc/features.md 1970-01-01 00:00:00.000000000 +0000 2468@@ -1,55 +0,0 @@ 2469-# Features 2470- 2471-This document describes some of the features supported by `gopls`. It is 2472-currently under construction, so, for a comprehensive list, see the 2473-[Language Server Protocol](https://microsoft.github.io/language-server-protocol/). 2474- 2475-## Special features 2476- 2477-Here, only special features outside of the LSP are described. 2478- 2479-### Symbol Queries 2480- 2481-Gopls supports some extended syntax for `workspace/symbol` requests, when using 2482-the `fuzzy` symbol matcher (the default). Inspired by the popular fuzzy matcher 2483-[FZF](https://github.com/junegunn/fzf), the following special characters are 2484-supported within symbol queries: 2485- 2486-| Character | Usage | Match | 2487-| --------- | --------- | ------------ | 2488-| `'` | `'abc` | exact | 2489-| `^` | `^printf` | exact prefix | 2490-| `$` | `printf$` | exact suffix | 2491- 2492-## Template Files 2493- 2494-Gopls provides some support for Go template files, that is, files that 2495-are parsed by `text/template` or `html/template`. 2496-Gopls recognizes template files based on their file extension, which may be 2497-configured by the 2498-[`templateExtensions`](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#templateextensions-string) setting. 2499-Making this list empty turns off template support. 2500- 2501-In template files, template support works inside 2502-the default `{{` delimiters. (Go template parsing 2503-allows the user to specify other delimiters, but 2504-gopls does not know how to do that.) 2505- 2506-Gopls template support includes the following features: 2507-+ **Diagnostics**: if template parsing returns an error, 2508-it is presented as a diagnostic. (Missing functions do not produce errors.) 2509-+ **Syntax Highlighting**: syntax highlighting is provided for template files. 2510-+ **Definitions**: gopls provides jump-to-definition inside templates, though it does not understand scoping (all templates are considered to be in one global scope). 2511-+ **References**: gopls provides find-references, with the same scoping limitation as definitions. 2512-+ **Completions**: gopls will attempt to suggest completions inside templates. 2513- 2514-### Configuring your editor 2515- 2516-In addition to configuring `templateExtensions`, you may need to configure your 2517-editor or LSP client to activate `gopls` for template files. For example, in 2518-`VS Code` you will need to configure both 2519-[`files.associations`](https://code.visualstudio.com/docs/languages/identifiers) 2520-and `build.templateExtensions` (the gopls setting). 2521- 2522-<!--TODO(rstambler): Automatically generate a list of supported features.--> 2523- 2524diff -urN a/gopls/doc/generate.go b/gopls/doc/generate.go 2525--- a/gopls/doc/generate.go 2000-01-01 00:00:00.000000000 -0000 2526+++ b/gopls/doc/generate.go 1970-01-01 00:00:00.000000000 +0000 2527@@ -1,778 +0,0 @@ 2528-// Copyright 2020 The Go Authors. All rights reserved. 2529-// Use of this source code is governed by a BSD-style 2530-// license that can be found in the LICENSE file. 2531- 2532-//go:build go1.16 2533-// +build go1.16 2534- 2535-// Command generate creates API (settings, etc) documentation in JSON and 2536-// Markdown for machine and human consumption. 2537-package main 2538- 2539-import ( 2540- "bytes" 2541- "encoding/json" 2542- "fmt" 2543- "go/ast" 2544- "go/format" 2545- "go/token" 2546- "go/types" 2547- "io" 2548- "io/ioutil" 2549- "os" 2550- "os/exec" 2551- "path/filepath" 2552- "reflect" 2553- "regexp" 2554- "sort" 2555- "strconv" 2556- "strings" 2557- "time" 2558- "unicode" 2559- 2560- "github.com/jba/printsrc" 2561- "golang.org/x/tools/go/ast/astutil" 2562- "golang.org/x/tools/go/packages" 2563- "golang.org/x/tools/gopls/internal/lsp/command" 2564- "golang.org/x/tools/gopls/internal/lsp/command/commandmeta" 2565- "golang.org/x/tools/gopls/internal/lsp/mod" 2566- "golang.org/x/tools/gopls/internal/lsp/safetoken" 2567- "golang.org/x/tools/gopls/internal/lsp/source" 2568-) 2569- 2570-func main() { 2571- if _, err := doMain(true); err != nil { 2572- fmt.Fprintf(os.Stderr, "Generation failed: %v\n", err) 2573- os.Exit(1) 2574- } 2575-} 2576- 2577-func doMain(write bool) (bool, error) { 2578- api, err := loadAPI() 2579- if err != nil { 2580- return false, err 2581- } 2582- 2583- sourceDir, err := pkgDir("golang.org/x/tools/gopls/internal/lsp/source") 2584- if err != nil { 2585- return false, err 2586- } 2587- 2588- if ok, err := rewriteFile(filepath.Join(sourceDir, "api_json.go"), api, write, rewriteAPI); !ok || err != nil { 2589- return ok, err 2590- } 2591- 2592- goplsDir, err := pkgDir("golang.org/x/tools/gopls") 2593- if err != nil { 2594- return false, err 2595- } 2596- 2597- if ok, err := rewriteFile(filepath.Join(goplsDir, "doc", "settings.md"), api, write, rewriteSettings); !ok || err != nil { 2598- return ok, err 2599- } 2600- if ok, err := rewriteFile(filepath.Join(goplsDir, "doc", "commands.md"), api, write, rewriteCommands); !ok || err != nil { 2601- return ok, err 2602- } 2603- if ok, err := rewriteFile(filepath.Join(goplsDir, "doc", "analyzers.md"), api, write, rewriteAnalyzers); !ok || err != nil { 2604- return ok, err 2605- } 2606- if ok, err := rewriteFile(filepath.Join(goplsDir, "doc", "inlayHints.md"), api, write, rewriteInlayHints); !ok || err != nil { 2607- return ok, err 2608- } 2609- 2610- return true, nil 2611-} 2612- 2613-// pkgDir returns the directory corresponding to the import path pkgPath. 2614-func pkgDir(pkgPath string) (string, error) { 2615- out, err := exec.Command("go", "list", "-f", "{{.Dir}}", pkgPath).Output() 2616- if err != nil { 2617- return "", err 2618- } 2619- return strings.TrimSpace(string(out)), nil 2620-} 2621- 2622-func loadAPI() (*source.APIJSON, error) { 2623- pkgs, err := packages.Load( 2624- &packages.Config{ 2625- Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedDeps, 2626- }, 2627- "golang.org/x/tools/gopls/internal/lsp/source", 2628- ) 2629- if err != nil { 2630- return nil, err 2631- } 2632- pkg := pkgs[0] 2633- 2634- api := &source.APIJSON{ 2635- Options: map[string][]*source.OptionJSON{}, 2636- } 2637- defaults := source.DefaultOptions() 2638- 2639- api.Commands, err = loadCommands(pkg) 2640- if err != nil { 2641- return nil, err 2642- } 2643- api.Lenses = loadLenses(api.Commands) 2644- 2645- // Transform the internal command name to the external command name. 2646- for _, c := range api.Commands { 2647- c.Command = command.ID(c.Command) 2648- } 2649- for _, m := range []map[string]*source.Analyzer{ 2650- defaults.DefaultAnalyzers, 2651- defaults.TypeErrorAnalyzers, 2652- defaults.ConvenienceAnalyzers, 2653- // Don't yet add staticcheck analyzers. 2654- } { 2655- api.Analyzers = append(api.Analyzers, loadAnalyzers(m)...) 2656- } 2657- api.Hints = loadHints(source.AllInlayHints) 2658- for _, category := range []reflect.Value{ 2659- reflect.ValueOf(defaults.UserOptions), 2660- } { 2661- // Find the type information and ast.File corresponding to the category. 2662- optsType := pkg.Types.Scope().Lookup(category.Type().Name()) 2663- if optsType == nil { 2664- return nil, fmt.Errorf("could not find %v in scope %v", category.Type().Name(), pkg.Types.Scope()) 2665- } 2666- opts, err := loadOptions(category, optsType, pkg, "") 2667- if err != nil { 2668- return nil, err 2669- } 2670- catName := strings.TrimSuffix(category.Type().Name(), "Options") 2671- api.Options[catName] = opts 2672- 2673- // Hardcode the expected values for the analyses and code lenses 2674- // settings, since their keys are not enums. 2675- for _, opt := range opts { 2676- switch opt.Name { 2677- case "analyses": 2678- for _, a := range api.Analyzers { 2679- opt.EnumKeys.Keys = append(opt.EnumKeys.Keys, source.EnumKey{ 2680- Name: fmt.Sprintf("%q", a.Name), 2681- Doc: a.Doc, 2682- Default: strconv.FormatBool(a.Default), 2683- }) 2684- } 2685- case "codelenses": 2686- // Hack: Lenses don't set default values, and we don't want to 2687- // pass in the list of expected lenses to loadOptions. Instead, 2688- // format the defaults using reflection here. The hackiest part 2689- // is reversing lowercasing of the field name. 2690- reflectField := category.FieldByName(upperFirst(opt.Name)) 2691- for _, l := range api.Lenses { 2692- def, err := formatDefaultFromEnumBoolMap(reflectField, l.Lens) 2693- if err != nil { 2694- return nil, err 2695- } 2696- opt.EnumKeys.Keys = append(opt.EnumKeys.Keys, source.EnumKey{ 2697- Name: fmt.Sprintf("%q", l.Lens), 2698- Doc: l.Doc, 2699- Default: def, 2700- }) 2701- } 2702- case "hints": 2703- for _, a := range api.Hints { 2704- opt.EnumKeys.Keys = append(opt.EnumKeys.Keys, source.EnumKey{ 2705- Name: fmt.Sprintf("%q", a.Name), 2706- Doc: a.Doc, 2707- Default: strconv.FormatBool(a.Default), 2708- }) 2709- } 2710- } 2711- } 2712- } 2713- return api, nil 2714-} 2715- 2716-func loadOptions(category reflect.Value, optsType types.Object, pkg *packages.Package, hierarchy string) ([]*source.OptionJSON, error) { 2717- file, err := fileForPos(pkg, optsType.Pos()) 2718- if err != nil { 2719- return nil, err 2720- } 2721- 2722- enums, err := loadEnums(pkg) 2723- if err != nil { 2724- return nil, err 2725- } 2726- 2727- var opts []*source.OptionJSON 2728- optsStruct := optsType.Type().Underlying().(*types.Struct) 2729- for i := 0; i < optsStruct.NumFields(); i++ { 2730- // The types field gives us the type. 2731- typesField := optsStruct.Field(i) 2732- 2733- // If the field name ends with "Options", assume it is a struct with 2734- // additional options and process it recursively. 2735- if h := strings.TrimSuffix(typesField.Name(), "Options"); h != typesField.Name() { 2736- // Keep track of the parent structs. 2737- if hierarchy != "" { 2738- h = hierarchy + "." + h 2739- } 2740- options, err := loadOptions(category, typesField, pkg, strings.ToLower(h)) 2741- if err != nil { 2742- return nil, err 2743- } 2744- opts = append(opts, options...) 2745- continue 2746- } 2747- path, _ := astutil.PathEnclosingInterval(file, typesField.Pos(), typesField.Pos()) 2748- if len(path) < 2 { 2749- return nil, fmt.Errorf("could not find AST node for field %v", typesField) 2750- } 2751- // The AST field gives us the doc. 2752- astField, ok := path[1].(*ast.Field) 2753- if !ok { 2754- return nil, fmt.Errorf("unexpected AST path %v", path) 2755- } 2756- 2757- // The reflect field gives us the default value. 2758- reflectField := category.FieldByName(typesField.Name()) 2759- if !reflectField.IsValid() { 2760- return nil, fmt.Errorf("could not find reflect field for %v", typesField.Name()) 2761- } 2762- 2763- def, err := formatDefault(reflectField) 2764- if err != nil { 2765- return nil, err 2766- } 2767- 2768- typ := typesField.Type().String() 2769- if _, ok := enums[typesField.Type()]; ok { 2770- typ = "enum" 2771- } 2772- name := lowerFirst(typesField.Name()) 2773- 2774- var enumKeys source.EnumKeys 2775- if m, ok := typesField.Type().(*types.Map); ok { 2776- e, ok := enums[m.Key()] 2777- if ok { 2778- typ = strings.Replace(typ, m.Key().String(), m.Key().Underlying().String(), 1) 2779- } 2780- keys, err := collectEnumKeys(name, m, reflectField, e) 2781- if err != nil { 2782- return nil, err 2783- } 2784- if keys != nil { 2785- enumKeys = *keys 2786- } 2787- } 2788- 2789- // Get the status of the field by checking its struct tags. 2790- reflectStructField, ok := category.Type().FieldByName(typesField.Name()) 2791- if !ok { 2792- return nil, fmt.Errorf("no struct field for %s", typesField.Name()) 2793- } 2794- status := reflectStructField.Tag.Get("status") 2795- 2796- opts = append(opts, &source.OptionJSON{ 2797- Name: name, 2798- Type: typ, 2799- Doc: lowerFirst(astField.Doc.Text()), 2800- Default: def, 2801- EnumKeys: enumKeys, 2802- EnumValues: enums[typesField.Type()], 2803- Status: status, 2804- Hierarchy: hierarchy, 2805- }) 2806- } 2807- return opts, nil 2808-} 2809- 2810-func loadEnums(pkg *packages.Package) (map[types.Type][]source.EnumValue, error) { 2811- enums := map[types.Type][]source.EnumValue{} 2812- for _, name := range pkg.Types.Scope().Names() { 2813- obj := pkg.Types.Scope().Lookup(name) 2814- cnst, ok := obj.(*types.Const) 2815- if !ok { 2816- continue 2817- } 2818- f, err := fileForPos(pkg, cnst.Pos()) 2819- if err != nil { 2820- return nil, fmt.Errorf("finding file for %q: %v", cnst.Name(), err) 2821- } 2822- path, _ := astutil.PathEnclosingInterval(f, cnst.Pos(), cnst.Pos()) 2823- spec := path[1].(*ast.ValueSpec) 2824- value := cnst.Val().ExactString() 2825- doc := valueDoc(cnst.Name(), value, spec.Doc.Text()) 2826- v := source.EnumValue{ 2827- Value: value, 2828- Doc: doc, 2829- } 2830- enums[obj.Type()] = append(enums[obj.Type()], v) 2831- } 2832- return enums, nil 2833-} 2834- 2835-func collectEnumKeys(name string, m *types.Map, reflectField reflect.Value, enumValues []source.EnumValue) (*source.EnumKeys, error) { 2836- // Make sure the value type gets set for analyses and codelenses 2837- // too. 2838- if len(enumValues) == 0 && !hardcodedEnumKeys(name) { 2839- return nil, nil 2840- } 2841- keys := &source.EnumKeys{ 2842- ValueType: m.Elem().String(), 2843- } 2844- // We can get default values for enum -> bool maps. 2845- var isEnumBoolMap bool 2846- if basic, ok := m.Elem().(*types.Basic); ok && basic.Kind() == types.Bool { 2847- isEnumBoolMap = true 2848- } 2849- for _, v := range enumValues { 2850- var def string 2851- if isEnumBoolMap { 2852- var err error 2853- def, err = formatDefaultFromEnumBoolMap(reflectField, v.Value) 2854- if err != nil { 2855- return nil, err 2856- } 2857- } 2858- keys.Keys = append(keys.Keys, source.EnumKey{ 2859- Name: v.Value, 2860- Doc: v.Doc, 2861- Default: def, 2862- }) 2863- } 2864- return keys, nil 2865-} 2866- 2867-func formatDefaultFromEnumBoolMap(reflectMap reflect.Value, enumKey string) (string, error) { 2868- if reflectMap.Kind() != reflect.Map { 2869- return "", nil 2870- } 2871- name := enumKey 2872- if unquoted, err := strconv.Unquote(name); err == nil { 2873- name = unquoted 2874- } 2875- for _, e := range reflectMap.MapKeys() { 2876- if e.String() == name { 2877- value := reflectMap.MapIndex(e) 2878- if value.Type().Kind() == reflect.Bool { 2879- return formatDefault(value) 2880- } 2881- } 2882- } 2883- // Assume that if the value isn't mentioned in the map, it defaults to 2884- // the default value, false. 2885- return formatDefault(reflect.ValueOf(false)) 2886-} 2887- 2888-// formatDefault formats the default value into a JSON-like string. 2889-// VS Code exposes settings as JSON, so showing them as JSON is reasonable. 2890-// TODO(rstambler): Reconsider this approach, as the VS Code Go generator now 2891-// marshals to JSON. 2892-func formatDefault(reflectField reflect.Value) (string, error) { 2893- def := reflectField.Interface() 2894- 2895- // Durations marshal as nanoseconds, but we want the stringy versions, 2896- // e.g. "100ms". 2897- if t, ok := def.(time.Duration); ok { 2898- def = t.String() 2899- } 2900- defBytes, err := json.Marshal(def) 2901- if err != nil { 2902- return "", err 2903- } 2904- 2905- // Nil values format as "null" so print them as hardcoded empty values. 2906- switch reflectField.Type().Kind() { 2907- case reflect.Map: 2908- if reflectField.IsNil() { 2909- defBytes = []byte("{}") 2910- } 2911- case reflect.Slice: 2912- if reflectField.IsNil() { 2913- defBytes = []byte("[]") 2914- } 2915- } 2916- return string(defBytes), err 2917-} 2918- 2919-// valueDoc transforms a docstring documenting an constant identifier to a 2920-// docstring documenting its value. 2921-// 2922-// If doc is of the form "Foo is a bar", it returns '`"fooValue"` is a bar'. If 2923-// doc is non-standard ("this value is a bar"), it returns '`"fooValue"`: this 2924-// value is a bar'. 2925-func valueDoc(name, value, doc string) string { 2926- if doc == "" { 2927- return "" 2928- } 2929- if strings.HasPrefix(doc, name) { 2930- // docstring in standard form. Replace the subject with value. 2931- return fmt.Sprintf("`%s`%s", value, doc[len(name):]) 2932- } 2933- return fmt.Sprintf("`%s`: %s", value, doc) 2934-} 2935- 2936-func loadCommands(pkg *packages.Package) ([]*source.CommandJSON, error) { 2937- var commands []*source.CommandJSON 2938- 2939- _, cmds, err := commandmeta.Load() 2940- if err != nil { 2941- return nil, err 2942- } 2943- // Parse the objects it contains. 2944- for _, cmd := range cmds { 2945- cmdjson := &source.CommandJSON{ 2946- Command: cmd.Name, 2947- Title: cmd.Title, 2948- Doc: cmd.Doc, 2949- ArgDoc: argsDoc(cmd.Args), 2950- } 2951- if cmd.Result != nil { 2952- cmdjson.ResultDoc = typeDoc(cmd.Result, 0) 2953- } 2954- commands = append(commands, cmdjson) 2955- } 2956- return commands, nil 2957-} 2958- 2959-func argsDoc(args []*commandmeta.Field) string { 2960- var b strings.Builder 2961- for i, arg := range args { 2962- b.WriteString(typeDoc(arg, 0)) 2963- if i != len(args)-1 { 2964- b.WriteString(",\n") 2965- } 2966- } 2967- return b.String() 2968-} 2969- 2970-func typeDoc(arg *commandmeta.Field, level int) string { 2971- // Max level to expand struct fields. 2972- const maxLevel = 3 2973- if len(arg.Fields) > 0 { 2974- if level < maxLevel { 2975- return arg.FieldMod + structDoc(arg.Fields, level) 2976- } 2977- return "{ ... }" 2978- } 2979- under := arg.Type.Underlying() 2980- switch u := under.(type) { 2981- case *types.Slice: 2982- return fmt.Sprintf("[]%s", u.Elem().Underlying().String()) 2983- } 2984- return types.TypeString(under, nil) 2985-} 2986- 2987-func structDoc(fields []*commandmeta.Field, level int) string { 2988- var b strings.Builder 2989- b.WriteString("{\n") 2990- indent := strings.Repeat("\t", level) 2991- for _, fld := range fields { 2992- if fld.Doc != "" && level == 0 { 2993- doclines := strings.Split(fld.Doc, "\n") 2994- for _, line := range doclines { 2995- fmt.Fprintf(&b, "%s\t// %s\n", indent, line) 2996- } 2997- } 2998- tag := strings.Split(fld.JSONTag, ",")[0] 2999- if tag == "" { 3000- tag = fld.Name 3001- } 3002- fmt.Fprintf(&b, "%s\t%q: %s,\n", indent, tag, typeDoc(fld, level+1)) 3003- } 3004- fmt.Fprintf(&b, "%s}", indent) 3005- return b.String() 3006-} 3007- 3008-func loadLenses(commands []*source.CommandJSON) []*source.LensJSON { 3009- all := map[command.Command]struct{}{} 3010- for k := range source.LensFuncs() { 3011- all[k] = struct{}{} 3012- } 3013- for k := range mod.LensFuncs() { 3014- if _, ok := all[k]; ok { 3015- panic(fmt.Sprintf("duplicate lens %q", string(k))) 3016- } 3017- all[k] = struct{}{} 3018- } 3019- 3020- var lenses []*source.LensJSON 3021- 3022- for _, cmd := range commands { 3023- if _, ok := all[command.Command(cmd.Command)]; ok { 3024- lenses = append(lenses, &source.LensJSON{ 3025- Lens: cmd.Command, 3026- Title: cmd.Title, 3027- Doc: cmd.Doc, 3028- }) 3029- } 3030- } 3031- return lenses 3032-} 3033- 3034-func loadAnalyzers(m map[string]*source.Analyzer) []*source.AnalyzerJSON { 3035- var sorted []string 3036- for _, a := range m { 3037- sorted = append(sorted, a.Analyzer.Name) 3038- } 3039- sort.Strings(sorted) 3040- var json []*source.AnalyzerJSON 3041- for _, name := range sorted { 3042- a := m[name] 3043- json = append(json, &source.AnalyzerJSON{ 3044- Name: a.Analyzer.Name, 3045- Doc: a.Analyzer.Doc, 3046- Default: a.Enabled, 3047- }) 3048- } 3049- return json 3050-} 3051- 3052-func loadHints(m map[string]*source.Hint) []*source.HintJSON { 3053- var sorted []string 3054- for _, h := range m { 3055- sorted = append(sorted, h.Name) 3056- } 3057- sort.Strings(sorted) 3058- var json []*source.HintJSON 3059- for _, name := range sorted { 3060- h := m[name] 3061- json = append(json, &source.HintJSON{ 3062- Name: h.Name, 3063- Doc: h.Doc, 3064- }) 3065- } 3066- return json 3067-} 3068- 3069-func lowerFirst(x string) string { 3070- if x == "" { 3071- return x 3072- } 3073- return strings.ToLower(x[:1]) + x[1:] 3074-} 3075- 3076-func upperFirst(x string) string { 3077- if x == "" { 3078- return x 3079- } 3080- return strings.ToUpper(x[:1]) + x[1:] 3081-} 3082- 3083-func fileForPos(pkg *packages.Package, pos token.Pos) (*ast.File, error) { 3084- fset := pkg.Fset 3085- for _, f := range pkg.Syntax { 3086- if safetoken.StartPosition(fset, f.Pos()).Filename == safetoken.StartPosition(fset, pos).Filename { 3087- return f, nil 3088- } 3089- } 3090- return nil, fmt.Errorf("no file for pos %v", pos) 3091-} 3092- 3093-func rewriteFile(file string, api *source.APIJSON, write bool, rewrite func([]byte, *source.APIJSON) ([]byte, error)) (bool, error) { 3094- old, err := ioutil.ReadFile(file) 3095- if err != nil { 3096- return false, err 3097- } 3098- 3099- new, err := rewrite(old, api) 3100- if err != nil { 3101- return false, fmt.Errorf("rewriting %q: %v", file, err) 3102- } 3103- 3104- if !write { 3105- return bytes.Equal(old, new), nil 3106- } 3107- 3108- if err := ioutil.WriteFile(file, new, 0); err != nil { 3109- return false, err 3110- } 3111- 3112- return true, nil 3113-} 3114- 3115-func rewriteAPI(_ []byte, api *source.APIJSON) ([]byte, error) { 3116- var buf bytes.Buffer 3117- fmt.Fprintf(&buf, "// Code generated by \"golang.org/x/tools/gopls/doc/generate\"; DO NOT EDIT.\n\npackage source\n\nvar GeneratedAPIJSON = ") 3118- if err := printsrc.NewPrinter("golang.org/x/tools/gopls/internal/lsp/source").Fprint(&buf, api); err != nil { 3119- return nil, err 3120- } 3121- return format.Source(buf.Bytes()) 3122-} 3123- 3124-type optionsGroup struct { 3125- title string 3126- final string 3127- level int 3128- options []*source.OptionJSON 3129-} 3130- 3131-func rewriteSettings(doc []byte, api *source.APIJSON) ([]byte, error) { 3132- result := doc 3133- for category, opts := range api.Options { 3134- groups := collectGroups(opts) 3135- 3136- // First, print a table of contents. 3137- section := bytes.NewBuffer(nil) 3138- fmt.Fprintln(section, "") 3139- for _, h := range groups { 3140- writeBullet(section, h.final, h.level) 3141- } 3142- fmt.Fprintln(section, "") 3143- 3144- // Currently, the settings document has a title and a subtitle, so 3145- // start at level 3 for a header beginning with "###". 3146- baseLevel := 3 3147- for _, h := range groups { 3148- level := baseLevel + h.level 3149- writeTitle(section, h.final, level) 3150- for _, opt := range h.options { 3151- header := strMultiply("#", level+1) 3152- fmt.Fprintf(section, "%s ", header) 3153- opt.Write(section) 3154- } 3155- } 3156- var err error 3157- result, err = replaceSection(result, category, section.Bytes()) 3158- if err != nil { 3159- return nil, err 3160- } 3161- } 3162- 3163- section := bytes.NewBuffer(nil) 3164- for _, lens := range api.Lenses { 3165- fmt.Fprintf(section, "### **%v**\n\nIdentifier: `%v`\n\n%v\n", lens.Title, lens.Lens, lens.Doc) 3166- } 3167- return replaceSection(result, "Lenses", section.Bytes()) 3168-} 3169- 3170-func collectGroups(opts []*source.OptionJSON) []optionsGroup { 3171- optsByHierarchy := map[string][]*source.OptionJSON{} 3172- for _, opt := range opts { 3173- optsByHierarchy[opt.Hierarchy] = append(optsByHierarchy[opt.Hierarchy], opt) 3174- } 3175- 3176- // As a hack, assume that uncategorized items are less important to 3177- // users and force the empty string to the end of the list. 3178- var containsEmpty bool 3179- var sorted []string 3180- for h := range optsByHierarchy { 3181- if h == "" { 3182- containsEmpty = true 3183- continue 3184- } 3185- sorted = append(sorted, h) 3186- } 3187- sort.Strings(sorted) 3188- if containsEmpty { 3189- sorted = append(sorted, "") 3190- } 3191- var groups []optionsGroup 3192- baseLevel := 0 3193- for _, h := range sorted { 3194- split := strings.SplitAfter(h, ".") 3195- last := split[len(split)-1] 3196- // Hack to capitalize all of UI. 3197- if last == "ui" { 3198- last = "UI" 3199- } 3200- // A hierarchy may look like "ui.formatting". If "ui" has no 3201- // options of its own, it may not be added to the map, but it 3202- // still needs a heading. 3203- components := strings.Split(h, ".") 3204- for i := 1; i < len(components); i++ { 3205- parent := strings.Join(components[0:i], ".") 3206- if _, ok := optsByHierarchy[parent]; !ok { 3207- groups = append(groups, optionsGroup{ 3208- title: parent, 3209- final: last, 3210- level: baseLevel + i, 3211- }) 3212- } 3213- } 3214- groups = append(groups, optionsGroup{ 3215- title: h, 3216- final: last, 3217- level: baseLevel + strings.Count(h, "."), 3218- options: optsByHierarchy[h], 3219- }) 3220- } 3221- return groups 3222-} 3223- 3224-func hardcodedEnumKeys(name string) bool { 3225- return name == "analyses" || name == "codelenses" 3226-} 3227- 3228-func writeBullet(w io.Writer, title string, level int) { 3229- if title == "" { 3230- return 3231- } 3232- // Capitalize the first letter of each title. 3233- prefix := strMultiply(" ", level) 3234- fmt.Fprintf(w, "%s* [%s](#%s)\n", prefix, capitalize(title), strings.ToLower(title)) 3235-} 3236- 3237-func writeTitle(w io.Writer, title string, level int) { 3238- if title == "" { 3239- return 3240- } 3241- // Capitalize the first letter of each title. 3242- fmt.Fprintf(w, "%s %s\n\n", strMultiply("#", level), capitalize(title)) 3243-} 3244- 3245-func capitalize(s string) string { 3246- return string(unicode.ToUpper(rune(s[0]))) + s[1:] 3247-} 3248- 3249-func strMultiply(str string, count int) string { 3250- var result string 3251- for i := 0; i < count; i++ { 3252- result += string(str) 3253- } 3254- return result 3255-} 3256- 3257-func rewriteCommands(doc []byte, api *source.APIJSON) ([]byte, error) { 3258- section := bytes.NewBuffer(nil) 3259- for _, command := range api.Commands { 3260- command.Write(section) 3261- } 3262- return replaceSection(doc, "Commands", section.Bytes()) 3263-} 3264- 3265-func rewriteAnalyzers(doc []byte, api *source.APIJSON) ([]byte, error) { 3266- section := bytes.NewBuffer(nil) 3267- for _, analyzer := range api.Analyzers { 3268- fmt.Fprintf(section, "## **%v**\n\n", analyzer.Name) 3269- fmt.Fprintf(section, "%s\n\n", analyzer.Doc) 3270- switch analyzer.Default { 3271- case true: 3272- fmt.Fprintf(section, "**Enabled by default.**\n\n") 3273- case false: 3274- fmt.Fprintf(section, "**Disabled by default. Enable it by setting `\"analyses\": {\"%s\": true}`.**\n\n", analyzer.Name) 3275- } 3276- } 3277- return replaceSection(doc, "Analyzers", section.Bytes()) 3278-} 3279- 3280-func rewriteInlayHints(doc []byte, api *source.APIJSON) ([]byte, error) { 3281- section := bytes.NewBuffer(nil) 3282- for _, hint := range api.Hints { 3283- fmt.Fprintf(section, "## **%v**\n\n", hint.Name) 3284- fmt.Fprintf(section, "%s\n\n", hint.Doc) 3285- switch hint.Default { 3286- case true: 3287- fmt.Fprintf(section, "**Enabled by default.**\n\n") 3288- case false: 3289- fmt.Fprintf(section, "**Disabled by default. Enable it by setting `\"hints\": {\"%s\": true}`.**\n\n", hint.Name) 3290- } 3291- } 3292- return replaceSection(doc, "Hints", section.Bytes()) 3293-} 3294- 3295-func replaceSection(doc []byte, sectionName string, replacement []byte) ([]byte, error) { 3296- re := regexp.MustCompile(fmt.Sprintf(`(?s)<!-- BEGIN %v.* -->\n(.*?)<!-- END %v.* -->`, sectionName, sectionName)) 3297- idx := re.FindSubmatchIndex(doc) 3298- if idx == nil { 3299- return nil, fmt.Errorf("could not find section %q", sectionName) 3300- } 3301- result := append([]byte(nil), doc[:idx[2]]...) 3302- result = append(result, replacement...) 3303- result = append(result, doc[idx[3]:]...) 3304- return result, nil 3305-} 3306diff -urN a/gopls/doc/generate_test.go b/gopls/doc/generate_test.go 3307--- a/gopls/doc/generate_test.go 2000-01-01 00:00:00.000000000 -0000 3308+++ b/gopls/doc/generate_test.go 1970-01-01 00:00:00.000000000 +0000 3309@@ -1,26 +0,0 @@ 3310-// Copyright 2020 The Go Authors. All rights reserved. 3311-// Use of this source code is governed by a BSD-style 3312-// license that can be found in the LICENSE file. 3313- 3314-package main 3315- 3316-import ( 3317- "testing" 3318- 3319- "golang.org/x/tools/internal/testenv" 3320-) 3321- 3322-func TestGenerated(t *testing.T) { 3323- // This test fails on 1.18 Kokoro for unknown reasons; in any case, it 3324- // suffices to run this test on any builder. 3325- testenv.NeedsGo1Point(t, 19) 3326- testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code. 3327- 3328- ok, err := doMain(false) 3329- if err != nil { 3330- t.Fatal(err) 3331- } 3332- if !ok { 3333- t.Error("documentation needs updating. run: `go run doc/generate.go` from the gopls module.") 3334- } 3335-} 3336diff -urN a/gopls/doc/inlayHints.md b/gopls/doc/inlayHints.md 3337--- a/gopls/doc/inlayHints.md 2000-01-01 00:00:00.000000000 -0000 3338+++ b/gopls/doc/inlayHints.md 1970-01-01 00:00:00.000000000 +0000 3339@@ -1,80 +0,0 @@ 3340-# Hints 3341- 3342-This document describes the inlay hints that `gopls` uses inside the editor. 3343- 3344-<!-- BEGIN Hints: DO NOT MANUALLY EDIT THIS SECTION --> 3345-## **assignVariableTypes** 3346- 3347-Enable/disable inlay hints for variable types in assign statements: 3348-```go 3349- i/* int*/, j/* int*/ := 0, len(r)-1 3350-``` 3351- 3352-**Disabled by default. Enable it by setting `"hints": {"assignVariableTypes": true}`.** 3353- 3354-## **compositeLiteralFields** 3355- 3356-Enable/disable inlay hints for composite literal field names: 3357-```go 3358- {/*in: */"Hello, world", /*want: */"dlrow ,olleH"} 3359-``` 3360- 3361-**Disabled by default. Enable it by setting `"hints": {"compositeLiteralFields": true}`.** 3362- 3363-## **compositeLiteralTypes** 3364- 3365-Enable/disable inlay hints for composite literal types: 3366-```go 3367- for _, c := range []struct { 3368- in, want string 3369- }{ 3370- /*struct{ in string; want string }*/{"Hello, world", "dlrow ,olleH"}, 3371- } 3372-``` 3373- 3374-**Disabled by default. Enable it by setting `"hints": {"compositeLiteralTypes": true}`.** 3375- 3376-## **constantValues** 3377- 3378-Enable/disable inlay hints for constant values: 3379-```go 3380- const ( 3381- KindNone Kind = iota/* = 0*/ 3382- KindPrint/* = 1*/ 3383- KindPrintf/* = 2*/ 3384- KindErrorf/* = 3*/ 3385- ) 3386-``` 3387- 3388-**Disabled by default. Enable it by setting `"hints": {"constantValues": true}`.** 3389- 3390-## **functionTypeParameters** 3391- 3392-Enable/disable inlay hints for implicit type parameters on generic functions: 3393-```go 3394- myFoo/*[int, string]*/(1, "hello") 3395-``` 3396- 3397-**Disabled by default. Enable it by setting `"hints": {"functionTypeParameters": true}`.** 3398- 3399-## **parameterNames** 3400- 3401-Enable/disable inlay hints for parameter names: 3402-```go 3403- parseInt(/* str: */ "123", /* radix: */ 8) 3404-``` 3405- 3406-**Disabled by default. Enable it by setting `"hints": {"parameterNames": true}`.** 3407- 3408-## **rangeVariableTypes** 3409- 3410-Enable/disable inlay hints for variable types in range statements: 3411-```go 3412- for k/* int*/, v/* string*/ := range []string{} { 3413- fmt.Println(k, v) 3414- } 3415-``` 3416- 3417-**Disabled by default. Enable it by setting `"hints": {"rangeVariableTypes": true}`.** 3418- 3419-<!-- END Hints: DO NOT MANUALLY EDIT THIS SECTION --> 3420diff -urN a/gopls/doc/releases.md b/gopls/doc/releases.md 3421--- a/gopls/doc/releases.md 2000-01-01 00:00:00.000000000 -0000 3422+++ b/gopls/doc/releases.md 1970-01-01 00:00:00.000000000 +0000 3423@@ -1,25 +0,0 @@ 3424-# Gopls release policy 3425- 3426-Gopls releases follow [semver](http://semver.org), with major changes and new 3427-features introduced only in new minor versions (i.e. versions of the form 3428-`v*.N.0` for some N). Subsequent patch releases contain only cherry-picked 3429-fixes or superficial updates. 3430- 3431-In order to align with the 3432-[Go release timeline](https://github.com/golang/go/wiki/Go-Release-Cycle#timeline), 3433-we aim to release a new minor version of Gopls approximately every three 3434-months, with patch releases approximately every month, according to the 3435-following table: 3436- 3437-| Month | Version(s) | 3438-| ---- | ------- | 3439-| Jan | `v*.<N+0>.0` | 3440-| Jan-Mar | `v*.<N+0>.*` | 3441-| Apr | `v*.<N+1>.0` | 3442-| Apr-Jun | `v*.<N+1>.*` | 3443-| Jul | `v*.<N+2>.0` | 3444-| Jul-Sep | `v*.<N+2>.*` | 3445-| Oct | `v*.<N+3>.0` | 3446-| Oct-Dec | `v*.<N+3>.*` | 3447- 3448-For more background on this policy, see https://go.dev/issue/55267. 3449diff -urN a/gopls/doc/semantictokens.md b/gopls/doc/semantictokens.md 3450--- a/gopls/doc/semantictokens.md 2000-01-01 00:00:00.000000000 -0000 3451+++ b/gopls/doc/semantictokens.md 1970-01-01 00:00:00.000000000 +0000 3452@@ -1,121 +0,0 @@ 3453-# Semantic Tokens 3454- 3455-The [LSP](https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocument_semanticTokens) 3456-specifies semantic tokens as a way of telling clients about language-specific 3457-properties of pieces of code in a file being edited. 3458- 3459-The client asks for a set of semantic tokens and modifiers. This note describe which ones 3460-gopls will return, and under what circumstances. Gopls has no control over how the client 3461-converts semantic tokens into colors (or some other visible indication). In vscode it 3462-is possible to modify the color a theme uses by setting the `editor.semanticTokenColorCustomizations` 3463-object. We provide a little [guidance](#Colors) later. 3464- 3465-There are 22 semantic tokens, with 10 possible modifiers. The protocol allows each semantic 3466-token to be used with any of the 1024 subsets of possible modifiers, but most combinations 3467-don't make intuitive sense (although `async documentation` has a certain appeal). 3468- 3469-The 22 semantic tokens are `namespace`, `type`, `class`, `enum`, `interface`, 3470- `struct`, `typeParameter`, `parameter`, `variable`, `property`, `enumMember`, 3471- `event`, `function`, `method`, `macro`, `keyword`, `modifier`, `comment`, 3472- `string`, `number`, `regexp`, `operator`. 3473- 3474-The 10 modifiers are `declaration`, `definition`, `readonly`, `static`, 3475- `deprecated`, `abstract`, `async`, `modification`, `documentation`, `defaultLibrary`. 3476- 3477-The authoritative lists are in the [specification](https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#semanticTokenTypes) 3478- 3479-For the implementation to work correctly the client and server have to agree on the ordering 3480-of the tokens and of the modifiers. Gopls, therefore, will only send tokens and modifiers 3481-that the client has asked for. This document says what gopls would send if the client 3482-asked for everything. By default, vscode asks for everything. 3483- 3484-Gopls sends 11 token types for `.go` files and 1 for `.*tmpl` files. 3485-Nothing is sent for any other kind of file. 3486-This all could change. (When Go has generics, gopls will return `typeParameter`.) 3487- 3488-For `.*tmpl` files gopls sends `macro`, and no modifiers, for each `{{`...`}}` scope. 3489- 3490-## Semantic tokens for Go files 3491- 3492-There are two contrasting guiding principles that might be used to decide what to mark 3493-with semantic tokens. All clients already do some kind of syntax marking. E.g., vscode 3494-uses a TextMate grammar. The minimal principle would send semantic tokens only for those 3495-language features that cannot be reliably found without parsing Go and looking at types. 3496-The maximal principle would attempt to convey as much as possible about the Go code, 3497-using all available parsing and type information. 3498- 3499-There is much to be said for returning minimal information, but the minimal principle is 3500-not well-specified. Gopls has no way of knowing what the clients know about the Go program 3501-being edited. Even in vscode the TextMate grammars can be more or less elaborate 3502-and change over time. (Nonetheless, a minimal implementation would not return `keyword`, 3503-`number`, `comment`, or `string`.) 3504- 3505-The maximal position isn't particularly well-specified either. To chose one example, a 3506-format string might have formatting codes (`%[4]-3.6f`), escape sequences (`\U00010604`), and regular 3507-characters. Should these all be distinguished? One could even imagine distinguishing 3508-different runes by their Unicode language assignment, or some other Unicode property, such as 3509-being [confusable](http://www.unicode.org/Public/security/10.0.0/confusables.txt). 3510- 3511-Gopls does not come close to either of these principles. Semantic tokens are returned for 3512-identifiers, keywords, operators, comments, and literals. (Semantic tokens do not 3513-cover the file. They are not returned for 3514-white space or punctuation, and there is no semantic token for labels.) 3515-The following describes more precisely what gopls 3516-does, with a few notes on possible alternative choices. 3517-The references to *object* refer to the 3518-```types.Object``` returned by the type checker. The references to *nodes* refer to the 3519-```ast.Node``` from the parser. 3520- 3521-1. __`keyword`__ All Go [keywords](https://golang.org/ref/spec#Keywords) are marked `keyword`. 3522-1. __`namespace`__ All package names are marked `namespace`. In an import, if there is an 3523-alias, it would be marked. Otherwise the last component of the import path is marked. 3524-1. __`type`__ Objects of type ```types.TypeName``` are marked `type`. 3525-If they are also ```types.Basic``` 3526-the modifier is `defaultLibrary`. (And in ```type B struct{C}```, ```B``` has modifier `definition`.) 3527-1. __`parameter`__ The formal arguments in ```ast.FuncDecl``` and ```ast.FuncType``` nodes are marked `parameter`. 3528-1. __`variable`__ Identifiers in the 3529-scope of ```const``` are modified with `readonly`. ```nil``` is usually a `variable` modified with both 3530-`readonly` and `defaultLibrary`. (```nil``` is a predefined identifier; the user can redefine it, 3531-in which case it would just be a variable, or whatever.) Identifiers of type ```types.Variable``` are, 3532-not surprisingly, marked `variable`. Identifiers being defined (node ```ast.GenDecl```) are modified 3533-by `definition` and, if appropriate, `readonly`. Receivers (in method declarations) are 3534-`variable`. 3535-1. __`method`__ Methods are marked at their definition (```func (x foo) bar() {}```) or declaration 3536-in an ```interface```. Methods are not marked where they are used. 3537-In ```x.bar()```, ```x``` will be marked 3538-either as a `namespace` if it is a package name, or as a `variable` if it is an interface value, 3539-so distinguishing ```bar``` seemed superfluous. 3540-1. __`function`__ Bultins (```types.Builtin```) are modified with `defaultLibrary` 3541-(e.g., ```make```, ```len```, ```copy```). Identifiers whose 3542-object is ```types.Func``` or whose node is ```ast.FuncDecl``` are `function`. 3543-1. __`comment`__ Comments and struct tags. (Perhaps struct tags should be `property`?) 3544-1. __`string`__ Strings. Could add modifiers for e.g., escapes or format codes. 3545-1. __`number`__ Numbers. Should the ```i``` in ```23i``` be handled specially? 3546-1. __`operator`__ Assignment operators, binary operators, ellipses (```...```), increment/decrement 3547-operators, sends (```<-```), and unary operators. 3548- 3549-Gopls will send the modifier `deprecated` if it finds a comment 3550-```// deprecated``` in the godoc. 3551- 3552-The unused tokens for Go code are `class`, `enum`, `interface`, 3553- `struct`, `typeParameter`, `property`, `enumMember`, 3554- `event`, `macro`, `modifier`, 3555- `regexp` 3556- 3557-## Colors 3558- 3559-These comments are about vscode. 3560- 3561-The documentation has a [helpful](https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#custom-textmate-scope-mappings) 3562-description of which semantic tokens correspond to scopes in TextMate grammars. Themes seem 3563-to use the TextMate scopes to decide on colors. 3564- 3565-Some examples of color customizations are [here](https://medium.com/@danromans/how-to-customize-semantic-token-colorization-with-visual-studio-code-ac3eab96141b). 3566- 3567-## Note 3568- 3569-While a file is being edited it may temporarily contain either 3570-parsing errors or type errors. In this case gopls cannot determine some (or maybe any) 3571-of the semantic tokens. To avoid weird flickering it is the responsibility 3572-of clients to maintain the semantic token information 3573-in the unedited part of the file, and they do. 3574\ No newline at end of file 3575diff -urN a/gopls/doc/settings.md b/gopls/doc/settings.md 3576--- a/gopls/doc/settings.md 2000-01-01 00:00:00.000000000 -0000 3577+++ b/gopls/doc/settings.md 1970-01-01 00:00:00.000000000 +0000 3578@@ -1,527 +0,0 @@ 3579-# Settings 3580- 3581-<!--TODO: Generate this file from the documentation in golang.org/x/tools/gopls/internal/lsp/source/options.go.--> 3582- 3583-This document describes the global settings for `gopls` inside the editor. 3584-The settings block will be called `"gopls"` and contains a collection of 3585-controls for `gopls` that the editor is not expected to understand or control. 3586-These settings can also be configured differently per workspace folder. 3587- 3588-In VSCode, this would be a section in your `settings.json` file that might look 3589-like this: 3590- 3591-```json5 3592- "gopls": { 3593- "ui.completion.usePlaceholders": true, 3594- ... 3595- }, 3596-``` 3597- 3598-## Officially supported 3599- 3600-Below is the list of settings that are officially supported for `gopls`. 3601- 3602-Any settings that are experimental or for debugging purposes are marked as 3603-such. 3604- 3605-To enable all experimental features, use **allExperiments: `true`**. You will 3606-still be able to independently override specific experimental features. 3607- 3608-<!-- BEGIN User: DO NOT MANUALLY EDIT THIS SECTION --> 3609- 3610-* [Build](#build) 3611-* [Formatting](#formatting) 3612-* [UI](#ui) 3613- * [Completion](#completion) 3614- * [Diagnostic](#diagnostic) 3615- * [Documentation](#documentation) 3616- * [Inlayhint](#inlayhint) 3617- * [Navigation](#navigation) 3618- 3619-### Build 3620- 3621-#### **buildFlags** *[]string* 3622- 3623-buildFlags is the set of flags passed on to the build system when invoked. 3624-It is applied to queries like `go list`, which is used when discovering files. 3625-The most common use is to set `-tags`. 3626- 3627-Default: `[]`. 3628- 3629-#### **env** *map[string]string* 3630- 3631-env adds environment variables to external commands run by `gopls`, most notably `go list`. 3632- 3633-Default: `{}`. 3634- 3635-#### **directoryFilters** *[]string* 3636- 3637-directoryFilters can be used to exclude unwanted directories from the 3638-workspace. By default, all directories are included. Filters are an 3639-operator, `+` to include and `-` to exclude, followed by a path prefix 3640-relative to the workspace folder. They are evaluated in order, and 3641-the last filter that applies to a path controls whether it is included. 3642-The path prefix can be empty, so an initial `-` excludes everything. 3643- 3644-DirectoryFilters also supports the `**` operator to match 0 or more directories. 3645- 3646-Examples: 3647- 3648-Exclude node_modules at current depth: `-node_modules` 3649- 3650-Exclude node_modules at any depth: `-**/node_modules` 3651- 3652-Include only project_a: `-` (exclude everything), `+project_a` 3653- 3654-Include only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules` 3655- 3656-Default: `["-**/node_modules"]`. 3657- 3658-#### **templateExtensions** *[]string* 3659- 3660-templateExtensions gives the extensions of file names that are treateed 3661-as template files. (The extension 3662-is the part of the file name after the final dot.) 3663- 3664-Default: `[]`. 3665- 3666-#### **memoryMode** *enum* 3667- 3668-**This setting is experimental and may be deleted.** 3669- 3670-memoryMode controls the tradeoff `gopls` makes between memory usage and 3671-correctness. 3672- 3673-Values other than `Normal` are untested and may break in surprising ways. 3674- 3675-Must be one of: 3676- 3677-* `"DegradeClosed"`: In DegradeClosed mode, `gopls` will collect less information about 3678-packages without open files. As a result, features like Find 3679-References and Rename will miss results in such packages. 3680-* `"Normal"` 3681- 3682-Default: `"Normal"`. 3683- 3684-#### **expandWorkspaceToModule** *bool* 3685- 3686-**This setting is experimental and may be deleted.** 3687- 3688-expandWorkspaceToModule instructs `gopls` to adjust the scope of the 3689-workspace to find the best available module root. `gopls` first looks for 3690-a go.mod file in any parent directory of the workspace folder, expanding 3691-the scope to that directory if it exists. If no viable parent directory is 3692-found, gopls will check if there is exactly one child directory containing 3693-a go.mod file, narrowing the scope to that directory if it exists. 3694- 3695-Default: `true`. 3696- 3697-#### **allowModfileModifications** *bool* 3698- 3699-**This setting is experimental and may be deleted.** 3700- 3701-allowModfileModifications disables -mod=readonly, allowing imports from 3702-out-of-scope modules. This option will eventually be removed. 3703- 3704-Default: `false`. 3705- 3706-#### **allowImplicitNetworkAccess** *bool* 3707- 3708-**This setting is experimental and may be deleted.** 3709- 3710-allowImplicitNetworkAccess disables GOPROXY=off, allowing implicit module 3711-downloads rather than requiring user action. This option will eventually 3712-be removed. 3713- 3714-Default: `false`. 3715- 3716-#### **standaloneTags** *[]string* 3717- 3718-standaloneTags specifies a set of build constraints that identify 3719-individual Go source files that make up the entire main package of an 3720-executable. 3721- 3722-A common example of standalone main files is the convention of using the 3723-directive `//go:build ignore` to denote files that are not intended to be 3724-included in any package, for example because they are invoked directly by 3725-the developer using `go run`. 3726- 3727-Gopls considers a file to be a standalone main file if and only if it has 3728-package name "main" and has a build directive of the exact form 3729-"//go:build tag" or "// +build tag", where tag is among the list of tags 3730-configured by this setting. Notably, if the build constraint is more 3731-complicated than a simple tag (such as the composite constraint 3732-`//go:build tag && go1.18`), the file is not considered to be a standalone 3733-main file. 3734- 3735-This setting is only supported when gopls is built with Go 1.16 or later. 3736- 3737-Default: `["ignore"]`. 3738- 3739-### Formatting 3740- 3741-#### **local** *string* 3742- 3743-local is the equivalent of the `goimports -local` flag, which puts 3744-imports beginning with this string after third-party packages. It should 3745-be the prefix of the import path whose imports should be grouped 3746-separately. 3747- 3748-Default: `""`. 3749- 3750-#### **gofumpt** *bool* 3751- 3752-gofumpt indicates if we should run gofumpt formatting. 3753- 3754-Default: `false`. 3755- 3756-### UI 3757- 3758-#### **codelenses** *map[string]bool* 3759- 3760-codelenses overrides the enabled/disabled state of code lenses. See the 3761-"Code Lenses" section of the 3762-[Settings page](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#code-lenses) 3763-for the list of supported lenses. 3764- 3765-Example Usage: 3766- 3767-```json5 3768-"gopls": { 3769-... 3770- "codelenses": { 3771- "generate": false, // Don't show the `go generate` lens. 3772- "gc_details": true // Show a code lens toggling the display of gc's choices. 3773- } 3774-... 3775-} 3776-``` 3777- 3778-Default: `{"gc_details":false,"generate":true,"regenerate_cgo":true,"tidy":true,"upgrade_dependency":true,"vendor":true}`. 3779- 3780-#### **semanticTokens** *bool* 3781- 3782-**This setting is experimental and may be deleted.** 3783- 3784-semanticTokens controls whether the LSP server will send 3785-semantic tokens to the client. 3786- 3787-Default: `false`. 3788- 3789-#### **noSemanticString** *bool* 3790- 3791-**This setting is experimental and may be deleted.** 3792- 3793-noSemanticString turns off the sending of the semantic token 'string' 3794- 3795-Default: `false`. 3796- 3797-#### **noSemanticNumber** *bool* 3798- 3799-**This setting is experimental and may be deleted.** 3800- 3801-noSemanticNumber turns off the sending of the semantic token 'number' 3802- 3803-Default: `false`. 3804- 3805-#### Completion 3806- 3807-##### **usePlaceholders** *bool* 3808- 3809-placeholders enables placeholders for function parameters or struct 3810-fields in completion responses. 3811- 3812-Default: `false`. 3813- 3814-##### **completionBudget** *time.Duration* 3815- 3816-**This setting is for debugging purposes only.** 3817- 3818-completionBudget is the soft latency goal for completion requests. Most 3819-requests finish in a couple milliseconds, but in some cases deep 3820-completions can take much longer. As we use up our budget we 3821-dynamically reduce the search scope to ensure we return timely 3822-results. Zero means unlimited. 3823- 3824-Default: `"100ms"`. 3825- 3826-##### **matcher** *enum* 3827- 3828-**This is an advanced setting and should not be configured by most `gopls` users.** 3829- 3830-matcher sets the algorithm that is used when calculating completion 3831-candidates. 3832- 3833-Must be one of: 3834- 3835-* `"CaseInsensitive"` 3836-* `"CaseSensitive"` 3837-* `"Fuzzy"` 3838- 3839-Default: `"Fuzzy"`. 3840- 3841-##### **experimentalPostfixCompletions** *bool* 3842- 3843-**This setting is experimental and may be deleted.** 3844- 3845-experimentalPostfixCompletions enables artificial method snippets 3846-such as "someSlice.sort!". 3847- 3848-Default: `true`. 3849- 3850-#### Diagnostic 3851- 3852-##### **analyses** *map[string]bool* 3853- 3854-analyses specify analyses that the user would like to enable or disable. 3855-A map of the names of analysis passes that should be enabled/disabled. 3856-A full list of analyzers that gopls uses can be found in 3857-[analyzers.md](https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md). 3858- 3859-Example Usage: 3860- 3861-```json5 3862-... 3863-"analyses": { 3864- "unreachable": false, // Disable the unreachable analyzer. 3865- "unusedparams": true // Enable the unusedparams analyzer. 3866-} 3867-... 3868-``` 3869- 3870-Default: `{}`. 3871- 3872-##### **staticcheck** *bool* 3873- 3874-**This setting is experimental and may be deleted.** 3875- 3876-staticcheck enables additional analyses from staticcheck.io. 3877-These analyses are documented on 3878-[Staticcheck's website](https://staticcheck.io/docs/checks/). 3879- 3880-Default: `false`. 3881- 3882-##### **annotations** *map[string]bool* 3883- 3884-**This setting is experimental and may be deleted.** 3885- 3886-annotations specifies the various kinds of optimization diagnostics 3887-that should be reported by the gc_details command. 3888- 3889-Can contain any of: 3890- 3891-* `"bounds"` controls bounds checking diagnostics. 3892-* `"escape"` controls diagnostics about escape choices. 3893-* `"inline"` controls diagnostics about inlining choices. 3894-* `"nil"` controls nil checks. 3895- 3896-Default: `{"bounds":true,"escape":true,"inline":true,"nil":true}`. 3897- 3898-##### **vulncheck** *enum* 3899- 3900-**This setting is experimental and may be deleted.** 3901- 3902-vulncheck enables vulnerability scanning. 3903- 3904-Must be one of: 3905- 3906-* `"Imports"`: In Imports mode, `gopls` will report vulnerabilities that affect packages 3907-directly and indirectly used by the analyzed main module. 3908-* `"Off"`: Disable vulnerability analysis. 3909- 3910-Default: `"Off"`. 3911- 3912-##### **diagnosticsDelay** *time.Duration* 3913- 3914-**This is an advanced setting and should not be configured by most `gopls` users.** 3915- 3916-diagnosticsDelay controls the amount of time that gopls waits 3917-after the most recent file modification before computing deep diagnostics. 3918-Simple diagnostics (parsing and type-checking) are always run immediately 3919-on recently modified packages. 3920- 3921-This option must be set to a valid duration string, for example `"250ms"`. 3922- 3923-Default: `"250ms"`. 3924- 3925-#### Documentation 3926- 3927-##### **hoverKind** *enum* 3928- 3929-hoverKind controls the information that appears in the hover text. 3930-SingleLine and Structured are intended for use only by authors of editor plugins. 3931- 3932-Must be one of: 3933- 3934-* `"FullDocumentation"` 3935-* `"NoDocumentation"` 3936-* `"SingleLine"` 3937-* `"Structured"` is an experimental setting that returns a structured hover format. 3938-This format separates the signature from the documentation, so that the client 3939-can do more manipulation of these fields.\ 3940-This should only be used by clients that support this behavior. 3941-* `"SynopsisDocumentation"` 3942- 3943-Default: `"FullDocumentation"`. 3944- 3945-##### **linkTarget** *string* 3946- 3947-linkTarget controls where documentation links go. 3948-It might be one of: 3949- 3950-* `"godoc.org"` 3951-* `"pkg.go.dev"` 3952- 3953-If company chooses to use its own `godoc.org`, its address can be used as well. 3954- 3955-Modules matching the GOPRIVATE environment variable will not have 3956-documentation links in hover. 3957- 3958-Default: `"pkg.go.dev"`. 3959- 3960-##### **linksInHover** *bool* 3961- 3962-linksInHover toggles the presence of links to documentation in hover. 3963- 3964-Default: `true`. 3965- 3966-#### Inlayhint 3967- 3968-##### **hints** *map[string]bool* 3969- 3970-**This setting is experimental and may be deleted.** 3971- 3972-hints specify inlay hints that users want to see. A full list of hints 3973-that gopls uses can be found in 3974-[inlayHints.md](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md). 3975- 3976-Default: `{}`. 3977- 3978-#### Navigation 3979- 3980-##### **importShortcut** *enum* 3981- 3982-importShortcut specifies whether import statements should link to 3983-documentation or go to definitions. 3984- 3985-Must be one of: 3986- 3987-* `"Both"` 3988-* `"Definition"` 3989-* `"Link"` 3990- 3991-Default: `"Both"`. 3992- 3993-##### **symbolMatcher** *enum* 3994- 3995-**This is an advanced setting and should not be configured by most `gopls` users.** 3996- 3997-symbolMatcher sets the algorithm that is used when finding workspace symbols. 3998- 3999-Must be one of: 4000- 4001-* `"CaseInsensitive"` 4002-* `"CaseSensitive"` 4003-* `"FastFuzzy"` 4004-* `"Fuzzy"` 4005- 4006-Default: `"FastFuzzy"`. 4007- 4008-##### **symbolStyle** *enum* 4009- 4010-**This is an advanced setting and should not be configured by most `gopls` users.** 4011- 4012-symbolStyle controls how symbols are qualified in symbol responses. 4013- 4014-Example Usage: 4015- 4016-```json5 4017-"gopls": { 4018-... 4019- "symbolStyle": "Dynamic", 4020-... 4021-} 4022-``` 4023- 4024-Must be one of: 4025- 4026-* `"Dynamic"` uses whichever qualifier results in the highest scoring 4027-match for the given symbol query. Here a "qualifier" is any "/" or "." 4028-delimited suffix of the fully qualified symbol. i.e. "to/pkg.Foo.Field" or 4029-just "Foo.Field". 4030-* `"Full"` is fully qualified symbols, i.e. 4031-"path/to/pkg.Foo.Field". 4032-* `"Package"` is package qualified symbols i.e. 4033-"pkg.Foo.Field". 4034- 4035-Default: `"Dynamic"`. 4036- 4037-#### **verboseOutput** *bool* 4038- 4039-**This setting is for debugging purposes only.** 4040- 4041-verboseOutput enables additional debug logging. 4042- 4043-Default: `false`. 4044- 4045-<!-- END User: DO NOT MANUALLY EDIT THIS SECTION --> 4046- 4047-#### **newDiff** *string* 4048- 4049-newDiff enables the new diff implementation. If this is "both", for now both 4050-diffs will be run and statistics will be generated in a file in $TMPDIR. This 4051-is a risky setting; help in trying it is appreciated. If it is "old" the old 4052-implementation is used, and if it is "new", just the new implementation is 4053-used. This setting will eventually be deleted, once gopls has fully migrated to 4054-the new diff algorithm. 4055- 4056-Default: 'both'. 4057- 4058-## Code Lenses 4059- 4060-These are the code lenses that `gopls` currently supports. They can be enabled 4061-and disabled using the `codelenses` setting, documented above. Their names and 4062-features are subject to change. 4063- 4064-<!-- BEGIN Lenses: DO NOT MANUALLY EDIT THIS SECTION --> 4065-### **Toggle gc_details** 4066- 4067-Identifier: `gc_details` 4068- 4069-Toggle the calculation of gc annotations. 4070-### **Run go generate** 4071- 4072-Identifier: `generate` 4073- 4074-Runs `go generate` for a given directory. 4075-### **Regenerate cgo** 4076- 4077-Identifier: `regenerate_cgo` 4078- 4079-Regenerates cgo definitions. 4080-### **Run govulncheck.** 4081- 4082-Identifier: `run_govulncheck` 4083- 4084-Run vulnerability check (`govulncheck`). 4085-### **Run test(s) (legacy)** 4086- 4087-Identifier: `test` 4088- 4089-Runs `go test` for a specific set of test or benchmark functions. 4090-### **Run go mod tidy** 4091- 4092-Identifier: `tidy` 4093- 4094-Runs `go mod tidy` for a module. 4095-### **Upgrade a dependency** 4096- 4097-Identifier: `upgrade_dependency` 4098- 4099-Upgrades a dependency in the go.mod file for a module. 4100-### **Run go mod vendor** 4101- 4102-Identifier: `vendor` 4103- 4104-Runs `go mod vendor` for a module. 4105-<!-- END Lenses: DO NOT MANUALLY EDIT THIS SECTION --> 4106diff -urN a/gopls/doc/subl.md b/gopls/doc/subl.md 4107--- a/gopls/doc/subl.md 2000-01-01 00:00:00.000000000 -0000 4108+++ b/gopls/doc/subl.md 1970-01-01 00:00:00.000000000 +0000 4109@@ -1,81 +0,0 @@ 4110-# Sublime Text 4111- 4112-Use the [LSP] package. After installing it using Package Control, do the following: 4113- 4114-* Open the **Command Palette** 4115-* Find and run the command **LSP: Enable Language Server Globally** 4116-* Select the **gopls** item. Be careful not to select the similarly named *golsp* by mistake. 4117- 4118-Finally, you should familiarise yourself with the LSP package's *Settings* and *Key Bindings*. Find them under the menu item **Preferences > Package Settings > LSP**. 4119- 4120-## Examples 4121-Minimal global LSP settings, that assume **gopls** and **go** appear on the PATH seen by Sublime Text:<br> 4122-``` 4123-{ 4124- "clients": { 4125- "gopls": { 4126- "enabled": true, 4127- } 4128- } 4129-} 4130-``` 4131- 4132-Global LSP settings that supply a specific PATH for finding **gopls** and **go**, as well as some settings for Sublime LSP itself: 4133-``` 4134-{ 4135- "clients": { 4136- "gopls": { 4137- "enabled": true, 4138- "env": { 4139- "PATH": "/path/to/your/go/bin", 4140- } 4141- } 4142- }, 4143- // Recommended by https://agniva.me/gopls/2021/01/02/setting-up-gopls-sublime.html 4144- // except log_stderr mentioned there is no longer recognized. 4145- "show_references_in_quick_panel": true, 4146- "log_debug": true, 4147- // These two are recommended by LSP-json as replacement for deprecated only_show_lsp_completions 4148- "inhibit_snippet_completions": true, 4149- "inhibit_word_completions": true, 4150- } 4151- ``` 4152- 4153-LSP and gopls settings can also be adjusted on a per-project basis to override global settings. 4154-``` 4155-{ 4156- "folders": [ 4157- { 4158- "path": "/path/to/a/folder/one" 4159- }, 4160- { 4161- // If you happen to be working on Go itself, this can be helpful; go-dev/bin should be on PATH. 4162- "path": "/path/to/your/go-dev/src/cmd" 4163- } 4164- ], 4165- "settings": { 4166- "LSP": { 4167- "gopls": { 4168- // To use a specific version of gopls with Sublime Text LSP (e.g., to try new features in development) 4169- "command": [ 4170- "/path/to/your/go/bin/gopls" 4171- ], 4172- "env": { 4173- "PATH": "/path/to/your/go-dev/bin:/path/to/your/go/bin", 4174- "GOPATH": "", 4175- }, 4176- "settings": { 4177- "experimentalWorkspaceModule": true 4178- } 4179- } 4180- }, 4181- // This will apply for all languages in this project that have 4182- // LSP servers, not just Go, however cannot enable just for Go. 4183- "lsp_format_on_save": true, 4184- } 4185-} 4186-``` 4187- 4188-Usually changes to these settings are recognized after saving the project file, but it may sometimes be necessary to either restart the server(s) (**Tools > LSP > Restart Servers**) or quit and restart Sublime Text itself. 4189- 4190-[LSP]: https://packagecontrol.io/packages/LSP 4191diff -urN a/gopls/doc/troubleshooting.md b/gopls/doc/troubleshooting.md 4192--- a/gopls/doc/troubleshooting.md 2000-01-01 00:00:00.000000000 -0000 4193+++ b/gopls/doc/troubleshooting.md 1970-01-01 00:00:00.000000000 +0000 4194@@ -1,48 +0,0 @@ 4195-# Troubleshooting 4196- 4197-If you suspect that `gopls` is crashing or not working correctly, please follow the troubleshooting steps below. 4198- 4199-If `gopls` is using too much memory, please follow the steps under [Memory usage](#debug-memory-usage). 4200- 4201-## Steps 4202- 4203-VS Code users should follow [their troubleshooting guide](https://github.com/golang/vscode-go/blob/master/docs/troubleshooting.md), which has more a more specific version of these instructions. 4204- 4205-1. Verify that your project is in good shape by working with it outside of your editor. Running a command like `go build ./...` in the workspace directory will compile everything. For modules, `go mod tidy` is another good check, though it may modify your `go.mod`. 4206-1. Check that your editor isn't showing any diagnostics that indicate a problem with your workspace. They may appear as diagnostics on a Go file's package declaration, diagnostics in a go.mod file, or as a status or progress message. Problems in the workspace configuration can cause many different symptoms. See the [workspace setup instructions](workspace.md) for help. 4207-1. Make sure `gopls` is up to date by following the [installation instructions](../README.md#installation), then [restarting gopls](#restart-gopls). 4208-1. Optionally, [ask for help](#ask-for-help) on Gophers Slack. 4209-1. Finally, [report the issue](#file-an-issue) to the `gopls` developers. 4210- 4211-## Restart `gopls` 4212- 4213-`gopls` has no persistent state, so restarting it will fix transient problems. This is good and bad: good, because you can keep working, and bad, because you won't be able to debug the issue until it recurs. 4214- 4215-In most cases, closing all your open editors will guarantee that `gopls` is killed and restarted. If you don't want to do that, there may be an editor command you can use to restart only `gopls`. Note that some `vim` configurations keep the server alive for a while after the editor exits; you may need to explicitly kill `gopls` if you use `vim`. 4216- 4217-## Ask for help 4218- 4219-Gophers Slack has active editor-specific channels like [#emacs](https://gophers.slack.com/archives/C0HKHULEM), [#vim](https://gophers.slack.com/archives/C07GBR52P), and [#vscode](https://gophers.slack.com/archives/C2B4L99RS) that can help debug further. If you're confident the problem is with `gopls`, you can go straight to [#gopls](https://gophers.slack.com/archives/CJZH85XCZ). Invites are [available to everyone](https://invite.slack.golangbridge.org). Come prepared with a short description of the issue, and try to be available to answer questions for a while afterward. 4220- 4221-## File an issue 4222- 4223-We can't diagnose a problem from just a description. When filing an issue, please include as much as possible of the following information: 4224- 4225-1. Your editor and any settings you have configured (for example, your VSCode `settings.json` file). 4226-1. A sample program that reproduces the issue, if possible. 4227-1. The output of `gopls version` on the command line. 4228-1. A complete gopls log file from a session where the issue occurred. It should have a `go env for <workspace folder>` log line near the beginning. It's also helpful to tell us the timestamp the problem occurred, so we can find it the log. See the [instructions](#capture-logs) for information on how to capture gopls logs. 4229- 4230-Your editor may have a command that fills out some of the necessary information, such as `:GoReportGitHubIssue` in `vim-go`. Otherwise, you can use `gopls bug` on the command line. If neither of those work you can start from scratch directly on the [Go issue tracker](https://github.com/golang/go/issues/new?title=x%2Ftools%2Fgopls%3A%20%3Cfill%20this%20in%3E). 4231- 4232-## Capture logs 4233- 4234-You may have to change your editor's configuration to pass a `-logfile` flag to gopls. 4235- 4236-To increase the level of detail in your logs, start `gopls` with the `-rpc.trace` flag. To start a debug server that will allow you to see profiles and memory usage, start `gopls` with `serve --debug=localhost:6060`. You will then be able to view debug information by navigating to `localhost:6060`. 4237- 4238-If you are unsure of how to pass a flag to `gopls` through your editor, please see the [documentation for your editor](../README.md#editors). 4239- 4240-## Debug memory usage 4241- 4242-`gopls` automatically writes out memory debug information when your usage exceeds 1GB. This information can be found in your temporary directory with names like `gopls.1234-5GiB-withnames.zip`. On Windows, your temporary directory will be located at `%TMP%`, and on Unixes, it will be `$TMPDIR`, which is usually `/tmp`. Please [file an issue](#file-an-issue) with this memory debug information attached. If you are uncomfortable sharing the package names of your code, you can share the `-nonames` zip instead, but it's much less useful. 4243diff -urN a/gopls/doc/vim.md b/gopls/doc/vim.md 4244--- a/gopls/doc/vim.md 2000-01-01 00:00:00.000000000 -0000 4245+++ b/gopls/doc/vim.md 1970-01-01 00:00:00.000000000 +0000 4246@@ -1,216 +0,0 @@ 4247-# Vim / Neovim 4248- 4249-* [vim-go](#vimgo) 4250-* [LanguageClient-neovim](#lcneovim) 4251-* [Ale](#ale) 4252-* [vim-lsp](#vimlsp) 4253-* [vim-lsc](#vimlsc) 4254-* [coc.nvim](#cocnvim) 4255-* [govim](#govim) 4256-* [Neovim v0.5.0+](#neovim) 4257- * [Installation](#neovim-install) 4258- * [Custom Configuration](#neovim-config) 4259- * [Imports](#neovim-imports) 4260- * [Omnifunc](#neovim-omnifunc) 4261- * [Additional Links](#neovim-links) 4262- 4263-## <a href="#vimgo" id="vimgo">vim-go</a> 4264- 4265-Use [vim-go] ver 1.20+, with the following configuration: 4266- 4267-```vim 4268-let g:go_def_mode='gopls' 4269-let g:go_info_mode='gopls' 4270-``` 4271- 4272-## <a href="#lcneovim" id="lcneovim">LanguageClient-neovim</a> 4273- 4274-Use [LanguageClient-neovim], with the following configuration: 4275- 4276-```vim 4277-" Launch gopls when Go files are in use 4278-let g:LanguageClient_serverCommands = { 4279- \ 'go': ['gopls'] 4280- \ } 4281-" Run gofmt on save 4282-autocmd BufWritePre *.go :call LanguageClient#textDocument_formatting_sync() 4283-``` 4284- 4285-## <a href="#ale" id="ale">Ale</a> 4286- 4287-Use [ale]: 4288- 4289-```vim 4290-let g:ale_linters = { 4291- \ 'go': ['gopls'], 4292- \} 4293-``` 4294- 4295-see [this issue][ale-issue-2179] 4296- 4297-## <a href="#vimlsp" id="vimlsp">vim-lsp</a> 4298- 4299-Use [prabirshrestha/vim-lsp], with the following configuration: 4300- 4301-```vim 4302-augroup LspGo 4303- au! 4304- autocmd User lsp_setup call lsp#register_server({ 4305- \ 'name': 'go-lang', 4306- \ 'cmd': {server_info->['gopls']}, 4307- \ 'whitelist': ['go'], 4308- \ }) 4309- autocmd FileType go setlocal omnifunc=lsp#complete 4310- "autocmd FileType go nmap <buffer> gd <plug>(lsp-definition) 4311- "autocmd FileType go nmap <buffer> ,n <plug>(lsp-next-error) 4312- "autocmd FileType go nmap <buffer> ,p <plug>(lsp-previous-error) 4313-augroup END 4314-``` 4315- 4316-## <a href="#vimlsc" id="vimlsc">vim-lsc</a> 4317- 4318-Use [natebosch/vim-lsc], with the following configuration: 4319- 4320-```vim 4321-let g:lsc_server_commands = { 4322-\ "go": { 4323-\ "command": "gopls serve", 4324-\ "log_level": -1, 4325-\ "suppress_stderr": v:true, 4326-\ }, 4327-\} 4328-``` 4329- 4330-The `log_level` and `suppress_stderr` parts are needed to prevent breakage from logging. See 4331-issues [#180](https://github.com/natebosch/vim-lsc/issues/180) and 4332-[#213](https://github.com/natebosch/vim-lsc/issues/213). 4333- 4334-## <a href="#cocnvim" id="cocnvim">coc.nvim</a> 4335- 4336-Use [coc.nvim], with the following `coc-settings.json` configuration: 4337- 4338-```json 4339- "languageserver": { 4340- "golang": { 4341- "command": "gopls", 4342- "rootPatterns": ["go.work", "go.mod", ".vim/", ".git/", ".hg/"], 4343- "filetypes": ["go"], 4344- "initializationOptions": { 4345- "usePlaceholders": true 4346- } 4347- } 4348- } 4349-``` 4350- 4351-If you use `go.work` files, you may want to set the 4352-`workspace.workspaceFolderCheckCwd` option. This will force coc.nvim to search 4353-parent directories for `go.work` files, even if the current open directory has 4354-a `go.mod` file. See the 4355-[coc.nvim documentation](https://github.com/neoclide/coc.nvim/wiki/Using-workspaceFolders) 4356-for more details. 4357- 4358-Other [settings](settings.md) can be added in `initializationOptions` too. 4359- 4360-The `editor.action.organizeImport` code action will auto-format code and add missing imports. To run this automatically on save, add the following line to your `init.vim`: 4361- 4362-```vim 4363-autocmd BufWritePre *.go :call CocAction('runCommand', 'editor.action.organizeImport') 4364-``` 4365- 4366-## <a href="#govim" id="govim">govim</a> 4367- 4368-In vim classic only, use the experimental [`govim`], simply follow the [install steps][govim-install]. 4369- 4370-## <a href="#neovim" id="neovim">Neovim v0.5.0+</a> 4371- 4372-To use the new native LSP client in Neovim, make sure you 4373-[install][nvim-install] Neovim v.0.5.0+, 4374-the `nvim-lspconfig` configuration helper plugin, and check the 4375-[`gopls` configuration section][nvim-lspconfig] there. 4376- 4377-### <a href="#neovim-install" id="neovim-install">Installation</a> 4378- 4379-You can use Neovim's native plugin system. On a Unix system, you can do that by 4380-cloning the `nvim-lspconfig` repository into the correct directory: 4381- 4382-```sh 4383-dir="${HOME}/.local/share/nvim/site/pack/nvim-lspconfig/opt/nvim-lspconfig/" 4384-mkdir -p "$dir" 4385-cd "$dir" 4386-git clone 'https://github.com/neovim/nvim-lspconfig.git' . 4387-``` 4388- 4389-### <a href="#neovim-config" id="neovim-config">Custom Configuration</a> 4390- 4391-You can add custom configuration using Lua. Here is an example of enabling the 4392-`unusedparams` check as well as `staticcheck`: 4393- 4394-```vim 4395-lua <<EOF 4396- lspconfig = require "lspconfig" 4397- util = require "lspconfig/util" 4398- 4399- lspconfig.gopls.setup { 4400- cmd = {"gopls", "serve"}, 4401- filetypes = {"go", "gomod"}, 4402- root_dir = util.root_pattern("go.work", "go.mod", ".git"), 4403- settings = { 4404- gopls = { 4405- analyses = { 4406- unusedparams = true, 4407- }, 4408- staticcheck = true, 4409- }, 4410- }, 4411- } 4412-EOF 4413-``` 4414- 4415-### <a href="#neovim-imports" id="neovim-imports">Imports</a> 4416- 4417-Use the following configuration to have your imports organized on save using 4418-the logic of `goimports`. Note: this requires Neovim v0.7.0 or later. 4419- 4420-```lua 4421-vim.api.nvim_create_autocmd('BufWritePre', { 4422- pattern = '*.go', 4423- callback = function() 4424- vim.lsp.buf.code_action({ context = { only = { 'source.organizeImports' } }, apply = true }) 4425- end 4426-}) 4427-``` 4428- 4429-### <a href="#neovim-omnifunc" id="neovim-omnifunc">Omnifunc</a> 4430- 4431-In Neovim v0.8.1 and later if you don't set the option `omnifunc`, it will auto 4432-set to `v:lua.vim.lsp.omnifunc`. If you are using an earlier version, you can 4433-configure it manually: 4434- 4435-```lua 4436-local on_attach = function(client, bufnr) 4437- -- Enable completion triggered by <c-x><c-o> 4438- vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') 4439-end 4440-require('lspconfig').gopls.setup({ 4441- on_attach = on_attach 4442-}) 4443-``` 4444- 4445-### <a href="#neovim-links" id="neovim-links">Additional Links</a> 4446- 4447-* [Neovim's official LSP documentation][nvim-docs]. 4448- 4449-[vim-go]: https://github.com/fatih/vim-go 4450-[LanguageClient-neovim]: https://github.com/autozimu/LanguageClient-neovim 4451-[ale]: https://github.com/w0rp/ale 4452-[ale-issue-2179]: https://github.com/w0rp/ale/issues/2179 4453-[prabirshrestha/vim-lsp]: https://github.com/prabirshrestha/vim-lsp/ 4454-[natebosch/vim-lsc]: https://github.com/natebosch/vim-lsc/ 4455-[natebosch/vim-lsc#180]: https://github.com/natebosch/vim-lsc/issues/180 4456-[coc.nvim]: https://github.com/neoclide/coc.nvim/ 4457-[`govim`]: https://github.com/myitcv/govim 4458-[govim-install]: https://github.com/myitcv/govim/blob/master/README.md#govim---go-development-plugin-for-vim8 4459-[nvim-docs]: https://neovim.io/doc/user/lsp.html 4460-[nvim-install]: https://github.com/neovim/neovim/wiki/Installing-Neovim 4461-[nvim-lspconfig]: https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#gopls 4462-[nvim-lspconfig-imports]: https://github.com/neovim/nvim-lspconfig/issues/115 4463diff -urN a/gopls/doc/workspace.md b/gopls/doc/workspace.md 4464--- a/gopls/doc/workspace.md 2000-01-01 00:00:00.000000000 -0000 4465+++ b/gopls/doc/workspace.md 1970-01-01 00:00:00.000000000 +0000 4466@@ -1,101 +0,0 @@ 4467-# Setting up your workspace 4468- 4469-`gopls` supports both Go module and GOPATH modes. However, it needs a defined 4470-scope in which language features like references, rename, and implementation 4471-should operate. 4472- 4473-The following options are available for configuring this scope: 4474- 4475-## Module mode 4476- 4477-### One module 4478- 4479-If you are working with a single module, you can open the module root (the 4480-directory containing the `go.mod` file), a subdirectory within the module, 4481-or a parent directory containing the module. 4482- 4483-**Note**: If you open a parent directory containing a module, it must **only** 4484-contain that single module. Otherwise, you are working with multiple modules. 4485- 4486-### Multiple modules 4487- 4488-Gopls has several alternatives for working on multiple modules simultaneously, 4489-described below. Starting with Go 1.18, Go workspaces are the preferred solution. 4490- 4491-#### Go workspaces (Go 1.18+) 4492- 4493-Starting with Go 1.18, the `go` command has native support for multi-module 4494-workspaces, via [`go.work`](https://go.dev/ref/mod#workspaces) files. These 4495-files are recognized by gopls starting with `[email protected]`. 4496- 4497-The easiest way to work on multiple modules in Go 1.18 and later is therefore 4498-to create a `go.work` file containing the modules you wish to work on, and set 4499-your workspace root to the directory containing the `go.work` file. 4500- 4501-For example, suppose this repo is checked out into the `$WORK/tools` directory. 4502-We can work on both `golang.org/x/tools` and `golang.org/x/tools/gopls` 4503-simultaneously by creating a `go.work` file using `go work init`, followed by 4504-`go work use MODULE_DIRECTORIES...` to add directories containing `go.mod` files to the 4505-workspace: 4506- 4507-```sh 4508-cd $WORK 4509-go work init 4510-go work use ./tools/ ./tools/gopls/ 4511-``` 4512- 4513-...followed by opening the `$WORK` directory in our editor. 4514- 4515-#### DEPRECATED: Experimental workspace module (Go 1.17 and earlier) 4516- 4517-**This feature is deprecated and will be removed in future versions of gopls. 4518-Please see [issue #52897](https://go.dev/issue/52897) for additional 4519-information.** 4520- 4521-With earlier versions of Go, `gopls` can simulate multi-module workspaces by 4522-creating a synthetic module requiring the modules in the workspace root. 4523-See [the design document](https://github.com/golang/proposal/blob/master/design/37720-gopls-workspaces.md) 4524-for more information. 4525- 4526-This feature is experimental, and will eventually be removed once `go.work` 4527-files are accepted by all supported Go versions. 4528- 4529-You can enable this feature by configuring the 4530-[experimentalWorkspaceModule](settings.md#experimentalworkspacemodule-bool) 4531-setting. 4532- 4533-#### Multiple workspace folders 4534- 4535-If neither of the above solutions work, and your editor allows configuring the 4536-set of 4537-["workspace folders"](https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#workspaceFolder) 4538-used during your LSP session, you can still work on multiple modules by adding 4539-a workspace folder at each module root (the locations of `go.mod` files). This 4540-means that each module has its own scope, and features will not work across 4541-modules. 4542- 4543-In VS Code, you can create a workspace folder by setting up a 4544-[multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces). 4545-View the [documentation for your editor plugin](../README.md#editor) to learn how to 4546-configure a workspace folder in your editor. 4547- 4548-### GOPATH mode 4549- 4550-When opening a directory within your GOPATH, the workspace scope will be just 4551-that directory. 4552- 4553-### At your own risk 4554- 4555-Some users or companies may have projects that encompass one `$GOPATH`. If you 4556-open your entire `$GOPATH` or `$GOPATH/src` folder, the workspace scope will be 4557-your entire `GOPATH`. If your GOPATH is large, `gopls` to be very slow to start 4558-because it will try to find all of the Go files in the directory you have 4559-opened. It will then load all of the files it has found. 4560- 4561-To work around this case, you can create a new `$GOPATH` that contains only the 4562-packages you want to work on. 4563- 4564---- 4565- 4566-If you have additional use cases that are not mentioned above, please 4567-[file a new issue](https://github.com/golang/go/issues/new). 4568diff -urN a/gopls/go.mod b/gopls/go.mod 4569--- a/gopls/go.mod 2000-01-01 00:00:00.000000000 -0000 4570+++ b/gopls/go.mod 1970-01-01 00:00:00.000000000 +0000 4571@@ -1,29 +0,0 @@ 4572-module golang.org/x/tools/gopls 4573- 4574-go 1.18 4575- 4576-require ( 4577- github.com/google/go-cmp v0.5.9 4578- github.com/jba/printsrc v0.2.2 4579- github.com/jba/templatecheck v0.6.0 4580- github.com/sergi/go-diff v1.1.0 4581- golang.org/x/mod v0.9.0 4582- golang.org/x/sync v0.1.0 4583- golang.org/x/sys v0.6.0 4584- golang.org/x/text v0.8.0 4585- golang.org/x/tools v0.6.0 4586- golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815 4587- gopkg.in/yaml.v3 v3.0.1 4588- honnef.co/go/tools v0.4.2 4589- mvdan.cc/gofumpt v0.4.0 4590- mvdan.cc/xurls/v2 v2.4.0 4591-) 4592- 4593-require ( 4594- github.com/BurntSushi/toml v1.2.1 // indirect 4595- github.com/google/safehtml v0.1.0 // indirect 4596- golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect 4597- golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 // indirect 4598-) 4599- 4600-replace golang.org/x/tools => ../ 4601diff -urN a/gopls/go.sum b/gopls/go.sum 4602--- a/gopls/go.sum 2000-01-01 00:00:00.000000000 -0000 4603+++ b/gopls/go.sum 1970-01-01 00:00:00.000000000 +0000 4604@@ -1,101 +0,0 @@ 4605-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4606-github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= 4607-github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 4608-github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 4609-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 4610-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 4611-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4612-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4613-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4614-github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= 4615-github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= 4616-github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= 4617-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 4618-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 4619-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 4620-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 4621-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 4622-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 4623-github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= 4624-github.com/google/safehtml v0.1.0 h1:EwLKo8qawTKfsi0orxcQAZzu07cICaBeFMegAU9eaT8= 4625-github.com/google/safehtml v0.1.0/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= 4626-github.com/jba/printsrc v0.2.2 h1:9OHK51UT+/iMAEBlQIIXW04qvKyF3/vvLuwW/hL8tDU= 4627-github.com/jba/printsrc v0.2.2/go.mod h1:1xULjw59sL0dPdWpDoVU06TIEO/Wnfv6AHRpiElTwYM= 4628-github.com/jba/templatecheck v0.6.0 h1:SwM8C4hlK/YNLsdcXStfnHWE2HKkuTVwy5FKQHt5ro8= 4629-github.com/jba/templatecheck v0.6.0/go.mod h1:/1k7EajoSErFI9GLHAsiIJEaNLt3ALKNw2TV7z2SYv4= 4630-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 4631-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 4632-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 4633-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 4634-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 4635-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 4636-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 4637-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 4638-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4639-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 4640-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 4641-github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= 4642-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 4643-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 4644-github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= 4645-github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 4646-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 4647-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 4648-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 4649-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 4650-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 4651-golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= 4652-golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= 4653-golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 4654-golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 h1:2O2DON6y3XMJiQRAS1UWU+54aec2uopH3x7MAiqGW6Y= 4655-golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 4656-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 4657-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 4658-golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 4659-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 4660-golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= 4661-golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 4662-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 4663-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 4664-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 4665-golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 4666-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 4667-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 4668-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 4669-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4670-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4671-golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4672-golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4673-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4674-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4675-golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 4676-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 4677-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 4678-golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 4679-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 4680-golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 4681-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 4682-golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815 h1:A9kONVi4+AnuOr1dopsibH6hLi1Huy54cbeJxnq4vmU= 4683-golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815/go.mod h1:XJiVExZgoZfrrxoTeVsFYrSSk1snhfpOEC95JL+A4T0= 4684-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 4685-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 4686-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 4687-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 4688-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 4689-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 4690-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 4691-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 4692-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 4693-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= 4694-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 4695-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 4696-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 4697-honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= 4698-honnef.co/go/tools v0.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc= 4699-honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= 4700-mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= 4701-mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= 4702-mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 h1:Jh3LAeMt1eGpxomyu3jVkmVZWW2MxZ1qIIV2TZ/nRio= 4703-mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= 4704-mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= 4705-mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= 4706diff -urN a/gopls/integration/govim/artifacts.go b/gopls/integration/govim/artifacts.go 4707--- a/gopls/integration/govim/artifacts.go 2000-01-01 00:00:00.000000000 -0000 4708+++ b/gopls/integration/govim/artifacts.go 1970-01-01 00:00:00.000000000 +0000 4709@@ -1,67 +0,0 @@ 4710-// Copyright 2020 The Go Authors. All rights reserved. 4711-// Use of this source code is governed by a BSD-style 4712-// license that can be found in the LICENSE file. 4713- 4714-package main 4715- 4716-import ( 4717- "flag" 4718- "fmt" 4719- "io/ioutil" 4720- "net/http" 4721- "os" 4722- "path" 4723-) 4724- 4725-var bucket = flag.String("bucket", "golang-gopls_integration_tests", "GCS bucket holding test artifacts.") 4726- 4727-const usage = ` 4728-artifacts [--bucket=<bucket ID>] <cloud build evaluation ID> 4729- 4730-Fetch artifacts from an integration test run. Evaluation ID should be extracted 4731-from the cloud build notification. 4732- 4733-In order for this to work, the GCS bucket that artifacts were written to must 4734-be publicly readable. By default, this fetches from the 4735-golang-gopls_integration_tests bucket. 4736-` 4737- 4738-func main() { 4739- flag.Usage = func() { 4740- fmt.Fprint(flag.CommandLine.Output(), usage) 4741- } 4742- flag.Parse() 4743- if flag.NArg() != 1 { 4744- flag.Usage() 4745- os.Exit(2) 4746- } 4747- evalID := flag.Arg(0) 4748- logURL := fmt.Sprintf("https://storage.googleapis.com/%s/log-%s.txt", *bucket, evalID) 4749- if err := download(logURL); err != nil { 4750- fmt.Fprintf(os.Stderr, "downloading logs: %v", err) 4751- } 4752- tarURL := fmt.Sprintf("https://storage.googleapis.com/%s/govim/%s/artifacts.tar.gz", *bucket, evalID) 4753- if err := download(tarURL); err != nil { 4754- fmt.Fprintf(os.Stderr, "downloading artifact tarball: %v", err) 4755- } 4756-} 4757- 4758-func download(artifactURL string) error { 4759- name := path.Base(artifactURL) 4760- resp, err := http.Get(artifactURL) 4761- if err != nil { 4762- return fmt.Errorf("fetching from GCS: %v", err) 4763- } 4764- defer resp.Body.Close() 4765- if resp.StatusCode != http.StatusOK { 4766- return fmt.Errorf("got status code %d from GCS", resp.StatusCode) 4767- } 4768- data, err := ioutil.ReadAll(resp.Body) 4769- if err != nil { 4770- return fmt.Errorf("reading result: %v", err) 4771- } 4772- if err := ioutil.WriteFile(name, data, 0644); err != nil { 4773- return fmt.Errorf("writing artifact: %v", err) 4774- } 4775- return nil 4776-} 4777diff -urN a/gopls/integration/govim/cloudbuild.harness.yaml b/gopls/integration/govim/cloudbuild.harness.yaml 4778--- a/gopls/integration/govim/cloudbuild.harness.yaml 2000-01-01 00:00:00.000000000 -0000 4779+++ b/gopls/integration/govim/cloudbuild.harness.yaml 1970-01-01 00:00:00.000000000 +0000 4780@@ -1,21 +0,0 @@ 4781-# Copyright 2019 The Go Authors. All rights reserved. 4782-# Use of this source code is governed by a BSD-style 4783-# license that can be found in the LICENSE file. 4784- 4785-# Build the govim test harness that will be used to run govim integration tests 4786-# for gopls. See README.md for instructions on how to use this. 4787-steps: 4788- - name: 'gcr.io/cloud-builders/docker' 4789- args: ['build', 4790- # To allow for breaking changes to this test harness, tag with a major 4791- # version number. 4792- '-t', 'gcr.io/$PROJECT_ID/govim-harness:latest', 4793- '-t', 'gcr.io/$PROJECT_ID/govim-harness:3', 4794- # It is assumed that this build is running from the root directory of the 4795- # tools repository. 4796- '-f', 'gopls/integration/govim/Dockerfile', 4797- # Use the integration test directory as build context: the test harness 4798- # doesn't actually require any local files. 4799- 'gopls/integration/govim'] 4800-images: 4801- - gcr.io/$PROJECT_ID/govim-harness 4802diff -urN a/gopls/integration/govim/cloudbuild.yaml b/gopls/integration/govim/cloudbuild.yaml 4803--- a/gopls/integration/govim/cloudbuild.yaml 2000-01-01 00:00:00.000000000 -0000 4804+++ b/gopls/integration/govim/cloudbuild.yaml 1970-01-01 00:00:00.000000000 +0000 4805@@ -1,51 +0,0 @@ 4806-# Copyright 2019 The Go Authors. All rights reserved. 4807-# Use of this source code is governed by a BSD-style 4808-# license that can be found in the LICENSE file. 4809- 4810-# Build gopls, and run the govim integration tests. See README.md for 4811-# instructions on how to use this. 4812- 4813-substitutions: 4814- # This bucket must be owned by the GCP project executing the build. If 4815- # you are running this from your own project, override using --substitutions. 4816- _RESULT_BUCKET: 'golang-gopls_integration_tests' 4817- 4818-steps: 4819- # Build gopls from source, to use with the govim integration tests. 4820- - name: 'golang:1.14' 4821- env: ['GOPROXY=https://proxy.golang.org'] 4822- dir: 'gopls' 4823- args: ['go', 'build'] 4824- 4825- # Run the tests. Note that the script in this step does not return the exit 4826- # code from `go test`, but rather saves it for use in the final step after 4827- # uploading artifacts. 4828- - name: 'gcr.io/$PROJECT_ID/govim-harness:3' 4829- dir: '/src/govim' 4830- volumes: 4831- - name: artifacts 4832- path: /artifacts 4833- env: 4834- - GOVIM_TESTSCRIPT_WORKDIR_ROOT=/artifacts 4835- - VIM_FLAVOR=vim 4836- args: ['/workspace/gopls/integration/govim/run_tests_for_cloudbuild.sh'] 4837- 4838- # The govim tests produce a large number of artifacts; tarball/gzip to reduce 4839- # roundtrips and save space. 4840- - name: 'ubuntu' 4841- volumes: 4842- - name: artifacts 4843- path: /artifacts 4844- args: ['tar', '-czf', 'artifacts.tar.gz', '/artifacts'] 4845- 4846- # Upload artifacts to GCS. 4847- - name: 'gcr.io/cloud-builders/gsutil' 4848- args: ['cp', 'artifacts.tar.gz', 'gs://${_RESULT_BUCKET}/govim/${BUILD_ID}/artifacts.tar.gz'] 4849- 4850- # Exit with the actual exit code of the integration tests. 4851- - name: 'ubuntu' 4852- args: ['bash', 'govim_test_result.sh'] 4853- 4854-# Write build logs to the same bucket as artifacts, so they can be more easily 4855-# shared. 4856-logsBucket: 'gs://${_RESULT_BUCKET}' 4857diff -urN a/gopls/integration/govim/Dockerfile b/gopls/integration/govim/Dockerfile 4858--- a/gopls/integration/govim/Dockerfile 2000-01-01 00:00:00.000000000 -0000 4859+++ b/gopls/integration/govim/Dockerfile 1970-01-01 00:00:00.000000000 +0000 4860@@ -1,16 +0,0 @@ 4861-# Copyright 2019 The Go Authors. All rights reserved. 4862-# Use of this source code is governed by a BSD-style 4863-# license that can be found in the LICENSE file. 4864- 4865-# govim requires a more recent version of vim than is available in most 4866-# distros, so we build from their base image. 4867-FROM govim/govim:latest-vim 4868-ARG GOVIM_REF 4869- 4870-ENV GOPROXY=https://proxy.golang.org GOPATH=/go VIM_FLAVOR=vim 4871-WORKDIR /src 4872- 4873-# Clone govim. In order to use the go command for resolving latest, we download 4874-# a redundant copy of govim to the build cache using `go mod download`. 4875-RUN git clone https://github.com/govim/govim /src/govim && cd /src/govim && \ 4876- git checkout $GOVIM_REF 4877diff -urN a/gopls/integration/govim/README.md b/gopls/integration/govim/README.md 4878--- a/gopls/integration/govim/README.md 2000-01-01 00:00:00.000000000 -0000 4879+++ b/gopls/integration/govim/README.md 1970-01-01 00:00:00.000000000 +0000 4880@@ -1,47 +0,0 @@ 4881-# govim integration tests 4882- 4883-Files in this directory configure Cloud Build to run [govim] integration tests 4884-against a gopls binary built from source. 4885- 4886-## Running on GCP 4887- 4888-To run these integration tests in Cloud Build, use the following steps. Here 4889-we assume that `$PROJECT_ID` is a valid GCP project and `$BUCKET` is a cloud 4890-storage bucket owned by that project. 4891- 4892-- `cd` to the root directory of the tools project. 4893-- (at least once per GCP project) Build the test harness: 4894-``` 4895-$ gcloud builds submit \ 4896- --project="${PROJECT_ID}" \ 4897- --config=gopls/integration/govim/cloudbuild.harness.yaml 4898-``` 4899-- Run the integration tests: 4900-``` 4901-$ gcloud builds submit \ 4902- --project="${PROJECT_ID}" \ 4903- --config=gopls/integration/govim/cloudbuild.yaml \ 4904- --substitutions=_RESULT_BUCKET="${BUCKET}" 4905-``` 4906- 4907-## Fetching Artifacts 4908- 4909-Assuming the artifacts bucket is world readable, you can fetch integration from 4910-GCS. They are located at: 4911- 4912-- logs: `https://storage.googleapis.com/${BUCKET}/log-${EVALUATION_ID}.txt` 4913-- artifact tarball: `https://storage.googleapis.com/${BUCKET}/govim/${EVALUATION_ID}/artifacts.tar.gz` 4914- 4915-The `artifacts.go` command can be used to fetch both artifacts using an 4916-evaluation id. 4917- 4918-## Running locally 4919- 4920-Run `gopls/integration/govim/run_local.sh`. This may take a while the first 4921-time it is run, as it will require building the test harness. This script 4922-accepts two flags to modify its behavior: 4923- 4924-**--sudo**: run docker with `sudo` 4925-**--short**: run `go test -short` 4926- 4927-[govim]: https://github.com/govim/govim 4928diff -urN a/gopls/integration/govim/run_local.sh b/gopls/integration/govim/run_local.sh 4929--- a/gopls/integration/govim/run_local.sh 2000-01-01 00:00:00.000000000 -0000 4930+++ b/gopls/integration/govim/run_local.sh 1970-01-01 00:00:00.000000000 +0000 4931@@ -1,96 +0,0 @@ 4932-#!/bin/bash -e 4933- 4934-# Copyright 2019 The Go Authors. All rights reserved. 4935-# Use of this source code is governed by a BSD-style 4936-# license that can be found in the LICENSE file. 4937- 4938-# Run govim integration tests against a local gopls. 4939- 4940-usage() { 4941- cat <<EOUSAGE 4942-Usage: $0 [--sudo] [--short] [--version (semver|latest)] 4943- 4944-Args: 4945- --sudo run docker with sudo 4946- --short run `go test` with `-short` 4947- --version run on the specific tagged govim version (or latest) rather 4948- than the default branch 4949- 4950-Run govim tests against HEAD using local docker. 4951-EOUSAGE 4952-} 4953- 4954-SUDO_IF_NEEDED= 4955-TEST_SHORT= 4956-DOCKERFILE=gopls/integration/govim/Dockerfile 4957-GOVIM_REF=main 4958-while [[ $# -gt 0 ]]; do 4959- case "$1" in 4960- "-h" | "--help" | "help") 4961- usage 4962- exit 0 4963- ;; 4964- "--sudo") 4965- SUDO_IF_NEEDED="sudo " 4966- shift 4967- ;; 4968- "--short") 4969- TEST_SHORT="-short" 4970- shift 4971- ;; 4972- "--version") 4973- if [[ -z "$2" ]]; then 4974- usage 4975- exit 1 4976- fi 4977- GOVIM_REF=$2 4978- if [[ "${GOVIM_REF}" == "latest" ]]; then 4979- TMPGOPATH=$(mktemp -d) 4980- trap "GOPATH=${TMPGOPATH} go clean -modcache && rm -r ${TMPGOPATH}" EXIT 4981- GOVIM_REF=$(GOPATH=${TMPGOPATH} go mod download -json \ 4982- github.com/govim/govim@latest | jq -r .Version) 4983- fi 4984- shift 2 4985- ;; 4986- *) 4987- usage 4988- exit 1 4989- esac 4990-done 4991- 4992-# Find the tools root, so that this script can be run from any directory. 4993-script_dir=$(dirname "$(readlink -f "$0")") 4994-tools_dir=$(readlink -f "${script_dir}/../../..") 4995- 4996-# Build gopls. 4997-cd "${tools_dir}/gopls" 4998-temp_gopls=$(mktemp -p "$PWD") 4999-trap "rm -f \"${temp_gopls}\"" EXIT 5000-# For consistency across environments, use golang docker to build rather than 5001-# the local go command. 5002-${SUDO_IF_NEEDED}docker run --rm -t \ 5003- -v "${tools_dir}:/src/tools" \ 5004- -w "/src/tools/gopls" \ 5005- golang:rc \ 5006- go build -o $(basename ${temp_gopls}) 5007- 5008-# Build the test harness. Here we are careful to pass in a very limited build 5009-# context so as to optimize caching. 5010-echo "Checking out govim@${GOVIM_REF}" 5011-cd "${tools_dir}" 5012-${SUDO_IF_NEEDED}docker build \ 5013- --build-arg GOVIM_REF="${GOVIM_REF}" \ 5014- -t gopls-govim-harness:${GOVIM_REF} \ 5015- -f gopls/integration/govim/Dockerfile \ 5016- gopls/integration/govim 5017- 5018-# Run govim integration tests. 5019-echo "running govim integration tests using ${temp_gopls}" 5020-temp_gopls_name=$(basename "${temp_gopls}") 5021-${SUDO_IF_NEEDED}docker run --rm -t \ 5022- -v "${tools_dir}:/src/tools" \ 5023- -w "/src/govim" \ 5024- --ulimit memlock=-1:-1 \ 5025- gopls-govim-harness:${GOVIM_REF} \ 5026- go test ${TEST_SHORT} ./cmd/govim \ 5027- -gopls "/src/tools/gopls/${temp_gopls_name}" 5028diff -urN a/gopls/integration/govim/run_tests_for_cloudbuild.sh b/gopls/integration/govim/run_tests_for_cloudbuild.sh 5029--- a/gopls/integration/govim/run_tests_for_cloudbuild.sh 2000-01-01 00:00:00.000000000 -0000 5030+++ b/gopls/integration/govim/run_tests_for_cloudbuild.sh 1970-01-01 00:00:00.000000000 +0000 5031@@ -1,28 +0,0 @@ 5032-#!/bin/bash 5033- 5034-# Copyright 2020 The Go Authors. All rights reserved. 5035-# Use of this source code is governed by a BSD-style 5036-# license that can be found in the LICENSE file. 5037- 5038-# This script runs govim integration tests but always succeeds, instead writing 5039-# their result to a file so that any test failure can be deferred to a later 5040-# build step. We do this so that we can capture govim test artifacts regardless 5041-# of the test results. 5042- 5043-# Substitute the locally built gopls binary for use in govim integration tests. 5044-go test -short ./cmd/govim -gopls /workspace/gopls/gopls 5045- 5046-# Stash the error, for use in a later build step. 5047-echo "exit $?" > /workspace/govim_test_result.sh 5048- 5049-# Clean up unnecessary artifacts. This is based on govim/_scripts/tidyUp.bash. 5050-# Since we're fetching govim using the go command, we won't have this non-go 5051-# source directory available to us. 5052-if [[ -n "$GOVIM_TESTSCRIPT_WORKDIR_ROOT" ]]; then 5053- echo "Cleaning up build artifacts..." 5054- # Make artifacts writable so that rm -rf doesn't complain. 5055- chmod -R u+w "$GOVIM_TESTSCRIPT_WORKDIR_ROOT" 5056- 5057- # Remove directories we don't care about. 5058- find "$GOVIM_TESTSCRIPT_WORKDIR_ROOT" -type d \( -name .vim -o -name gopath \) -prune -exec rm -rf '{}' \; 5059-fi 5060diff -urN a/gopls/internal/coverage/coverage.go b/gopls/internal/coverage/coverage.go 5061--- a/gopls/internal/coverage/coverage.go 2000-01-01 00:00:00.000000000 -0000 5062+++ b/gopls/internal/coverage/coverage.go 1970-01-01 00:00:00.000000000 +0000 5063@@ -1,266 +0,0 @@ 5064-// Copyright 2021 The Go Authors. All rights reserved. 5065-// Use of this source code is governed by a BSD-style 5066-// license that can be found in the LICENSE file. 5067- 5068-//go:build go.1.16 5069-// +build go.1.16 5070- 5071-// Running this program in the tools directory will produce a coverage file /tmp/cover.out 5072-// and a coverage report for all the packages under internal/lsp, accumulated by all the tests 5073-// under gopls. 5074-// 5075-// -o controls where the coverage file is written, defaulting to /tmp/cover.out 5076-// -i coverage-file will generate the report from an existing coverage file 5077-// -v controls verbosity (0: only report coverage, 1: report as each directory is finished, 5078-// 5079-// 2: report on each test, 3: more details, 4: too much) 5080-// 5081-// -t tests only tests packages in the given comma-separated list of directories in gopls. 5082-// 5083-// The names should start with ., as in ./internal/regtest/bench 5084-// 5085-// -run tests. If set, -run tests is passed on to the go test command. 5086-// 5087-// Despite gopls' use of goroutines, the counts are almost deterministic. 5088-package main 5089- 5090-import ( 5091- "bytes" 5092- "encoding/json" 5093- "flag" 5094- "fmt" 5095- "log" 5096- "os" 5097- "os/exec" 5098- "path/filepath" 5099- "sort" 5100- "strings" 5101- "time" 5102- 5103- "golang.org/x/tools/cover" 5104-) 5105- 5106-var ( 5107- proFile = flag.String("i", "", "existing profile file") 5108- outFile = flag.String("o", "/tmp/cover.out", "where to write the coverage file") 5109- verbose = flag.Int("v", 0, "how much detail to print as tests are running") 5110- tests = flag.String("t", "", "list of tests to run") 5111- run = flag.String("run", "", "value of -run to pass to go test") 5112-) 5113- 5114-func main() { 5115- log.SetFlags(log.Lshortfile) 5116- flag.Parse() 5117- 5118- if *proFile != "" { 5119- report(*proFile) 5120- return 5121- } 5122- 5123- checkCwd() 5124- // find the packages under gopls containing tests 5125- tests := listDirs("gopls") 5126- tests = onlyTests(tests) 5127- tests = realTestName(tests) 5128- 5129- // report coverage for packages under internal/lsp 5130- parg := "golang.org/x/tools/gopls/internal/lsp/..." 5131- 5132- accum := []string{} 5133- seen := make(map[string]bool) 5134- now := time.Now() 5135- for _, toRun := range tests { 5136- if excluded(toRun) { 5137- continue 5138- } 5139- x := runTest(toRun, parg) 5140- if *verbose > 0 { 5141- fmt.Printf("finished %s %.1fs\n", toRun, time.Since(now).Seconds()) 5142- } 5143- lines := bytes.Split(x, []byte{'\n'}) 5144- for _, l := range lines { 5145- if len(l) == 0 { 5146- continue 5147- } 5148- if !seen[string(l)] { 5149- // not accumulating counts, so only works for mode:set 5150- seen[string(l)] = true 5151- accum = append(accum, string(l)) 5152- } 5153- } 5154- } 5155- sort.Strings(accum[1:]) 5156- if err := os.WriteFile(*outFile, []byte(strings.Join(accum, "\n")), 0644); err != nil { 5157- log.Print(err) 5158- } 5159- report(*outFile) 5160-} 5161- 5162-type result struct { 5163- Time time.Time 5164- Test string 5165- Action string 5166- Package string 5167- Output string 5168- Elapsed float64 5169-} 5170- 5171-func runTest(tName, parg string) []byte { 5172- args := []string{"test", "-short", "-coverpkg", parg, "-coverprofile", *outFile, 5173- "-json"} 5174- if *run != "" { 5175- args = append(args, fmt.Sprintf("-run=%s", *run)) 5176- } 5177- args = append(args, tName) 5178- cmd := exec.Command("go", args...) 5179- cmd.Dir = "./gopls" 5180- ans, err := cmd.Output() 5181- if *verbose > 1 { 5182- got := strings.Split(string(ans), "\n") 5183- for _, g := range got { 5184- if g == "" { 5185- continue 5186- } 5187- var m result 5188- if err := json.Unmarshal([]byte(g), &m); err != nil { 5189- log.Printf("%T/%v", err, err) // shouldn't happen 5190- continue 5191- } 5192- maybePrint(m) 5193- } 5194- } 5195- if err != nil { 5196- log.Printf("%s: %q, cmd=%s", tName, ans, cmd.String()) 5197- } 5198- buf, err := os.ReadFile(*outFile) 5199- if err != nil { 5200- log.Fatal(err) 5201- } 5202- return buf 5203-} 5204- 5205-func report(fn string) { 5206- profs, err := cover.ParseProfiles(fn) 5207- if err != nil { 5208- log.Fatal(err) 5209- } 5210- for _, p := range profs { 5211- statements, counts := 0, 0 5212- for _, x := range p.Blocks { 5213- statements += x.NumStmt 5214- if x.Count != 0 { 5215- counts += x.NumStmt // sic: if any were executed, all were 5216- } 5217- } 5218- pc := 100 * float64(counts) / float64(statements) 5219- fmt.Printf("%3.0f%% %3d/%3d %s\n", pc, counts, statements, p.FileName) 5220- } 5221-} 5222- 5223-var todo []string // tests to run 5224- 5225-func excluded(tname string) bool { 5226- if *tests == "" { // run all tests 5227- return false 5228- } 5229- if todo == nil { 5230- todo = strings.Split(*tests, ",") 5231- } 5232- for _, nm := range todo { 5233- if tname == nm { // run this test 5234- return false 5235- } 5236- } 5237- // not in list, skip it 5238- return true 5239-} 5240- 5241-// should m.Package be printed sometime? 5242-func maybePrint(m result) { 5243- switch m.Action { 5244- case "pass", "fail", "skip": 5245- fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed) 5246- case "run": 5247- if *verbose > 2 { 5248- fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed) 5249- } 5250- case "output": 5251- if *verbose > 3 { 5252- fmt.Printf("%s %s %q %.3f\n", m.Action, m.Test, m.Output, m.Elapsed) 5253- } 5254- case "pause", "cont": 5255- if *verbose > 2 { 5256- fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed) 5257- } 5258- default: 5259- fmt.Printf("%#v\n", m) 5260- log.Fatalf("unknown action %s\n", m.Action) 5261- } 5262-} 5263- 5264-// return only the directories that contain tests 5265-func onlyTests(s []string) []string { 5266- ans := []string{} 5267-outer: 5268- for _, d := range s { 5269- files, err := os.ReadDir(d) 5270- if err != nil { 5271- log.Fatalf("%s: %v", d, err) 5272- } 5273- for _, de := range files { 5274- if strings.Contains(de.Name(), "_test.go") { 5275- ans = append(ans, d) 5276- continue outer 5277- } 5278- } 5279- } 5280- return ans 5281-} 5282- 5283-// replace the prefix gopls/ with ./ as the tests are run in the gopls directory 5284-func realTestName(p []string) []string { 5285- ans := []string{} 5286- for _, x := range p { 5287- x = x[len("gopls/"):] 5288- ans = append(ans, "./"+x) 5289- } 5290- return ans 5291-} 5292- 5293-// make sure we start in a tools directory 5294-func checkCwd() { 5295- dir, err := os.Getwd() 5296- if err != nil { 5297- log.Fatal(err) 5298- } 5299- // we expect to be at the root of golang.org/x/tools 5300- cmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}", "golang.org/x/tools") 5301- buf, err := cmd.Output() 5302- buf = bytes.Trim(buf, "\n \t") // remove \n at end 5303- if err != nil { 5304- log.Fatal(err) 5305- } 5306- if string(buf) != dir { 5307- log.Fatalf("wrong directory: in %q, should be in %q", dir, string(buf)) 5308- } 5309- // and we expect gopls and internal/lsp as subdirectories 5310- _, err = os.Stat("gopls") 5311- if err != nil { 5312- log.Fatalf("expected a gopls directory, %v", err) 5313- } 5314-} 5315- 5316-func listDirs(dir string) []string { 5317- ans := []string{} 5318- f := func(path string, dirEntry os.DirEntry, err error) error { 5319- if strings.HasSuffix(path, "/testdata") || strings.HasSuffix(path, "/typescript") { 5320- return filepath.SkipDir 5321- } 5322- if dirEntry.IsDir() { 5323- ans = append(ans, path) 5324- } 5325- return nil 5326- } 5327- filepath.WalkDir(dir, f) 5328- return ans 5329-} 5330diff -urN a/gopls/internal/govulncheck/semver/semver.go b/gopls/internal/govulncheck/semver/semver.go 5331--- a/gopls/internal/govulncheck/semver/semver.go 2000-01-01 00:00:00.000000000 -0000 5332+++ b/gopls/internal/govulncheck/semver/semver.go 1970-01-01 00:00:00.000000000 +0000 5333@@ -1,51 +0,0 @@ 5334-// Copyright 2022 The Go Authors. All rights reserved. 5335-// Use of this source code is governed by a BSD-style 5336-// license that can be found in the LICENSE file. 5337- 5338-//go:build go1.18 5339-// +build go1.18 5340- 5341-// Package semver provides shared utilities for manipulating 5342-// Go semantic versions. 5343-package semver 5344- 5345-import ( 5346- "regexp" 5347- "strings" 5348-) 5349- 5350-// addSemverPrefix adds a 'v' prefix to s if it isn't already prefixed 5351-// with 'v' or 'go'. This allows us to easily test go-style SEMVER 5352-// strings against normal SEMVER strings. 5353-func addSemverPrefix(s string) string { 5354- if !strings.HasPrefix(s, "v") && !strings.HasPrefix(s, "go") { 5355- return "v" + s 5356- } 5357- return s 5358-} 5359- 5360-// removeSemverPrefix removes the 'v' or 'go' prefixes from go-style 5361-// SEMVER strings, for usage in the public vulnerability format. 5362-func removeSemverPrefix(s string) string { 5363- s = strings.TrimPrefix(s, "v") 5364- s = strings.TrimPrefix(s, "go") 5365- return s 5366-} 5367- 5368-// CanonicalizeSemverPrefix turns a SEMVER string into the canonical 5369-// representation using the 'v' prefix, as used by the OSV format. 5370-// Input may be a bare SEMVER ("1.2.3"), Go prefixed SEMVER ("go1.2.3"), 5371-// or already canonical SEMVER ("v1.2.3"). 5372-func CanonicalizeSemverPrefix(s string) string { 5373- return addSemverPrefix(removeSemverPrefix(s)) 5374-} 5375- 5376-var ( 5377- // Regexp for matching go tags. The groups are: 5378- // 1 the major.minor version 5379- // 2 the patch version, or empty if none 5380- // 3 the entire prerelease, if present 5381- // 4 the prerelease type ("beta" or "rc") 5382- // 5 the prerelease number 5383- tagRegexp = regexp.MustCompile(`^go(\d+\.\d+)(\.\d+|)((beta|rc|-pre)(\d+))?$`) 5384-) 5385diff -urN a/gopls/internal/govulncheck/semver/semver_test.go b/gopls/internal/govulncheck/semver/semver_test.go 5386--- a/gopls/internal/govulncheck/semver/semver_test.go 2000-01-01 00:00:00.000000000 -0000 5387+++ b/gopls/internal/govulncheck/semver/semver_test.go 1970-01-01 00:00:00.000000000 +0000 5388@@ -1,28 +0,0 @@ 5389-// Copyright 2022 The Go Authors. All rights reserved. 5390-// Use of this source code is governed by a BSD-style 5391-// license that can be found in the LICENSE file. 5392- 5393-//go:build go1.18 5394-// +build go1.18 5395- 5396-package semver 5397- 5398-import ( 5399- "testing" 5400-) 5401- 5402-func TestCanonicalize(t *testing.T) { 5403- for _, test := range []struct { 5404- v string 5405- want string 5406- }{ 5407- {"v1.2.3", "v1.2.3"}, 5408- {"1.2.3", "v1.2.3"}, 5409- {"go1.2.3", "v1.2.3"}, 5410- } { 5411- got := CanonicalizeSemverPrefix(test.v) 5412- if got != test.want { 5413- t.Errorf("want %s; got %s", test.want, got) 5414- } 5415- } 5416-} 5417diff -urN a/gopls/internal/govulncheck/types_118.go b/gopls/internal/govulncheck/types_118.go 5418--- a/gopls/internal/govulncheck/types_118.go 2000-01-01 00:00:00.000000000 -0000 5419+++ b/gopls/internal/govulncheck/types_118.go 1970-01-01 00:00:00.000000000 +0000 5420@@ -1,43 +0,0 @@ 5421-// Copyright 2022 The Go Authors. All rights reserved. 5422-// Use of this source code is governed by a BSD-style 5423-// license that can be found in the LICENSE file. 5424- 5425-//go:build go1.18 5426-// +build go1.18 5427- 5428-// Package govulncheck provides an experimental govulncheck API. 5429-package govulncheck 5430- 5431-import ( 5432- "golang.org/x/vuln/exp/govulncheck" 5433-) 5434- 5435-var ( 5436- // Source reports vulnerabilities that affect the analyzed packages. 5437- Source = govulncheck.Source 5438- 5439- // DefaultCache constructs cache for a vulnerability database client. 5440- DefaultCache = govulncheck.DefaultCache 5441-) 5442- 5443-type ( 5444- // Config is the configuration for Main. 5445- Config = govulncheck.Config 5446- 5447- // Vuln represents a single OSV entry. 5448- Vuln = govulncheck.Vuln 5449- 5450- // Module represents a specific vulnerability relevant to a 5451- // single module or package. 5452- Module = govulncheck.Module 5453- 5454- // Package is a Go package with known vulnerable symbols. 5455- Package = govulncheck.Package 5456- 5457- // CallStacks contains a representative call stack for each 5458- // vulnerable symbol that is called. 5459- CallStack = govulncheck.CallStack 5460- 5461- // StackFrame represents a call stack entry. 5462- StackFrame = govulncheck.StackFrame 5463-) 5464diff -urN a/gopls/internal/govulncheck/types.go b/gopls/internal/govulncheck/types.go 5465--- a/gopls/internal/govulncheck/types.go 2000-01-01 00:00:00.000000000 -0000 5466+++ b/gopls/internal/govulncheck/types.go 1970-01-01 00:00:00.000000000 +0000 5467@@ -1,37 +0,0 @@ 5468-// Copyright 2022 The Go Authors. All rights reserved. 5469-// Use of this source code is governed by a BSD-style 5470-// license that can be found in the LICENSE file. 5471- 5472-package govulncheck 5473- 5474-import "time" 5475- 5476-// Result is the result of vulnerability scanning. 5477-type Result struct { 5478- // Vulns contains all vulnerabilities that are called or imported by 5479- // the analyzed module. 5480- Vulns []*Vuln `json:",omitempty"` 5481- 5482- // Mode contains the source of the vulnerability info. 5483- // Clients of the gopls.fetch_vulncheck_result command may need 5484- // to interpret the vulnerabilities differently based on the 5485- // analysis mode. For example, Vuln without callstack traces 5486- // indicate a vulnerability that is not used if the result was 5487- // from 'govulncheck' analysis mode. On the other hand, Vuln 5488- // without callstack traces just implies the package with the 5489- // vulnerability is known to the workspace and we do not know 5490- // whether the vulnerable symbols are actually used or not. 5491- Mode AnalysisMode `json:",omitempty"` 5492- 5493- // AsOf describes when this Result was computed using govulncheck. 5494- // It is valid only with the govulncheck analysis mode. 5495- AsOf time.Time `json:",omitempty"` 5496-} 5497- 5498-type AnalysisMode string 5499- 5500-const ( 5501- ModeInvalid AnalysisMode = "" // zero value 5502- ModeGovulncheck AnalysisMode = "govulncheck" 5503- ModeImports AnalysisMode = "imports" 5504-) 5505diff -urN a/gopls/internal/govulncheck/types_not118.go b/gopls/internal/govulncheck/types_not118.go 5506--- a/gopls/internal/govulncheck/types_not118.go 2000-01-01 00:00:00.000000000 -0000 5507+++ b/gopls/internal/govulncheck/types_not118.go 1970-01-01 00:00:00.000000000 +0000 5508@@ -1,126 +0,0 @@ 5509-// Copyright 2022 The Go Authors. All rights reserved. 5510-// Use of this source code is governed by a BSD-style 5511-// license that can be found in the LICENSE file. 5512- 5513-//go:build !go1.18 5514-// +build !go1.18 5515- 5516-package govulncheck 5517- 5518-import ( 5519- "go/token" 5520- 5521- "golang.org/x/vuln/osv" 5522-) 5523- 5524-// Vuln represents a single OSV entry. 5525-type Vuln struct { 5526- // OSV contains all data from the OSV entry for this vulnerability. 5527- OSV *osv.Entry 5528- 5529- // Modules contains all of the modules in the OSV entry where a 5530- // vulnerable package is imported by the target source code or binary. 5531- // 5532- // For example, a module M with two packages M/p1 and M/p2, where only p1 5533- // is vulnerable, will appear in this list if and only if p1 is imported by 5534- // the target source code or binary. 5535- Modules []*Module 5536-} 5537- 5538-func (v *Vuln) IsCalled() bool { 5539- return false 5540-} 5541- 5542-// Module represents a specific vulnerability relevant to a single module. 5543-type Module struct { 5544- // Path is the module path of the module containing the vulnerability. 5545- // 5546- // Importable packages in the standard library will have the path "stdlib". 5547- Path string 5548- 5549- // FoundVersion is the module version where the vulnerability was found. 5550- FoundVersion string 5551- 5552- // FixedVersion is the module version where the vulnerability was 5553- // fixed. If there are multiple fixed versions in the OSV report, this will 5554- // be the latest fixed version. 5555- // 5556- // This is empty if a fix is not available. 5557- FixedVersion string 5558- 5559- // Packages contains all the vulnerable packages in OSV entry that are 5560- // imported by the target source code or binary. 5561- // 5562- // For example, given a module M with two packages M/p1 and M/p2, where 5563- // both p1 and p2 are vulnerable, p1 and p2 will each only appear in this 5564- // list they are individually imported by the target source code or binary. 5565- Packages []*Package 5566-} 5567- 5568-// Package is a Go package with known vulnerable symbols. 5569-type Package struct { 5570- // Path is the import path of the package containing the vulnerability. 5571- Path string 5572- 5573- // CallStacks contains a representative call stack for each 5574- // vulnerable symbol that is called. 5575- // 5576- // For vulnerabilities found from binary analysis, only CallStack.Symbol 5577- // will be provided. 5578- // 5579- // For non-affecting vulnerabilities reported from the source mode 5580- // analysis, this will be empty. 5581- CallStacks []CallStack 5582-} 5583- 5584-// CallStacks contains a representative call stack for a vulnerable 5585-// symbol. 5586-type CallStack struct { 5587- // Symbol is the name of the detected vulnerable function 5588- // or method. 5589- // 5590- // This follows the naming convention in the OSV report. 5591- Symbol string 5592- 5593- // Summary is a one-line description of the callstack, used by the 5594- // default govulncheck mode. 5595- // 5596- // Example: module3.main calls github.com/shiyanhui/dht.DHT.Run 5597- Summary string 5598- 5599- // Frames contains an entry for each stack in the call stack. 5600- // 5601- // Frames are sorted starting from the entry point to the 5602- // imported vulnerable symbol. The last frame in Frames should match 5603- // Symbol. 5604- Frames []*StackFrame 5605-} 5606- 5607-// StackFrame represents a call stack entry. 5608-type StackFrame struct { 5609- // PackagePath is the import path. 5610- PkgPath string 5611- 5612- // FuncName is the function name. 5613- FuncName string 5614- 5615- // RecvType is the fully qualified receiver type, 5616- // if the called symbol is a method. 5617- // 5618- // The client can create the final symbol name by 5619- // prepending RecvType to FuncName. 5620- RecvType string 5621- 5622- // Position describes an arbitrary source position 5623- // including the file, line, and column location. 5624- // A Position is valid if the line number is > 0. 5625- Position token.Position 5626-} 5627- 5628-func (sf *StackFrame) Name() string { 5629- return "" 5630-} 5631- 5632-func (sf *StackFrame) Pos() string { 5633- return "" 5634-} 5635diff -urN a/gopls/internal/govulncheck/util.go b/gopls/internal/govulncheck/util.go 5636--- a/gopls/internal/govulncheck/util.go 2000-01-01 00:00:00.000000000 -0000 5637+++ b/gopls/internal/govulncheck/util.go 1970-01-01 00:00:00.000000000 +0000 5638@@ -1,36 +0,0 @@ 5639-// Copyright 2022 The Go Authors. All rights reserved. 5640-// Use of this source code is governed by a BSD-style 5641-// license that can be found in the LICENSE file. 5642- 5643-//go:build go1.18 5644-// +build go1.18 5645- 5646-package govulncheck 5647- 5648-import ( 5649- "golang.org/x/mod/semver" 5650- isem "golang.org/x/tools/gopls/internal/govulncheck/semver" 5651- "golang.org/x/vuln/osv" 5652-) 5653- 5654-// LatestFixed returns the latest fixed version in the list of affected ranges, 5655-// or the empty string if there are no fixed versions. 5656-func LatestFixed(modulePath string, as []osv.Affected) string { 5657- v := "" 5658- for _, a := range as { 5659- if a.Package.Name != modulePath { 5660- continue 5661- } 5662- for _, r := range a.Ranges { 5663- if r.Type == osv.TypeSemver { 5664- for _, e := range r.Events { 5665- if e.Fixed != "" && (v == "" || 5666- semver.Compare(isem.CanonicalizeSemverPrefix(e.Fixed), isem.CanonicalizeSemverPrefix(v)) > 0) { 5667- v = e.Fixed 5668- } 5669- } 5670- } 5671- } 5672- } 5673- return v 5674-} 5675diff -urN a/gopls/internal/govulncheck/vulncache.go b/gopls/internal/govulncheck/vulncache.go 5676--- a/gopls/internal/govulncheck/vulncache.go 2000-01-01 00:00:00.000000000 -0000 5677+++ b/gopls/internal/govulncheck/vulncache.go 1970-01-01 00:00:00.000000000 +0000 5678@@ -1,105 +0,0 @@ 5679-// Copyright 2022 The Go Authors. All rights reserved. 5680-// Use of this source code is governed by a BSD-style 5681-// license that can be found in the LICENSE file. 5682- 5683-//go:build go1.18 5684-// +build go1.18 5685- 5686-package govulncheck 5687- 5688-import ( 5689- "sync" 5690- "time" 5691- 5692- vulnc "golang.org/x/vuln/client" 5693- "golang.org/x/vuln/osv" 5694-) 5695- 5696-// inMemoryCache is an implementation of the [client.Cache] interface 5697-// that "decorates" another instance of that interface to provide 5698-// an additional layer of (memory-based) caching. 5699-type inMemoryCache struct { 5700- mu sync.Mutex 5701- underlying vulnc.Cache 5702- db map[string]*db 5703-} 5704- 5705-var _ vulnc.Cache = &inMemoryCache{} 5706- 5707-type db struct { 5708- retrieved time.Time 5709- index vulnc.DBIndex 5710- entry map[string][]*osv.Entry 5711-} 5712- 5713-// NewInMemoryCache returns a new memory-based cache that decorates 5714-// the provided cache (file-based, perhaps). 5715-func NewInMemoryCache(underlying vulnc.Cache) *inMemoryCache { 5716- return &inMemoryCache{ 5717- underlying: underlying, 5718- db: make(map[string]*db), 5719- } 5720-} 5721- 5722-func (c *inMemoryCache) lookupDBLocked(dbName string) *db { 5723- cached := c.db[dbName] 5724- if cached == nil { 5725- cached = &db{entry: make(map[string][]*osv.Entry)} 5726- c.db[dbName] = cached 5727- } 5728- return cached 5729-} 5730- 5731-// ReadIndex returns the index for dbName from the cache, or returns zero values 5732-// if it is not present. 5733-func (c *inMemoryCache) ReadIndex(dbName string) (vulnc.DBIndex, time.Time, error) { 5734- c.mu.Lock() 5735- defer c.mu.Unlock() 5736- cached := c.lookupDBLocked(dbName) 5737- 5738- if cached.retrieved.IsZero() { 5739- // First time ReadIndex is called. 5740- index, retrieved, err := c.underlying.ReadIndex(dbName) 5741- if err != nil { 5742- return index, retrieved, err 5743- } 5744- cached.index, cached.retrieved = index, retrieved 5745- } 5746- return cached.index, cached.retrieved, nil 5747-} 5748- 5749-// WriteIndex puts the index and retrieved time into the cache. 5750-func (c *inMemoryCache) WriteIndex(dbName string, index vulnc.DBIndex, retrieved time.Time) error { 5751- c.mu.Lock() 5752- defer c.mu.Unlock() 5753- cached := c.lookupDBLocked(dbName) 5754- cached.index, cached.retrieved = index, retrieved 5755- // TODO(hyangah): shouldn't we invalidate all cached entries? 5756- return c.underlying.WriteIndex(dbName, index, retrieved) 5757-} 5758- 5759-// ReadEntries returns the vulndb entries for path from the cache. 5760-func (c *inMemoryCache) ReadEntries(dbName, path string) ([]*osv.Entry, error) { 5761- c.mu.Lock() 5762- defer c.mu.Unlock() 5763- cached := c.lookupDBLocked(dbName) 5764- entries, ok := cached.entry[path] 5765- if !ok { 5766- // cache miss 5767- entries, err := c.underlying.ReadEntries(dbName, path) 5768- if err != nil { 5769- return entries, err 5770- } 5771- cached.entry[path] = entries 5772- } 5773- return entries, nil 5774-} 5775- 5776-// WriteEntries puts the entries for path into the cache. 5777-func (c *inMemoryCache) WriteEntries(dbName, path string, entries []*osv.Entry) error { 5778- c.mu.Lock() 5779- defer c.mu.Unlock() 5780- cached := c.lookupDBLocked(dbName) 5781- cached.entry[path] = entries 5782- return c.underlying.WriteEntries(dbName, path, entries) 5783-} 5784diff -urN a/gopls/internal/hooks/analysis_116.go b/gopls/internal/hooks/analysis_116.go 5785--- a/gopls/internal/hooks/analysis_116.go 2000-01-01 00:00:00.000000000 -0000 5786+++ b/gopls/internal/hooks/analysis_116.go 1970-01-01 00:00:00.000000000 +0000 5787@@ -1,14 +0,0 @@ 5788-// Copyright 2021 The Go Authors. All rights reserved. 5789-// Use of this source code is governed by a BSD-style 5790-// license that can be found in the LICENSE file. 5791- 5792-//go:build !go1.19 5793-// +build !go1.19 5794- 5795-package hooks 5796- 5797-import "golang.org/x/tools/gopls/internal/lsp/source" 5798- 5799-func updateAnalyzers(options *source.Options) { 5800- options.StaticcheckSupported = false 5801-} 5802diff -urN a/gopls/internal/hooks/analysis_119.go b/gopls/internal/hooks/analysis_119.go 5803--- a/gopls/internal/hooks/analysis_119.go 2000-01-01 00:00:00.000000000 -0000 5804+++ b/gopls/internal/hooks/analysis_119.go 1970-01-01 00:00:00.000000000 +0000 5805@@ -1,62 +0,0 @@ 5806-// Copyright 2019 The Go Authors. All rights reserved. 5807-// Use of this source code is governed by a BSD-style 5808-// license that can be found in the LICENSE file. 5809- 5810-//go:build go1.19 5811-// +build go1.19 5812- 5813-package hooks 5814- 5815-import ( 5816- "golang.org/x/tools/gopls/internal/lsp/protocol" 5817- "golang.org/x/tools/gopls/internal/lsp/source" 5818- "honnef.co/go/tools/analysis/lint" 5819- "honnef.co/go/tools/quickfix" 5820- "honnef.co/go/tools/simple" 5821- "honnef.co/go/tools/staticcheck" 5822- "honnef.co/go/tools/stylecheck" 5823-) 5824- 5825-func updateAnalyzers(options *source.Options) { 5826- options.StaticcheckSupported = true 5827- 5828- mapSeverity := func(severity lint.Severity) protocol.DiagnosticSeverity { 5829- switch severity { 5830- case lint.SeverityError: 5831- return protocol.SeverityError 5832- case lint.SeverityDeprecated: 5833- // TODO(dh): in LSP, deprecated is a tag, not a severity. 5834- // We'll want to support this once we enable SA5011. 5835- return protocol.SeverityWarning 5836- case lint.SeverityWarning: 5837- return protocol.SeverityWarning 5838- case lint.SeverityInfo: 5839- return protocol.SeverityInformation 5840- case lint.SeverityHint: 5841- return protocol.SeverityHint 5842- default: 5843- return protocol.SeverityWarning 5844- } 5845- } 5846- add := func(analyzers []*lint.Analyzer, skip map[string]struct{}) { 5847- for _, a := range analyzers { 5848- if _, ok := skip[a.Analyzer.Name]; ok { 5849- continue 5850- } 5851- 5852- enabled := !a.Doc.NonDefault 5853- options.AddStaticcheckAnalyzer(a.Analyzer, enabled, mapSeverity(a.Doc.Severity)) 5854- } 5855- } 5856- 5857- add(simple.Analyzers, nil) 5858- add(staticcheck.Analyzers, map[string]struct{}{ 5859- // This check conflicts with the vet printf check (golang/go#34494). 5860- "SA5009": {}, 5861- // This check relies on facts from dependencies, which 5862- // we don't currently compute. 5863- "SA5011": {}, 5864- }) 5865- add(stylecheck.Analyzers, nil) 5866- add(quickfix.Analyzers, nil) 5867-} 5868diff -urN a/gopls/internal/hooks/diff.go b/gopls/internal/hooks/diff.go 5869--- a/gopls/internal/hooks/diff.go 2000-01-01 00:00:00.000000000 -0000 5870+++ b/gopls/internal/hooks/diff.go 1970-01-01 00:00:00.000000000 +0000 5871@@ -1,169 +0,0 @@ 5872-// Copyright 2019 The Go Authors. All rights reserved. 5873-// Use of this source code is governed by a BSD-style 5874-// license that can be found in the LICENSE file. 5875- 5876-package hooks 5877- 5878-import ( 5879- "encoding/json" 5880- "fmt" 5881- "io/ioutil" 5882- "log" 5883- "os" 5884- "path/filepath" 5885- "runtime" 5886- "sync" 5887- "time" 5888- 5889- "github.com/sergi/go-diff/diffmatchpatch" 5890- "golang.org/x/tools/internal/bug" 5891- "golang.org/x/tools/internal/diff" 5892-) 5893- 5894-// structure for saving information about diffs 5895-// while the new code is being rolled out 5896-type diffstat struct { 5897- Before, After int 5898- Oldedits, Newedits int 5899- Oldtime, Newtime time.Duration 5900- Stack string 5901- Msg string `json:",omitempty"` // for errors 5902- Ignored int `json:",omitempty"` // numbr of skipped records with 0 edits 5903-} 5904- 5905-var ( 5906- ignoredMu sync.Mutex 5907- ignored int // counter of diff requests on equal strings 5908- 5909- diffStatsOnce sync.Once 5910- diffStats *os.File // never closed 5911-) 5912- 5913-// save writes a JSON record of statistics about diff requests to a temporary file. 5914-func (s *diffstat) save() { 5915- diffStatsOnce.Do(func() { 5916- f, err := ioutil.TempFile("", "gopls-diff-stats-*") 5917- if err != nil { 5918- log.Printf("can't create diff stats temp file: %v", err) // e.g. disk full 5919- return 5920- } 5921- diffStats = f 5922- }) 5923- if diffStats == nil { 5924- return 5925- } 5926- 5927- // diff is frequently called with equal strings, 5928- // so we count repeated instances but only print every 15th. 5929- ignoredMu.Lock() 5930- if s.Oldedits == 0 && s.Newedits == 0 { 5931- ignored++ 5932- if ignored < 15 { 5933- ignoredMu.Unlock() 5934- return 5935- } 5936- } 5937- s.Ignored = ignored 5938- ignored = 0 5939- ignoredMu.Unlock() 5940- 5941- // Record the name of the file in which diff was called. 5942- // There aren't many calls, so only the base name is needed. 5943- if _, file, line, ok := runtime.Caller(2); ok { 5944- s.Stack = fmt.Sprintf("%s:%d", filepath.Base(file), line) 5945- } 5946- x, err := json.Marshal(s) 5947- if err != nil { 5948- log.Fatalf("internal error marshalling JSON: %v", err) 5949- } 5950- fmt.Fprintf(diffStats, "%s\n", x) 5951-} 5952- 5953-// disaster is called when the diff algorithm panics or produces a 5954-// diff that cannot be applied. It saves the broken input in a 5955-// new temporary file and logs the file name, which is returned. 5956-func disaster(before, after string) string { 5957- // We use the pid to salt the name, not os.TempFile, 5958- // so that each process creates at most one file. 5959- // One is sufficient for a bug report. 5960- filename := fmt.Sprintf("%s/gopls-diff-bug-%x", os.TempDir(), os.Getpid()) 5961- 5962- // We use NUL as a separator: it should never appear in Go source. 5963- data := before + "\x00" + after 5964- 5965- if err := ioutil.WriteFile(filename, []byte(data), 0600); err != nil { 5966- log.Printf("failed to write diff bug report: %v", err) 5967- return "" 5968- } 5969- 5970- bug.Reportf("Bug detected in diff algorithm! Please send file %s to the maintainers of gopls if you are comfortable sharing its contents.", filename) 5971- 5972- return filename 5973-} 5974- 5975-// BothDiffs edits calls both the new and old diffs, checks that the new diffs 5976-// change before into after, and attempts to preserve some statistics. 5977-func BothDiffs(before, after string) (edits []diff.Edit) { 5978- // The new diff code contains a lot of internal checks that panic when they 5979- // fail. This code catches the panics, or other failures, tries to save 5980- // the failing example (and it would ask the user to send it back to us, and 5981- // changes options.newDiff to 'old', if only we could figure out how.) 5982- stat := diffstat{Before: len(before), After: len(after)} 5983- now := time.Now() 5984- oldedits := ComputeEdits(before, after) 5985- stat.Oldedits = len(oldedits) 5986- stat.Oldtime = time.Since(now) 5987- defer func() { 5988- if r := recover(); r != nil { 5989- disaster(before, after) 5990- edits = oldedits 5991- } 5992- }() 5993- now = time.Now() 5994- newedits := diff.Strings(before, after) 5995- stat.Newedits = len(newedits) 5996- stat.Newtime = time.Now().Sub(now) 5997- got, err := diff.Apply(before, newedits) 5998- if err != nil || got != after { 5999- stat.Msg += "FAIL" 6000- disaster(before, after) 6001- stat.save() 6002- return oldedits 6003- } 6004- stat.save() 6005- return newedits 6006-} 6007- 6008-// ComputeEdits computes a diff using the github.com/sergi/go-diff implementation. 6009-func ComputeEdits(before, after string) (edits []diff.Edit) { 6010- // The go-diff library has an unresolved panic (see golang/go#278774). 6011- // TODO(rstambler): Remove the recover once the issue has been fixed 6012- // upstream. 6013- defer func() { 6014- if r := recover(); r != nil { 6015- bug.Reportf("unable to compute edits: %s", r) 6016- // Report one big edit for the whole file. 6017- edits = []diff.Edit{{ 6018- Start: 0, 6019- End: len(before), 6020- New: after, 6021- }} 6022- } 6023- }() 6024- diffs := diffmatchpatch.New().DiffMain(before, after, true) 6025- edits = make([]diff.Edit, 0, len(diffs)) 6026- offset := 0 6027- for _, d := range diffs { 6028- start := offset 6029- switch d.Type { 6030- case diffmatchpatch.DiffDelete: 6031- offset += len(d.Text) 6032- edits = append(edits, diff.Edit{Start: start, End: offset}) 6033- case diffmatchpatch.DiffEqual: 6034- offset += len(d.Text) 6035- case diffmatchpatch.DiffInsert: 6036- edits = append(edits, diff.Edit{Start: start, End: start, New: d.Text}) 6037- } 6038- } 6039- return edits 6040-} 6041diff -urN a/gopls/internal/hooks/diff_test.go b/gopls/internal/hooks/diff_test.go 6042--- a/gopls/internal/hooks/diff_test.go 2000-01-01 00:00:00.000000000 -0000 6043+++ b/gopls/internal/hooks/diff_test.go 1970-01-01 00:00:00.000000000 +0000 6044@@ -1,33 +0,0 @@ 6045-// Copyright 2019 The Go Authors. All rights reserved. 6046-// Use of this source code is governed by a BSD-style 6047-// license that can be found in the LICENSE file. 6048- 6049-package hooks 6050- 6051-import ( 6052- "io/ioutil" 6053- "os" 6054- "testing" 6055- 6056- "golang.org/x/tools/internal/diff/difftest" 6057-) 6058- 6059-func TestDiff(t *testing.T) { 6060- difftest.DiffTest(t, ComputeEdits) 6061-} 6062- 6063-func TestDisaster(t *testing.T) { 6064- a := "This is a string,(\u0995) just for basic\nfunctionality" 6065- b := "This is another string, (\u0996) to see if disaster will store stuff correctly" 6066- fname := disaster(a, b) 6067- buf, err := ioutil.ReadFile(fname) 6068- if err != nil { 6069- t.Fatal(err) 6070- } 6071- if string(buf) != a+"\x00"+b { 6072- t.Error("failed to record original strings") 6073- } 6074- if err := os.Remove(fname); err != nil { 6075- t.Error(err) 6076- } 6077-} 6078diff -urN a/gopls/internal/hooks/gen-licenses.sh b/gopls/internal/hooks/gen-licenses.sh 6079--- a/gopls/internal/hooks/gen-licenses.sh 2000-01-01 00:00:00.000000000 -0000 6080+++ b/gopls/internal/hooks/gen-licenses.sh 1970-01-01 00:00:00.000000000 +0000 6081@@ -1,38 +0,0 @@ 6082-#!/bin/bash -eu 6083- 6084-# Copyright 2020 The Go Authors. All rights reserved. 6085-# Use of this source code is governed by a BSD-style 6086-# license that can be found in the LICENSE file. 6087- 6088-set -o pipefail 6089- 6090-output=$1 6091-tempfile=$(mktemp) 6092-cd $(dirname $0) 6093- 6094-cat > $tempfile <<END 6095-// Copyright 2020 The Go Authors. All rights reserved. 6096-// Use of this source code is governed by a BSD-style 6097-// license that can be found in the LICENSE file. 6098- 6099-//go:generate ./gen-licenses.sh licenses.go 6100-package hooks 6101- 6102-const licensesText = \` 6103-END 6104- 6105-# List all the modules gopls depends on, except other golang.org modules, which 6106-# are known to have the same license. 6107-mods=$(go list -deps -f '{{with .Module}}{{.Path}}{{end}}' golang.org/x/tools/gopls | sort -u | grep -v golang.org) 6108-for mod in $mods; do 6109- # Find the license file, either LICENSE or COPYING, and add it to the result. 6110- dir=$(go list -m -f {{.Dir}} $mod) 6111- license=$(ls -1 $dir | grep -E -i '^(LICENSE|COPYING)$') 6112- echo "-- $mod $license --" >> $tempfile 6113- echo >> $tempfile 6114- sed 's/^-- / &/' $dir/$license >> $tempfile 6115- echo >> $tempfile 6116-done 6117- 6118-echo "\`" >> $tempfile 6119-mv $tempfile $output 6120\ No newline at end of file 6121diff -urN a/gopls/internal/hooks/gofumpt_117.go b/gopls/internal/hooks/gofumpt_117.go 6122--- a/gopls/internal/hooks/gofumpt_117.go 2000-01-01 00:00:00.000000000 -0000 6123+++ b/gopls/internal/hooks/gofumpt_117.go 1970-01-01 00:00:00.000000000 +0000 6124@@ -1,13 +0,0 @@ 6125-// Copyright 2021 The Go Authors. All rights reserved. 6126-// Use of this source code is governed by a BSD-style 6127-// license that can be found in the LICENSE file. 6128- 6129-//go:build !go1.18 6130-// +build !go1.18 6131- 6132-package hooks 6133- 6134-import "golang.org/x/tools/gopls/internal/lsp/source" 6135- 6136-func updateGofumpt(options *source.Options) { 6137-} 6138diff -urN a/gopls/internal/hooks/gofumpt_118.go b/gopls/internal/hooks/gofumpt_118.go 6139--- a/gopls/internal/hooks/gofumpt_118.go 2000-01-01 00:00:00.000000000 -0000 6140+++ b/gopls/internal/hooks/gofumpt_118.go 1970-01-01 00:00:00.000000000 +0000 6141@@ -1,24 +0,0 @@ 6142-// Copyright 2022 The Go Authors. All rights reserved. 6143-// Use of this source code is governed by a BSD-style 6144-// license that can be found in the LICENSE file. 6145- 6146-//go:build go1.18 6147-// +build go1.18 6148- 6149-package hooks 6150- 6151-import ( 6152- "context" 6153- 6154- "golang.org/x/tools/gopls/internal/lsp/source" 6155- "mvdan.cc/gofumpt/format" 6156-) 6157- 6158-func updateGofumpt(options *source.Options) { 6159- options.GofumptFormat = func(ctx context.Context, langVersion, modulePath string, src []byte) ([]byte, error) { 6160- return format.Source(src, format.Options{ 6161- LangVersion: langVersion, 6162- ModulePath: modulePath, 6163- }) 6164- } 6165-} 6166diff -urN a/gopls/internal/hooks/hooks.go b/gopls/internal/hooks/hooks.go 6167--- a/gopls/internal/hooks/hooks.go 2000-01-01 00:00:00.000000000 -0000 6168+++ b/gopls/internal/hooks/hooks.go 1970-01-01 00:00:00.000000000 +0000 6169@@ -1,31 +0,0 @@ 6170-// Copyright 2019 The Go Authors. All rights reserved. 6171-// Use of this source code is governed by a BSD-style 6172-// license that can be found in the LICENSE file. 6173- 6174-// Package hooks adds all the standard gopls implementations. 6175-// This can be used in tests without needing to use the gopls main, and is 6176-// also the place to edit for custom builds of gopls. 6177-package hooks // import "golang.org/x/tools/gopls/internal/hooks" 6178- 6179-import ( 6180- "golang.org/x/tools/gopls/internal/lsp/source" 6181- "golang.org/x/tools/internal/diff" 6182- "mvdan.cc/xurls/v2" 6183-) 6184- 6185-func Options(options *source.Options) { 6186- options.LicensesText = licensesText 6187- if options.GoDiff { 6188- switch options.NewDiff { 6189- case "old": 6190- options.ComputeEdits = ComputeEdits 6191- case "new": 6192- options.ComputeEdits = diff.Strings 6193- default: 6194- options.ComputeEdits = BothDiffs 6195- } 6196- } 6197- options.URLRegexp = xurls.Relaxed() 6198- updateAnalyzers(options) 6199- updateGofumpt(options) 6200-} 6201diff -urN a/gopls/internal/hooks/licenses.go b/gopls/internal/hooks/licenses.go 6202--- a/gopls/internal/hooks/licenses.go 2000-01-01 00:00:00.000000000 -0000 6203+++ b/gopls/internal/hooks/licenses.go 1970-01-01 00:00:00.000000000 +0000 6204@@ -1,169 +0,0 @@ 6205-// Copyright 2020 The Go Authors. All rights reserved. 6206-// Use of this source code is governed by a BSD-style 6207-// license that can be found in the LICENSE file. 6208- 6209-//go:generate ./gen-licenses.sh licenses.go 6210-package hooks 6211- 6212-const licensesText = ` 6213--- github.com/BurntSushi/toml COPYING -- 6214- 6215-The MIT License (MIT) 6216- 6217-Copyright (c) 2013 TOML authors 6218- 6219-Permission is hereby granted, free of charge, to any person obtaining a copy 6220-of this software and associated documentation files (the "Software"), to deal 6221-in the Software without restriction, including without limitation the rights 6222-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6223-copies of the Software, and to permit persons to whom the Software is 6224-furnished to do so, subject to the following conditions: 6225- 6226-The above copyright notice and this permission notice shall be included in 6227-all copies or substantial portions of the Software. 6228- 6229-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 6230-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 6231-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 6232-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 6233-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 6234-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 6235-THE SOFTWARE. 6236- 6237--- github.com/google/go-cmp LICENSE -- 6238- 6239-Copyright (c) 2017 The Go Authors. All rights reserved. 6240- 6241-Redistribution and use in source and binary forms, with or without 6242-modification, are permitted provided that the following conditions are 6243-met: 6244- 6245- * Redistributions of source code must retain the above copyright 6246-notice, this list of conditions and the following disclaimer. 6247- * Redistributions in binary form must reproduce the above 6248-copyright notice, this list of conditions and the following disclaimer 6249-in the documentation and/or other materials provided with the 6250-distribution. 6251- * Neither the name of Google Inc. nor the names of its 6252-contributors may be used to endorse or promote products derived from 6253-this software without specific prior written permission. 6254- 6255-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6256-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 6257-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 6258-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 6259-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 6260-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 6261-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6262-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6263-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6264-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 6265-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6266- 6267--- github.com/sergi/go-diff LICENSE -- 6268- 6269-Copyright (c) 2012-2016 The go-diff Authors. All rights reserved. 6270- 6271-Permission is hereby granted, free of charge, to any person obtaining a 6272-copy of this software and associated documentation files (the "Software"), 6273-to deal in the Software without restriction, including without limitation 6274-the rights to use, copy, modify, merge, publish, distribute, sublicense, 6275-and/or sell copies of the Software, and to permit persons to whom the 6276-Software is furnished to do so, subject to the following conditions: 6277- 6278-The above copyright notice and this permission notice shall be included 6279-in all copies or substantial portions of the Software. 6280- 6281-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 6282-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 6283-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 6284-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 6285-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 6286-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 6287-DEALINGS IN THE SOFTWARE. 6288- 6289- 6290--- honnef.co/go/tools LICENSE -- 6291- 6292-Copyright (c) 2016 Dominik Honnef 6293- 6294-Permission is hereby granted, free of charge, to any person obtaining 6295-a copy of this software and associated documentation files (the 6296-"Software"), to deal in the Software without restriction, including 6297-without limitation the rights to use, copy, modify, merge, publish, 6298-distribute, sublicense, and/or sell copies of the Software, and to 6299-permit persons to whom the Software is furnished to do so, subject to 6300-the following conditions: 6301- 6302-The above copyright notice and this permission notice shall be 6303-included in all copies or substantial portions of the Software. 6304- 6305-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 6306-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 6307-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 6308-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 6309-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 6310-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 6311-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6312- 6313--- mvdan.cc/gofumpt LICENSE -- 6314- 6315-Copyright (c) 2019, Daniel Martí. All rights reserved. 6316- 6317-Redistribution and use in source and binary forms, with or without 6318-modification, are permitted provided that the following conditions are 6319-met: 6320- 6321- * Redistributions of source code must retain the above copyright 6322-notice, this list of conditions and the following disclaimer. 6323- * Redistributions in binary form must reproduce the above 6324-copyright notice, this list of conditions and the following disclaimer 6325-in the documentation and/or other materials provided with the 6326-distribution. 6327- * Neither the name of the copyright holder nor the names of its 6328-contributors may be used to endorse or promote products derived from 6329-this software without specific prior written permission. 6330- 6331-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6332-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 6333-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 6334-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 6335-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 6336-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 6337-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6338-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6339-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6340-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 6341-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6342- 6343--- mvdan.cc/xurls/v2 LICENSE -- 6344- 6345-Copyright (c) 2015, Daniel Martí. All rights reserved. 6346- 6347-Redistribution and use in source and binary forms, with or without 6348-modification, are permitted provided that the following conditions are 6349-met: 6350- 6351- * Redistributions of source code must retain the above copyright 6352-notice, this list of conditions and the following disclaimer. 6353- * Redistributions in binary form must reproduce the above 6354-copyright notice, this list of conditions and the following disclaimer 6355-in the documentation and/or other materials provided with the 6356-distribution. 6357- * Neither the name of the copyright holder nor the names of its 6358-contributors may be used to endorse or promote products derived from 6359-this software without specific prior written permission. 6360- 6361-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6362-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 6363-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 6364-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 6365-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 6366-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 6367-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6368-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6369-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6370-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 6371-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6372- 6373-` 6374diff -urN a/gopls/internal/hooks/licenses_test.go b/gopls/internal/hooks/licenses_test.go 6375--- a/gopls/internal/hooks/licenses_test.go 2000-01-01 00:00:00.000000000 -0000 6376+++ b/gopls/internal/hooks/licenses_test.go 1970-01-01 00:00:00.000000000 +0000 6377@@ -1,47 +0,0 @@ 6378-// Copyright 2020 The Go Authors. All rights reserved. 6379-// Use of this source code is governed by a BSD-style 6380-// license that can be found in the LICENSE file. 6381- 6382-package hooks 6383- 6384-import ( 6385- "bytes" 6386- "io/ioutil" 6387- "os/exec" 6388- "runtime" 6389- "testing" 6390- 6391- "golang.org/x/tools/internal/testenv" 6392-) 6393- 6394-func TestLicenses(t *testing.T) { 6395- // License text differs for older Go versions because staticcheck or gofumpt 6396- // isn't supported for those versions, and this fails for unknown, unrelated 6397- // reasons on Kokoro legacy CI. 6398- testenv.NeedsGo1Point(t, 19) 6399- 6400- if runtime.GOOS != "linux" && runtime.GOOS != "darwin" { 6401- t.Skip("generating licenses only works on Unixes") 6402- } 6403- tmp, err := ioutil.TempFile("", "") 6404- if err != nil { 6405- t.Fatal(err) 6406- } 6407- tmp.Close() 6408- 6409- if out, err := exec.Command("./gen-licenses.sh", tmp.Name()).CombinedOutput(); err != nil { 6410- t.Fatalf("generating licenses failed: %q, %v", out, err) 6411- } 6412- 6413- got, err := ioutil.ReadFile(tmp.Name()) 6414- if err != nil { 6415- t.Fatal(err) 6416- } 6417- want, err := ioutil.ReadFile("licenses.go") 6418- if err != nil { 6419- t.Fatal(err) 6420- } 6421- if !bytes.Equal(got, want) { 6422- t.Error("combined license text needs updating. Run: `go generate ./internal/hooks` from the gopls module.") 6423- } 6424-} 6425diff -urN a/gopls/internal/lsp/analysis/embeddirective/embeddirective.go b/gopls/internal/lsp/analysis/embeddirective/embeddirective.go 6426--- a/gopls/internal/lsp/analysis/embeddirective/embeddirective.go 2000-01-01 00:00:00.000000000 -0000 6427+++ b/gopls/internal/lsp/analysis/embeddirective/embeddirective.go 1970-01-01 00:00:00.000000000 +0000 6428@@ -1,58 +0,0 @@ 6429-// Copyright 2022 The Go Authors. All rights reserved. 6430-// Use of this source code is governed by a BSD-style 6431-// license that can be found in the LICENSE file. 6432- 6433-// Package embeddirective defines an Analyzer that validates import for //go:embed directive. 6434-package embeddirective 6435- 6436-import ( 6437- "go/ast" 6438- "strings" 6439- 6440- "golang.org/x/tools/go/analysis" 6441-) 6442- 6443-const Doc = `check for //go:embed directive import 6444- 6445-This analyzer checks that the embed package is imported when source code contains //go:embed comment directives. 6446-The embed package must be imported for //go:embed directives to function.import _ "embed".` 6447- 6448-var Analyzer = &analysis.Analyzer{ 6449- Name: "embed", 6450- Doc: Doc, 6451- Requires: []*analysis.Analyzer{}, 6452- Run: run, 6453- RunDespiteErrors: true, 6454-} 6455- 6456-func run(pass *analysis.Pass) (interface{}, error) { 6457- for _, f := range pass.Files { 6458- com := hasEmbedDirectiveComment(f) 6459- if com != nil { 6460- assertEmbedImport(pass, com, f) 6461- } 6462- } 6463- return nil, nil 6464-} 6465- 6466-// Check if the comment contains //go:embed directive. 6467-func hasEmbedDirectiveComment(f *ast.File) *ast.Comment { 6468- for _, cg := range f.Comments { 6469- for _, c := range cg.List { 6470- if strings.HasPrefix(c.Text, "//go:embed ") { 6471- return c 6472- } 6473- } 6474- } 6475- return nil 6476-} 6477- 6478-// Verifies that "embed" import exists for //go:embed directive. 6479-func assertEmbedImport(pass *analysis.Pass, com *ast.Comment, f *ast.File) { 6480- for _, imp := range f.Imports { 6481- if "\"embed\"" == imp.Path.Value { 6482- return 6483- } 6484- } 6485- pass.Report(analysis.Diagnostic{Pos: com.Pos(), End: com.Pos() + 10, Message: "The \"embed\" package must be imported when using go:embed directives."}) 6486-} 6487diff -urN a/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go b/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go 6488--- a/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go 2000-01-01 00:00:00.000000000 -0000 6489+++ b/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go 1970-01-01 00:00:00.000000000 +0000 6490@@ -1,22 +0,0 @@ 6491-// Copyright 2022 The Go Authors. All rights reserved. 6492-// Use of this source code is governed by a BSD-style 6493-// license that can be found in the LICENSE file. 6494- 6495-package embeddirective 6496- 6497-import ( 6498- "testing" 6499- 6500- "golang.org/x/tools/go/analysis/analysistest" 6501- "golang.org/x/tools/internal/typeparams" 6502-) 6503- 6504-func Test(t *testing.T) { 6505- testdata := analysistest.TestData() 6506- tests := []string{"a"} 6507- if typeparams.Enabled { 6508- tests = append(tests) 6509- } 6510- 6511- analysistest.RunWithSuggestedFixes(t, testdata, Analyzer, tests...) 6512-} 6513diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go 6514--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 6515+++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 6516@@ -1,13 +0,0 @@ 6517-package a 6518- 6519-import ( 6520- "fmt" 6521-) 6522- 6523-//go:embed embedText // want "The \"embed\" package must be imported when using go:embed directives" 6524-var s string 6525- 6526-// This is main function 6527-func main() { 6528- fmt.Println(s) 6529-} 6530diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go 6531--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go 2000-01-01 00:00:00.000000000 -0000 6532+++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go 1970-01-01 00:00:00.000000000 +0000 6533@@ -1,14 +0,0 @@ 6534-package a 6535- 6536-import ( 6537- _ "embed" 6538- "fmt" 6539-) 6540- 6541-//go:embed embedText // ok 6542-var s string 6543- 6544-// This is main function 6545-func main() { 6546- fmt.Println(s) 6547-} 6548diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText 6549--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText 2000-01-01 00:00:00.000000000 -0000 6550+++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText 1970-01-01 00:00:00.000000000 +0000 6551@@ -1 +0,0 @@ 6552-Hello World 6553\ No newline at end of file 6554diff -urN a/gopls/internal/lsp/analysis/fillreturns/fillreturns.go b/gopls/internal/lsp/analysis/fillreturns/fillreturns.go 6555--- a/gopls/internal/lsp/analysis/fillreturns/fillreturns.go 2000-01-01 00:00:00.000000000 -0000 6556+++ b/gopls/internal/lsp/analysis/fillreturns/fillreturns.go 1970-01-01 00:00:00.000000000 +0000 6557@@ -1,279 +0,0 @@ 6558-// Copyright 2020 The Go Authors. All rights reserved. 6559-// Use of this source code is governed by a BSD-style 6560-// license that can be found in the LICENSE file. 6561- 6562-// Package fillreturns defines an Analyzer that will attempt to 6563-// automatically fill in a return statement that has missing 6564-// values with zero value elements. 6565-package fillreturns 6566- 6567-import ( 6568- "bytes" 6569- "fmt" 6570- "go/ast" 6571- "go/format" 6572- "go/types" 6573- "regexp" 6574- "strings" 6575- 6576- "golang.org/x/tools/go/analysis" 6577- "golang.org/x/tools/go/ast/astutil" 6578- "golang.org/x/tools/internal/analysisinternal" 6579- "golang.org/x/tools/internal/fuzzy" 6580- "golang.org/x/tools/internal/typeparams" 6581-) 6582- 6583-const Doc = `suggest fixes for errors due to an incorrect number of return values 6584- 6585-This checker provides suggested fixes for type errors of the 6586-type "wrong number of return values (want %d, got %d)". For example: 6587- func m() (int, string, *bool, error) { 6588- return 6589- } 6590-will turn into 6591- func m() (int, string, *bool, error) { 6592- return 0, "", nil, nil 6593- } 6594- 6595-This functionality is similar to https://github.com/sqs/goreturns. 6596-` 6597- 6598-var Analyzer = &analysis.Analyzer{ 6599- Name: "fillreturns", 6600- Doc: Doc, 6601- Requires: []*analysis.Analyzer{}, 6602- Run: run, 6603- RunDespiteErrors: true, 6604-} 6605- 6606-func run(pass *analysis.Pass) (interface{}, error) { 6607- info := pass.TypesInfo 6608- if info == nil { 6609- return nil, fmt.Errorf("nil TypeInfo") 6610- } 6611- 6612-outer: 6613- for _, typeErr := range pass.TypeErrors { 6614- // Filter out the errors that are not relevant to this analyzer. 6615- if !FixesError(typeErr) { 6616- continue 6617- } 6618- var file *ast.File 6619- for _, f := range pass.Files { 6620- if f.Pos() <= typeErr.Pos && typeErr.Pos <= f.End() { 6621- file = f 6622- break 6623- } 6624- } 6625- if file == nil { 6626- continue 6627- } 6628- 6629- // Get the end position of the error. 6630- // (This heuristic assumes that the buffer is formatted, 6631- // at least up to the end position of the error.) 6632- var buf bytes.Buffer 6633- if err := format.Node(&buf, pass.Fset, file); err != nil { 6634- continue 6635- } 6636- typeErrEndPos := analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), typeErr.Pos) 6637- 6638- // TODO(rfindley): much of the error handling code below returns, when it 6639- // should probably continue. 6640- 6641- // Get the path for the relevant range. 6642- path, _ := astutil.PathEnclosingInterval(file, typeErr.Pos, typeErrEndPos) 6643- if len(path) == 0 { 6644- return nil, nil 6645- } 6646- 6647- // Find the enclosing return statement. 6648- var ret *ast.ReturnStmt 6649- var retIdx int 6650- for i, n := range path { 6651- if r, ok := n.(*ast.ReturnStmt); ok { 6652- ret = r 6653- retIdx = i 6654- break 6655- } 6656- } 6657- if ret == nil { 6658- return nil, nil 6659- } 6660- 6661- // Get the function type that encloses the ReturnStmt. 6662- var enclosingFunc *ast.FuncType 6663- for _, n := range path[retIdx+1:] { 6664- switch node := n.(type) { 6665- case *ast.FuncLit: 6666- enclosingFunc = node.Type 6667- case *ast.FuncDecl: 6668- enclosingFunc = node.Type 6669- } 6670- if enclosingFunc != nil { 6671- break 6672- } 6673- } 6674- if enclosingFunc == nil || enclosingFunc.Results == nil { 6675- continue 6676- } 6677- 6678- // Skip any generic enclosing functions, since type parameters don't 6679- // have 0 values. 6680- // TODO(rfindley): We should be able to handle this if the return 6681- // values are all concrete types. 6682- if tparams := typeparams.ForFuncType(enclosingFunc); tparams != nil && tparams.NumFields() > 0 { 6683- return nil, nil 6684- } 6685- 6686- // Find the function declaration that encloses the ReturnStmt. 6687- var outer *ast.FuncDecl 6688- for _, p := range path { 6689- if p, ok := p.(*ast.FuncDecl); ok { 6690- outer = p 6691- break 6692- } 6693- } 6694- if outer == nil { 6695- return nil, nil 6696- } 6697- 6698- // Skip any return statements that contain function calls with multiple 6699- // return values. 6700- for _, expr := range ret.Results { 6701- e, ok := expr.(*ast.CallExpr) 6702- if !ok { 6703- continue 6704- } 6705- if tup, ok := info.TypeOf(e).(*types.Tuple); ok && tup.Len() > 1 { 6706- continue outer 6707- } 6708- } 6709- 6710- // Duplicate the return values to track which values have been matched. 6711- remaining := make([]ast.Expr, len(ret.Results)) 6712- copy(remaining, ret.Results) 6713- 6714- fixed := make([]ast.Expr, len(enclosingFunc.Results.List)) 6715- 6716- // For each value in the return function declaration, find the leftmost element 6717- // in the return statement that has the desired type. If no such element exists, 6718- // fill in the missing value with the appropriate "zero" value. 6719- // Beware that type information may be incomplete. 6720- var retTyps []types.Type 6721- for _, ret := range enclosingFunc.Results.List { 6722- retTyp := info.TypeOf(ret.Type) 6723- if retTyp == nil { 6724- return nil, nil 6725- } 6726- retTyps = append(retTyps, retTyp) 6727- } 6728- matches := analysisinternal.MatchingIdents(retTyps, file, ret.Pos(), info, pass.Pkg) 6729- for i, retTyp := range retTyps { 6730- var match ast.Expr 6731- var idx int 6732- for j, val := range remaining { 6733- if t := info.TypeOf(val); t == nil || !matchingTypes(t, retTyp) { 6734- continue 6735- } 6736- if !analysisinternal.IsZeroValue(val) { 6737- match, idx = val, j 6738- break 6739- } 6740- // If the current match is a "zero" value, we keep searching in 6741- // case we find a non-"zero" value match. If we do not find a 6742- // non-"zero" value, we will use the "zero" value. 6743- match, idx = val, j 6744- } 6745- 6746- if match != nil { 6747- fixed[i] = match 6748- remaining = append(remaining[:idx], remaining[idx+1:]...) 6749- } else { 6750- names, ok := matches[retTyp] 6751- if !ok { 6752- return nil, fmt.Errorf("invalid return type: %v", retTyp) 6753- } 6754- // Find the identifier most similar to the return type. 6755- // If no identifier matches the pattern, generate a zero value. 6756- if best := fuzzy.BestMatch(retTyp.String(), names); best != "" { 6757- fixed[i] = ast.NewIdent(best) 6758- } else if zero := analysisinternal.ZeroValue(file, pass.Pkg, retTyp); zero != nil { 6759- fixed[i] = zero 6760- } else { 6761- return nil, nil 6762- } 6763- } 6764- } 6765- 6766- // Remove any non-matching "zero values" from the leftover values. 6767- var nonZeroRemaining []ast.Expr 6768- for _, expr := range remaining { 6769- if !analysisinternal.IsZeroValue(expr) { 6770- nonZeroRemaining = append(nonZeroRemaining, expr) 6771- } 6772- } 6773- // Append leftover return values to end of new return statement. 6774- fixed = append(fixed, nonZeroRemaining...) 6775- 6776- newRet := &ast.ReturnStmt{ 6777- Return: ret.Pos(), 6778- Results: fixed, 6779- } 6780- 6781- // Convert the new return statement AST to text. 6782- var newBuf bytes.Buffer 6783- if err := format.Node(&newBuf, pass.Fset, newRet); err != nil { 6784- return nil, err 6785- } 6786- 6787- pass.Report(analysis.Diagnostic{ 6788- Pos: typeErr.Pos, 6789- End: typeErrEndPos, 6790- Message: typeErr.Msg, 6791- SuggestedFixes: []analysis.SuggestedFix{{ 6792- Message: "Fill in return values", 6793- TextEdits: []analysis.TextEdit{{ 6794- Pos: ret.Pos(), 6795- End: ret.End(), 6796- NewText: newBuf.Bytes(), 6797- }}, 6798- }}, 6799- }) 6800- } 6801- return nil, nil 6802-} 6803- 6804-func matchingTypes(want, got types.Type) bool { 6805- if want == got || types.Identical(want, got) { 6806- return true 6807- } 6808- // Code segment to help check for untyped equality from (golang/go#32146). 6809- if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 { 6810- if lhs, ok := got.Underlying().(*types.Basic); ok { 6811- return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType 6812- } 6813- } 6814- return types.AssignableTo(want, got) || types.ConvertibleTo(want, got) 6815-} 6816- 6817-// Error messages have changed across Go versions. These regexps capture recent 6818-// incarnations. 6819-// 6820-// TODO(rfindley): once error codes are exported and exposed via go/packages, 6821-// use error codes rather than string matching here. 6822-var wrongReturnNumRegexes = []*regexp.Regexp{ 6823- regexp.MustCompile(`wrong number of return values \(want (\d+), got (\d+)\)`), 6824- regexp.MustCompile(`too many return values`), 6825- regexp.MustCompile(`not enough return values`), 6826-} 6827- 6828-func FixesError(err types.Error) bool { 6829- msg := strings.TrimSpace(err.Msg) 6830- for _, rx := range wrongReturnNumRegexes { 6831- if rx.MatchString(msg) { 6832- return true 6833- } 6834- } 6835- return false 6836-} 6837diff -urN a/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go b/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go 6838--- a/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go 2000-01-01 00:00:00.000000000 -0000 6839+++ b/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go 1970-01-01 00:00:00.000000000 +0000 6840@@ -1,22 +0,0 @@ 6841-// Copyright 2020 The Go Authors. All rights reserved. 6842-// Use of this source code is governed by a BSD-style 6843-// license that can be found in the LICENSE file. 6844- 6845-package fillreturns_test 6846- 6847-import ( 6848- "testing" 6849- 6850- "golang.org/x/tools/go/analysis/analysistest" 6851- "golang.org/x/tools/gopls/internal/lsp/analysis/fillreturns" 6852- "golang.org/x/tools/internal/typeparams" 6853-) 6854- 6855-func Test(t *testing.T) { 6856- testdata := analysistest.TestData() 6857- tests := []string{"a"} 6858- if typeparams.Enabled { 6859- tests = append(tests, "typeparams") 6860- } 6861- analysistest.RunWithSuggestedFixes(t, testdata, fillreturns.Analyzer, tests...) 6862-} 6863diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go 6864--- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 6865+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 6866@@ -1,139 +0,0 @@ 6867-// Copyright 2020 The Go Authors. All rights reserved. 6868-// Use of this source code is governed by a BSD-style 6869-// license that can be found in the LICENSE file. 6870- 6871-package fillreturns 6872- 6873-import ( 6874- "errors" 6875- "go/ast" 6876- ast2 "go/ast" 6877- "io" 6878- "net/http" 6879- . "net/http" 6880- "net/url" 6881- "strconv" 6882-) 6883- 6884-type T struct{} 6885-type T1 = T 6886-type I interface{} 6887-type I1 = I 6888-type z func(string, http.Handler) error 6889- 6890-func x() error { 6891- return errors.New("foo") 6892-} 6893- 6894-// The error messages below changed in 1.18; "return values" covers both forms. 6895- 6896-func b() (string, int, error) { 6897- return "", errors.New("foo") // want "return values" 6898-} 6899- 6900-func c() (string, int, error) { 6901- return 7, errors.New("foo") // want "return values" 6902-} 6903- 6904-func d() (string, int, error) { 6905- return "", 7 // want "return values" 6906-} 6907- 6908-func e() (T, error, *bool) { 6909- return (z(http.ListenAndServe))("", nil) // want "return values" 6910-} 6911- 6912-func preserveLeft() (int, int, error) { 6913- return 1, errors.New("foo") // want "return values" 6914-} 6915- 6916-func matchValues() (int, error, string) { 6917- return errors.New("foo"), 3 // want "return values" 6918-} 6919- 6920-func preventDataOverwrite() (int, string) { 6921- return errors.New("foo") // want "return values" 6922-} 6923- 6924-func closure() (string, error) { 6925- _ = func() (int, error) { 6926- return // want "return values" 6927- } 6928- return // want "return values" 6929-} 6930- 6931-func basic() (uint8, uint16, uint32, uint64, int8, int16, int32, int64, float32, float64, complex64, complex128, byte, rune, uint, int, uintptr, string, bool, error) { 6932- return // want "return values" 6933-} 6934- 6935-func complex() (*int, []int, [2]int, map[int]int) { 6936- return // want "return values" 6937-} 6938- 6939-func structsAndInterfaces() (T, url.URL, T1, I, I1, io.Reader, Client, ast2.Stmt) { 6940- return // want "return values" 6941-} 6942- 6943-func m() (int, error) { 6944- if 1 == 2 { 6945- return // want "return values" 6946- } else if 1 == 3 { 6947- return errors.New("foo") // want "return values" 6948- } else { 6949- return 1 // want "return values" 6950- } 6951- return // want "return values" 6952-} 6953- 6954-func convertibleTypes() (ast2.Expr, int) { 6955- return &ast2.ArrayType{} // want "return values" 6956-} 6957- 6958-func assignableTypes() (map[string]int, int) { 6959- type X map[string]int 6960- var x X 6961- return x // want "return values" 6962-} 6963- 6964-func interfaceAndError() (I, int) { 6965- return errors.New("foo") // want "return values" 6966-} 6967- 6968-func funcOneReturn() (string, error) { 6969- return strconv.Itoa(1) // want "return values" 6970-} 6971- 6972-func funcMultipleReturn() (int, error, string) { 6973- return strconv.Atoi("1") 6974-} 6975- 6976-func localFuncMultipleReturn() (string, int, error, string) { 6977- return b() 6978-} 6979- 6980-func multipleUnused() (int, string, string, string) { 6981- return 3, 4, 5 // want "return values" 6982-} 6983- 6984-func gotTooMany() int { 6985- if true { 6986- return 0, "" // want "return values" 6987- } else { 6988- return 1, 0, nil // want "return values" 6989- } 6990- return 0, 5, false // want "return values" 6991-} 6992- 6993-func fillVars() (int, string, ast.Node, bool, error) { 6994- eint := 0 6995- s := "a" 6996- var t bool 6997- if true { 6998- err := errors.New("fail") 6999- return // want "return values" 7000- } 7001- n := ast.NewIdent("ident") 7002- int := 3 7003- var b bool 7004- return "" // want "return values" 7005-} 7006diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden 7007--- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 7008+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 7009@@ -1,139 +0,0 @@ 7010-// Copyright 2020 The Go Authors. All rights reserved. 7011-// Use of this source code is governed by a BSD-style 7012-// license that can be found in the LICENSE file. 7013- 7014-package fillreturns 7015- 7016-import ( 7017- "errors" 7018- "go/ast" 7019- ast2 "go/ast" 7020- "io" 7021- "net/http" 7022- . "net/http" 7023- "net/url" 7024- "strconv" 7025-) 7026- 7027-type T struct{} 7028-type T1 = T 7029-type I interface{} 7030-type I1 = I 7031-type z func(string, http.Handler) error 7032- 7033-func x() error { 7034- return errors.New("foo") 7035-} 7036- 7037-// The error messages below changed in 1.18; "return values" covers both forms. 7038- 7039-func b() (string, int, error) { 7040- return "", 0, errors.New("foo") // want "return values" 7041-} 7042- 7043-func c() (string, int, error) { 7044- return "", 7, errors.New("foo") // want "return values" 7045-} 7046- 7047-func d() (string, int, error) { 7048- return "", 7, nil // want "return values" 7049-} 7050- 7051-func e() (T, error, *bool) { 7052- return T{}, (z(http.ListenAndServe))("", nil), nil // want "return values" 7053-} 7054- 7055-func preserveLeft() (int, int, error) { 7056- return 1, 0, errors.New("foo") // want "return values" 7057-} 7058- 7059-func matchValues() (int, error, string) { 7060- return 3, errors.New("foo"), "" // want "return values" 7061-} 7062- 7063-func preventDataOverwrite() (int, string) { 7064- return 0, "", errors.New("foo") // want "return values" 7065-} 7066- 7067-func closure() (string, error) { 7068- _ = func() (int, error) { 7069- return 0, nil // want "return values" 7070- } 7071- return "", nil // want "return values" 7072-} 7073- 7074-func basic() (uint8, uint16, uint32, uint64, int8, int16, int32, int64, float32, float64, complex64, complex128, byte, rune, uint, int, uintptr, string, bool, error) { 7075- return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", false, nil // want "return values" 7076-} 7077- 7078-func complex() (*int, []int, [2]int, map[int]int) { 7079- return nil, nil, nil, nil // want "return values" 7080-} 7081- 7082-func structsAndInterfaces() (T, url.URL, T1, I, I1, io.Reader, Client, ast2.Stmt) { 7083- return T{}, url.URL{}, T{}, nil, nil, nil, Client{}, nil // want "return values" 7084-} 7085- 7086-func m() (int, error) { 7087- if 1 == 2 { 7088- return 0, nil // want "return values" 7089- } else if 1 == 3 { 7090- return 0, errors.New("foo") // want "return values" 7091- } else { 7092- return 1, nil // want "return values" 7093- } 7094- return 0, nil // want "return values" 7095-} 7096- 7097-func convertibleTypes() (ast2.Expr, int) { 7098- return &ast2.ArrayType{}, 0 // want "return values" 7099-} 7100- 7101-func assignableTypes() (map[string]int, int) { 7102- type X map[string]int 7103- var x X 7104- return x, 0 // want "return values" 7105-} 7106- 7107-func interfaceAndError() (I, int) { 7108- return errors.New("foo"), 0 // want "return values" 7109-} 7110- 7111-func funcOneReturn() (string, error) { 7112- return strconv.Itoa(1), nil // want "return values" 7113-} 7114- 7115-func funcMultipleReturn() (int, error, string) { 7116- return strconv.Atoi("1") 7117-} 7118- 7119-func localFuncMultipleReturn() (string, int, error, string) { 7120- return b() 7121-} 7122- 7123-func multipleUnused() (int, string, string, string) { 7124- return 3, "", "", "", 4, 5 // want "return values" 7125-} 7126- 7127-func gotTooMany() int { 7128- if true { 7129- return 0 // want "return values" 7130- } else { 7131- return 1 // want "return values" 7132- } 7133- return 5 // want "return values" 7134-} 7135- 7136-func fillVars() (int, string, ast.Node, bool, error) { 7137- eint := 0 7138- s := "a" 7139- var t bool 7140- if true { 7141- err := errors.New("fail") 7142- return eint, s, nil, false, err // want "return values" 7143- } 7144- n := ast.NewIdent("ident") 7145- int := 3 7146- var b bool 7147- return int, "", n, b, nil // want "return values" 7148-} 7149diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go 7150--- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go 2000-01-01 00:00:00.000000000 -0000 7151+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go 1970-01-01 00:00:00.000000000 +0000 7152@@ -1,5 +0,0 @@ 7153-package fillreturns 7154- 7155-func hello[T any]() int { 7156- return 7157-} 7158diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden 7159--- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden 2000-01-01 00:00:00.000000000 -0000 7160+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden 1970-01-01 00:00:00.000000000 +0000 7161@@ -1,5 +0,0 @@ 7162-package fillreturns 7163- 7164-func hello[T any]() int { 7165- return 7166-} 7167diff -urN a/gopls/internal/lsp/analysis/fillstruct/fillstruct.go b/gopls/internal/lsp/analysis/fillstruct/fillstruct.go 7168--- a/gopls/internal/lsp/analysis/fillstruct/fillstruct.go 2000-01-01 00:00:00.000000000 -0000 7169+++ b/gopls/internal/lsp/analysis/fillstruct/fillstruct.go 1970-01-01 00:00:00.000000000 +0000 7170@@ -1,506 +0,0 @@ 7171-// Copyright 2020 The Go Authors. All rights reserved. 7172-// Use of this source code is governed by a BSD-style 7173-// license that can be found in the LICENSE file. 7174- 7175-// Package fillstruct defines an Analyzer that automatically 7176-// fills in a struct declaration with zero value elements for each field. 7177-// 7178-// The analyzer's diagnostic is merely a prompt. 7179-// The actual fix is created by a separate direct call from gopls to 7180-// the SuggestedFixes function. 7181-// Tests of Analyzer.Run can be found in ./testdata/src. 7182-// Tests of the SuggestedFixes logic live in ../../testdata/fillstruct. 7183-package fillstruct 7184- 7185-import ( 7186- "bytes" 7187- "fmt" 7188- "go/ast" 7189- "go/format" 7190- "go/token" 7191- "go/types" 7192- "strings" 7193- "unicode" 7194- 7195- "golang.org/x/tools/go/analysis" 7196- "golang.org/x/tools/go/analysis/passes/inspect" 7197- "golang.org/x/tools/go/ast/astutil" 7198- "golang.org/x/tools/go/ast/inspector" 7199- "golang.org/x/tools/gopls/internal/lsp/safetoken" 7200- "golang.org/x/tools/internal/analysisinternal" 7201- "golang.org/x/tools/internal/fuzzy" 7202- "golang.org/x/tools/internal/typeparams" 7203-) 7204- 7205-const Doc = `note incomplete struct initializations 7206- 7207-This analyzer provides diagnostics for any struct literals that do not have 7208-any fields initialized. Because the suggested fix for this analysis is 7209-expensive to compute, callers should compute it separately, using the 7210-SuggestedFix function below. 7211-` 7212- 7213-var Analyzer = &analysis.Analyzer{ 7214- Name: "fillstruct", 7215- Doc: Doc, 7216- Requires: []*analysis.Analyzer{inspect.Analyzer}, 7217- Run: run, 7218- RunDespiteErrors: true, 7219-} 7220- 7221-func run(pass *analysis.Pass) (interface{}, error) { 7222- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 7223- nodeFilter := []ast.Node{(*ast.CompositeLit)(nil)} 7224- inspect.Preorder(nodeFilter, func(n ast.Node) { 7225- expr := n.(*ast.CompositeLit) 7226- 7227- // Find enclosing file. 7228- // TODO(adonovan): use inspect.WithStack? 7229- var file *ast.File 7230- for _, f := range pass.Files { 7231- if f.Pos() <= expr.Pos() && expr.Pos() <= f.End() { 7232- file = f 7233- break 7234- } 7235- } 7236- if file == nil { 7237- return 7238- } 7239- 7240- typ := pass.TypesInfo.TypeOf(expr) 7241- if typ == nil { 7242- return 7243- } 7244- 7245- // Find reference to the type declaration of the struct being initialized. 7246- typ = deref(typ) 7247- tStruct, ok := typ.Underlying().(*types.Struct) 7248- if !ok { 7249- return 7250- } 7251- // Inv: typ is the possibly-named struct type. 7252- 7253- fieldCount := tStruct.NumFields() 7254- 7255- // Skip any struct that is already populated or that has no fields. 7256- if fieldCount == 0 || fieldCount == len(expr.Elts) { 7257- return 7258- } 7259- 7260- // Are any fields in need of filling? 7261- var fillableFields []string 7262- for i := 0; i < fieldCount; i++ { 7263- field := tStruct.Field(i) 7264- // Ignore fields that are not accessible in the current package. 7265- if field.Pkg() != nil && field.Pkg() != pass.Pkg && !field.Exported() { 7266- continue 7267- } 7268- fillableFields = append(fillableFields, fmt.Sprintf("%s: %s", field.Name(), field.Type().String())) 7269- } 7270- if len(fillableFields) == 0 { 7271- return 7272- } 7273- 7274- // Derive a name for the struct type. 7275- var name string 7276- if typ != tStruct { 7277- // named struct type (e.g. pkg.S[T]) 7278- name = types.TypeString(typ, types.RelativeTo(pass.Pkg)) 7279- } else { 7280- // anonymous struct type 7281- totalFields := len(fillableFields) 7282- const maxLen = 20 7283- // Find the index to cut off printing of fields. 7284- var i, fieldLen int 7285- for i = range fillableFields { 7286- if fieldLen > maxLen { 7287- break 7288- } 7289- fieldLen += len(fillableFields[i]) 7290- } 7291- fillableFields = fillableFields[:i] 7292- if i < totalFields { 7293- fillableFields = append(fillableFields, "...") 7294- } 7295- name = fmt.Sprintf("anonymous struct { %s }", strings.Join(fillableFields, ", ")) 7296- } 7297- pass.Report(analysis.Diagnostic{ 7298- Message: fmt.Sprintf("Fill %s", name), 7299- Pos: expr.Pos(), 7300- End: expr.End(), 7301- }) 7302- }) 7303- return nil, nil 7304-} 7305- 7306-// SuggestedFix computes the suggested fix for the kinds of 7307-// diagnostics produced by the Analyzer above. 7308-func SuggestedFix(fset *token.FileSet, start, end token.Pos, content []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) { 7309- if info == nil { 7310- return nil, fmt.Errorf("nil types.Info") 7311- } 7312- 7313- pos := start // don't use the end 7314- 7315- // TODO(rstambler): Using ast.Inspect would probably be more efficient than 7316- // calling PathEnclosingInterval. Switch this approach. 7317- path, _ := astutil.PathEnclosingInterval(file, pos, pos) 7318- if len(path) == 0 { 7319- return nil, fmt.Errorf("no enclosing ast.Node") 7320- } 7321- var expr *ast.CompositeLit 7322- for _, n := range path { 7323- if node, ok := n.(*ast.CompositeLit); ok { 7324- expr = node 7325- break 7326- } 7327- } 7328- 7329- typ := info.TypeOf(expr) 7330- if typ == nil { 7331- return nil, fmt.Errorf("no composite literal") 7332- } 7333- 7334- // Find reference to the type declaration of the struct being initialized. 7335- typ = deref(typ) 7336- tStruct, ok := typ.Underlying().(*types.Struct) 7337- if !ok { 7338- return nil, fmt.Errorf("%s is not a (pointer to) struct type", 7339- types.TypeString(typ, types.RelativeTo(pkg))) 7340- } 7341- // Inv: typ is the the possibly-named struct type. 7342- 7343- fieldCount := tStruct.NumFields() 7344- 7345- // Check which types have already been filled in. (we only want to fill in 7346- // the unfilled types, or else we'll blat user-supplied details) 7347- prefilledFields := map[string]ast.Expr{} 7348- for _, e := range expr.Elts { 7349- if kv, ok := e.(*ast.KeyValueExpr); ok { 7350- if key, ok := kv.Key.(*ast.Ident); ok { 7351- prefilledFields[key.Name] = kv.Value 7352- } 7353- } 7354- } 7355- 7356- // Use a new fileset to build up a token.File for the new composite 7357- // literal. We need one line for foo{, one line for }, and one line for 7358- // each field we're going to set. format.Node only cares about line 7359- // numbers, so we don't need to set columns, and each line can be 7360- // 1 byte long. 7361- // TODO(adonovan): why is this necessary? The position information 7362- // is going to be wrong for the existing trees in prefilledFields. 7363- // Can't the formatter just do its best with an empty fileset? 7364- fakeFset := token.NewFileSet() 7365- tok := fakeFset.AddFile("", -1, fieldCount+2) 7366- 7367- line := 2 // account for 1-based lines and the left brace 7368- var fieldTyps []types.Type 7369- for i := 0; i < fieldCount; i++ { 7370- field := tStruct.Field(i) 7371- // Ignore fields that are not accessible in the current package. 7372- if field.Pkg() != nil && field.Pkg() != pkg && !field.Exported() { 7373- fieldTyps = append(fieldTyps, nil) 7374- continue 7375- } 7376- fieldTyps = append(fieldTyps, field.Type()) 7377- } 7378- matches := analysisinternal.MatchingIdents(fieldTyps, file, start, info, pkg) 7379- var elts []ast.Expr 7380- for i, fieldTyp := range fieldTyps { 7381- if fieldTyp == nil { 7382- continue // TODO(adonovan): is this reachable? 7383- } 7384- fieldName := tStruct.Field(i).Name() 7385- 7386- tok.AddLine(line - 1) // add 1 byte per line 7387- if line > tok.LineCount() { 7388- panic(fmt.Sprintf("invalid line number %v (of %v) for fillstruct", line, tok.LineCount())) 7389- } 7390- pos := tok.LineStart(line) 7391- 7392- kv := &ast.KeyValueExpr{ 7393- Key: &ast.Ident{ 7394- NamePos: pos, 7395- Name: fieldName, 7396- }, 7397- Colon: pos, 7398- } 7399- if expr, ok := prefilledFields[fieldName]; ok { 7400- kv.Value = expr 7401- } else { 7402- names, ok := matches[fieldTyp] 7403- if !ok { 7404- return nil, fmt.Errorf("invalid struct field type: %v", fieldTyp) 7405- } 7406- 7407- // Find the name most similar to the field name. 7408- // If no name matches the pattern, generate a zero value. 7409- // NOTE: We currently match on the name of the field key rather than the field type. 7410- if best := fuzzy.BestMatch(fieldName, names); best != "" { 7411- kv.Value = ast.NewIdent(best) 7412- } else if v := populateValue(file, pkg, fieldTyp); v != nil { 7413- kv.Value = v 7414- } else { 7415- return nil, nil 7416- } 7417- } 7418- elts = append(elts, kv) 7419- line++ 7420- } 7421- 7422- // If all of the struct's fields are unexported, we have nothing to do. 7423- if len(elts) == 0 { 7424- return nil, fmt.Errorf("no elements to fill") 7425- } 7426- 7427- // Add the final line for the right brace. Offset is the number of 7428- // bytes already added plus 1. 7429- tok.AddLine(len(elts) + 1) 7430- line = len(elts) + 2 7431- if line > tok.LineCount() { 7432- panic(fmt.Sprintf("invalid line number %v (of %v) for fillstruct", line, tok.LineCount())) 7433- } 7434- 7435- cl := &ast.CompositeLit{ 7436- Type: expr.Type, 7437- Lbrace: tok.LineStart(1), 7438- Elts: elts, 7439- Rbrace: tok.LineStart(line), 7440- } 7441- 7442- // Find the line on which the composite literal is declared. 7443- split := bytes.Split(content, []byte("\n")) 7444- lineNumber := safetoken.StartPosition(fset, expr.Lbrace).Line 7445- firstLine := split[lineNumber-1] // lines are 1-indexed 7446- 7447- // Trim the whitespace from the left of the line, and use the index 7448- // to get the amount of whitespace on the left. 7449- trimmed := bytes.TrimLeftFunc(firstLine, unicode.IsSpace) 7450- index := bytes.Index(firstLine, trimmed) 7451- whitespace := firstLine[:index] 7452- 7453- // First pass through the formatter: turn the expr into a string. 7454- var formatBuf bytes.Buffer 7455- if err := format.Node(&formatBuf, fakeFset, cl); err != nil { 7456- return nil, fmt.Errorf("failed to run first format on:\n%s\ngot err: %v", cl.Type, err) 7457- } 7458- sug := indent(formatBuf.Bytes(), whitespace) 7459- 7460- if len(prefilledFields) > 0 { 7461- // Attempt a second pass through the formatter to line up columns. 7462- sourced, err := format.Source(sug) 7463- if err == nil { 7464- sug = indent(sourced, whitespace) 7465- } 7466- } 7467- 7468- return &analysis.SuggestedFix{ 7469- TextEdits: []analysis.TextEdit{ 7470- { 7471- Pos: expr.Pos(), 7472- End: expr.End(), 7473- NewText: sug, 7474- }, 7475- }, 7476- }, nil 7477-} 7478- 7479-// indent works line by line through str, indenting (prefixing) each line with 7480-// ind. 7481-func indent(str, ind []byte) []byte { 7482- split := bytes.Split(str, []byte("\n")) 7483- newText := bytes.NewBuffer(nil) 7484- for i, s := range split { 7485- if len(s) == 0 { 7486- continue 7487- } 7488- // Don't add the extra indentation to the first line. 7489- if i != 0 { 7490- newText.Write(ind) 7491- } 7492- newText.Write(s) 7493- if i < len(split)-1 { 7494- newText.WriteByte('\n') 7495- } 7496- } 7497- return newText.Bytes() 7498-} 7499- 7500-// populateValue constructs an expression to fill the value of a struct field. 7501-// 7502-// When the type of a struct field is a basic literal or interface, we return 7503-// default values. For other types, such as maps, slices, and channels, we create 7504-// empty expressions such as []T{} or make(chan T) rather than using default values. 7505-// 7506-// The reasoning here is that users will call fillstruct with the intention of 7507-// initializing the struct, in which case setting these fields to nil has no effect. 7508-func populateValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { 7509- switch u := typ.Underlying().(type) { 7510- case *types.Basic: 7511- switch { 7512- case u.Info()&types.IsNumeric != 0: 7513- return &ast.BasicLit{Kind: token.INT, Value: "0"} 7514- case u.Info()&types.IsBoolean != 0: 7515- return &ast.Ident{Name: "false"} 7516- case u.Info()&types.IsString != 0: 7517- return &ast.BasicLit{Kind: token.STRING, Value: `""`} 7518- case u.Kind() == types.UnsafePointer: 7519- return ast.NewIdent("nil") 7520- default: 7521- panic("unknown basic type") 7522- } 7523- 7524- case *types.Map: 7525- k := analysisinternal.TypeExpr(f, pkg, u.Key()) 7526- v := analysisinternal.TypeExpr(f, pkg, u.Elem()) 7527- if k == nil || v == nil { 7528- return nil 7529- } 7530- return &ast.CompositeLit{ 7531- Type: &ast.MapType{ 7532- Key: k, 7533- Value: v, 7534- }, 7535- } 7536- case *types.Slice: 7537- s := analysisinternal.TypeExpr(f, pkg, u.Elem()) 7538- if s == nil { 7539- return nil 7540- } 7541- return &ast.CompositeLit{ 7542- Type: &ast.ArrayType{ 7543- Elt: s, 7544- }, 7545- } 7546- 7547- case *types.Array: 7548- a := analysisinternal.TypeExpr(f, pkg, u.Elem()) 7549- if a == nil { 7550- return nil 7551- } 7552- return &ast.CompositeLit{ 7553- Type: &ast.ArrayType{ 7554- Elt: a, 7555- Len: &ast.BasicLit{ 7556- Kind: token.INT, Value: fmt.Sprintf("%v", u.Len()), 7557- }, 7558- }, 7559- } 7560- 7561- case *types.Chan: 7562- v := analysisinternal.TypeExpr(f, pkg, u.Elem()) 7563- if v == nil { 7564- return nil 7565- } 7566- dir := ast.ChanDir(u.Dir()) 7567- if u.Dir() == types.SendRecv { 7568- dir = ast.SEND | ast.RECV 7569- } 7570- return &ast.CallExpr{ 7571- Fun: ast.NewIdent("make"), 7572- Args: []ast.Expr{ 7573- &ast.ChanType{ 7574- Dir: dir, 7575- Value: v, 7576- }, 7577- }, 7578- } 7579- 7580- case *types.Struct: 7581- s := analysisinternal.TypeExpr(f, pkg, typ) 7582- if s == nil { 7583- return nil 7584- } 7585- return &ast.CompositeLit{ 7586- Type: s, 7587- } 7588- 7589- case *types.Signature: 7590- var params []*ast.Field 7591- for i := 0; i < u.Params().Len(); i++ { 7592- p := analysisinternal.TypeExpr(f, pkg, u.Params().At(i).Type()) 7593- if p == nil { 7594- return nil 7595- } 7596- params = append(params, &ast.Field{ 7597- Type: p, 7598- Names: []*ast.Ident{ 7599- { 7600- Name: u.Params().At(i).Name(), 7601- }, 7602- }, 7603- }) 7604- } 7605- var returns []*ast.Field 7606- for i := 0; i < u.Results().Len(); i++ { 7607- r := analysisinternal.TypeExpr(f, pkg, u.Results().At(i).Type()) 7608- if r == nil { 7609- return nil 7610- } 7611- returns = append(returns, &ast.Field{ 7612- Type: r, 7613- }) 7614- } 7615- return &ast.FuncLit{ 7616- Type: &ast.FuncType{ 7617- Params: &ast.FieldList{ 7618- List: params, 7619- }, 7620- Results: &ast.FieldList{ 7621- List: returns, 7622- }, 7623- }, 7624- Body: &ast.BlockStmt{}, 7625- } 7626- 7627- case *types.Pointer: 7628- switch u.Elem().(type) { 7629- case *types.Basic: 7630- return &ast.CallExpr{ 7631- Fun: &ast.Ident{ 7632- Name: "new", 7633- }, 7634- Args: []ast.Expr{ 7635- &ast.Ident{ 7636- Name: u.Elem().String(), 7637- }, 7638- }, 7639- } 7640- default: 7641- return &ast.UnaryExpr{ 7642- Op: token.AND, 7643- X: populateValue(f, pkg, u.Elem()), 7644- } 7645- } 7646- 7647- case *types.Interface: 7648- if param, ok := typ.(*typeparams.TypeParam); ok { 7649- // *new(T) is the zero value of a type parameter T. 7650- // TODO(adonovan): one could give a more specific zero 7651- // value if the type has a core type that is, say, 7652- // always a number or a pointer. See go/ssa for details. 7653- return &ast.StarExpr{ 7654- X: &ast.CallExpr{ 7655- Fun: ast.NewIdent("new"), 7656- Args: []ast.Expr{ 7657- ast.NewIdent(param.Obj().Name()), 7658- }, 7659- }, 7660- } 7661- } 7662- 7663- return ast.NewIdent("nil") 7664- } 7665- return nil 7666-} 7667- 7668-func deref(t types.Type) types.Type { 7669- for { 7670- ptr, ok := t.Underlying().(*types.Pointer) 7671- if !ok { 7672- return t 7673- } 7674- t = ptr.Elem() 7675- } 7676-} 7677diff -urN a/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go b/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go 7678--- a/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go 2000-01-01 00:00:00.000000000 -0000 7679+++ b/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go 1970-01-01 00:00:00.000000000 +0000 7680@@ -1,22 +0,0 @@ 7681-// Copyright 2020 The Go Authors. All rights reserved. 7682-// Use of this source code is governed by a BSD-style 7683-// license that can be found in the LICENSE file. 7684- 7685-package fillstruct_test 7686- 7687-import ( 7688- "testing" 7689- 7690- "golang.org/x/tools/go/analysis/analysistest" 7691- "golang.org/x/tools/gopls/internal/lsp/analysis/fillstruct" 7692- "golang.org/x/tools/internal/typeparams" 7693-) 7694- 7695-func Test(t *testing.T) { 7696- testdata := analysistest.TestData() 7697- tests := []string{"a"} 7698- if typeparams.Enabled { 7699- tests = append(tests, "typeparams") 7700- } 7701- analysistest.Run(t, testdata, fillstruct.Analyzer, tests...) 7702-} 7703diff -urN a/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go b/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go 7704--- a/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 7705+++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 7706@@ -1,113 +0,0 @@ 7707-// Copyright 2020 The Go Authors. All rights reserved. 7708-// Use of this source code is governed by a BSD-style 7709-// license that can be found in the LICENSE file. 7710- 7711-package fillstruct 7712- 7713-import ( 7714- data "b" 7715- "go/ast" 7716- "go/token" 7717- "unsafe" 7718-) 7719- 7720-type emptyStruct struct{} 7721- 7722-var _ = emptyStruct{} 7723- 7724-type basicStruct struct { 7725- foo int 7726-} 7727- 7728-var _ = basicStruct{} // want `Fill basicStruct` 7729- 7730-type twoArgStruct struct { 7731- foo int 7732- bar string 7733-} 7734- 7735-var _ = twoArgStruct{} // want `Fill twoArgStruct` 7736- 7737-var _ = twoArgStruct{ // want `Fill twoArgStruct` 7738- bar: "bar", 7739-} 7740- 7741-type nestedStruct struct { 7742- bar string 7743- basic basicStruct 7744-} 7745- 7746-var _ = nestedStruct{} // want `Fill nestedStruct` 7747- 7748-var _ = data.B{} // want `Fill b.B` 7749- 7750-type typedStruct struct { 7751- m map[string]int 7752- s []int 7753- c chan int 7754- c1 <-chan int 7755- a [2]string 7756-} 7757- 7758-var _ = typedStruct{} // want `Fill typedStruct` 7759- 7760-type funStruct struct { 7761- fn func(i int) int 7762-} 7763- 7764-var _ = funStruct{} // want `Fill funStruct` 7765- 7766-type funStructComplex struct { 7767- fn func(i int, s string) (string, int) 7768-} 7769- 7770-var _ = funStructComplex{} // want `Fill funStructComplex` 7771- 7772-type funStructEmpty struct { 7773- fn func() 7774-} 7775- 7776-var _ = funStructEmpty{} // want `Fill funStructEmpty` 7777- 7778-type Foo struct { 7779- A int 7780-} 7781- 7782-type Bar struct { 7783- X *Foo 7784- Y *Foo 7785-} 7786- 7787-var _ = Bar{} // want `Fill Bar` 7788- 7789-type importedStruct struct { 7790- m map[*ast.CompositeLit]ast.Field 7791- s []ast.BadExpr 7792- a [3]token.Token 7793- c chan ast.EmptyStmt 7794- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 7795- st ast.CompositeLit 7796-} 7797- 7798-var _ = importedStruct{} // want `Fill importedStruct` 7799- 7800-type pointerBuiltinStruct struct { 7801- b *bool 7802- s *string 7803- i *int 7804-} 7805- 7806-var _ = pointerBuiltinStruct{} // want `Fill pointerBuiltinStruct` 7807- 7808-var _ = []ast.BasicLit{ 7809- {}, // want `Fill go/ast.BasicLit` 7810-} 7811- 7812-var _ = []ast.BasicLit{{}, // want "go/ast.BasicLit" 7813-} 7814- 7815-type unsafeStruct struct { 7816- foo unsafe.Pointer 7817-} 7818- 7819-var _ = unsafeStruct{} // want `Fill unsafeStruct` 7820diff -urN a/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go b/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go 7821--- a/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go 2000-01-01 00:00:00.000000000 -0000 7822+++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go 1970-01-01 00:00:00.000000000 +0000 7823@@ -1,6 +0,0 @@ 7824-package fillstruct 7825- 7826-type B struct { 7827- ExportedInt int 7828- unexportedInt int 7829-} 7830diff -urN a/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go b/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go 7831--- a/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go 2000-01-01 00:00:00.000000000 -0000 7832+++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go 1970-01-01 00:00:00.000000000 +0000 7833@@ -1,50 +0,0 @@ 7834-// Copyright 2020 The Go Authors. All rights reserved. 7835-// Use of this source code is governed by a BSD-style 7836-// license that can be found in the LICENSE file. 7837- 7838-package fillstruct 7839- 7840-type emptyStruct[A any] struct{} 7841- 7842-var _ = emptyStruct[int]{} 7843- 7844-type basicStruct[T any] struct { 7845- foo T 7846-} 7847- 7848-var _ = basicStruct[int]{} // want `Fill basicStruct\[int\]` 7849- 7850-type twoArgStruct[F, B any] struct { 7851- foo F 7852- bar B 7853-} 7854- 7855-var _ = twoArgStruct[string, int]{} // want `Fill twoArgStruct\[string, int\]` 7856- 7857-var _ = twoArgStruct[int, string]{ // want `Fill twoArgStruct\[int, string\]` 7858- bar: "bar", 7859-} 7860- 7861-type nestedStruct struct { 7862- bar string 7863- basic basicStruct[int] 7864-} 7865- 7866-var _ = nestedStruct{} // want "Fill nestedStruct" 7867- 7868-func _[T any]() { 7869- type S struct{ t T } 7870- x := S{} // want "Fill S" 7871- _ = x 7872-} 7873- 7874-func Test() { 7875- var tests = []struct { 7876- a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p string 7877- }{ 7878- {}, // want "Fill anonymous struct { a: string, b: string, c: string, ... }" 7879- } 7880- for _, test := range tests { 7881- _ = test 7882- } 7883-} 7884diff -urN a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go 7885--- a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go 2000-01-01 00:00:00.000000000 -0000 7886+++ b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go 1970-01-01 00:00:00.000000000 +0000 7887@@ -1,31 +0,0 @@ 7888-// Copyright 2021 The Go Authors. All rights reserved. 7889-// Use of this source code is governed by a BSD-style 7890-// license that can be found in the LICENSE file. 7891- 7892-// Package infertypeargs defines an analyzer that checks for explicit function 7893-// arguments that could be inferred. 7894-package infertypeargs 7895- 7896-import ( 7897- "golang.org/x/tools/go/analysis" 7898- "golang.org/x/tools/go/analysis/passes/inspect" 7899-) 7900- 7901-const Doc = `check for unnecessary type arguments in call expressions 7902- 7903-Explicit type arguments may be omitted from call expressions if they can be 7904-inferred from function arguments, or from other type arguments: 7905- 7906- func f[T any](T) {} 7907- 7908- func _() { 7909- f[string]("foo") // string could be inferred 7910- } 7911-` 7912- 7913-var Analyzer = &analysis.Analyzer{ 7914- Name: "infertypeargs", 7915- Doc: Doc, 7916- Requires: []*analysis.Analyzer{inspect.Analyzer}, 7917- Run: run, 7918-} 7919diff -urN a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go 7920--- a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go 2000-01-01 00:00:00.000000000 -0000 7921+++ b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go 1970-01-01 00:00:00.000000000 +0000 7922@@ -1,21 +0,0 @@ 7923-// Copyright 2021 The Go Authors. All rights reserved. 7924-// Use of this source code is governed by a BSD-style 7925-// license that can be found in the LICENSE file. 7926- 7927-package infertypeargs_test 7928- 7929-import ( 7930- "testing" 7931- 7932- "golang.org/x/tools/go/analysis/analysistest" 7933- "golang.org/x/tools/gopls/internal/lsp/analysis/infertypeargs" 7934- "golang.org/x/tools/internal/typeparams" 7935-) 7936- 7937-func Test(t *testing.T) { 7938- if !typeparams.Enabled { 7939- t.Skip("type params are not enabled") 7940- } 7941- testdata := analysistest.TestData() 7942- analysistest.RunWithSuggestedFixes(t, testdata, infertypeargs.Analyzer, "a") 7943-} 7944diff -urN a/gopls/internal/lsp/analysis/infertypeargs/run_go117.go b/gopls/internal/lsp/analysis/infertypeargs/run_go117.go 7945--- a/gopls/internal/lsp/analysis/infertypeargs/run_go117.go 2000-01-01 00:00:00.000000000 -0000 7946+++ b/gopls/internal/lsp/analysis/infertypeargs/run_go117.go 1970-01-01 00:00:00.000000000 +0000 7947@@ -1,16 +0,0 @@ 7948-// Copyright 2021 The Go Authors. All rights reserved. 7949-// Use of this source code is governed by a BSD-style 7950-// license that can be found in the LICENSE file. 7951- 7952-//go:build !go1.18 7953-// +build !go1.18 7954- 7955-package infertypeargs 7956- 7957-import "golang.org/x/tools/go/analysis" 7958- 7959-// This analyzer only relates to go1.18+, and uses the types.CheckExpr API that 7960-// was added in Go 1.13. 7961-func run(pass *analysis.Pass) (interface{}, error) { 7962- return nil, nil 7963-} 7964diff -urN a/gopls/internal/lsp/analysis/infertypeargs/run_go118.go b/gopls/internal/lsp/analysis/infertypeargs/run_go118.go 7965--- a/gopls/internal/lsp/analysis/infertypeargs/run_go118.go 2000-01-01 00:00:00.000000000 -0000 7966+++ b/gopls/internal/lsp/analysis/infertypeargs/run_go118.go 1970-01-01 00:00:00.000000000 +0000 7967@@ -1,111 +0,0 @@ 7968-// Copyright 2021 The Go Authors. All rights reserved. 7969-// Use of this source code is governed by a BSD-style 7970-// license that can be found in the LICENSE file. 7971- 7972-//go:build go1.18 7973-// +build go1.18 7974- 7975-package infertypeargs 7976- 7977-import ( 7978- "go/ast" 7979- "go/token" 7980- "go/types" 7981- 7982- "golang.org/x/tools/go/analysis" 7983- "golang.org/x/tools/go/analysis/passes/inspect" 7984- "golang.org/x/tools/go/ast/inspector" 7985- "golang.org/x/tools/internal/typeparams" 7986-) 7987- 7988-func run(pass *analysis.Pass) (interface{}, error) { 7989- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 7990- 7991- nodeFilter := []ast.Node{ 7992- (*ast.CallExpr)(nil), 7993- } 7994- 7995- inspect.Preorder(nodeFilter, func(node ast.Node) { 7996- call := node.(*ast.CallExpr) 7997- x, lbrack, indices, rbrack := typeparams.UnpackIndexExpr(call.Fun) 7998- ident := calledIdent(x) 7999- if ident == nil || len(indices) == 0 { 8000- return // no explicit args, nothing to do 8001- } 8002- 8003- // Confirm that instantiation actually occurred at this ident. 8004- idata, ok := typeparams.GetInstances(pass.TypesInfo)[ident] 8005- if !ok { 8006- return // something went wrong, but fail open 8007- } 8008- instance := idata.Type 8009- 8010- // Start removing argument expressions from the right, and check if we can 8011- // still infer the call expression. 8012- required := len(indices) // number of type expressions that are required 8013- for i := len(indices) - 1; i >= 0; i-- { 8014- var fun ast.Expr 8015- if i == 0 { 8016- // No longer an index expression: just use the parameterized operand. 8017- fun = x 8018- } else { 8019- fun = typeparams.PackIndexExpr(x, lbrack, indices[:i], indices[i-1].End()) 8020- } 8021- newCall := &ast.CallExpr{ 8022- Fun: fun, 8023- Lparen: call.Lparen, 8024- Args: call.Args, 8025- Ellipsis: call.Ellipsis, 8026- Rparen: call.Rparen, 8027- } 8028- info := new(types.Info) 8029- typeparams.InitInstanceInfo(info) 8030- if err := types.CheckExpr(pass.Fset, pass.Pkg, call.Pos(), newCall, info); err != nil { 8031- // Most likely inference failed. 8032- break 8033- } 8034- newIData := typeparams.GetInstances(info)[ident] 8035- newInstance := newIData.Type 8036- if !types.Identical(instance, newInstance) { 8037- // The inferred result type does not match the original result type, so 8038- // this simplification is not valid. 8039- break 8040- } 8041- required = i 8042- } 8043- if required < len(indices) { 8044- var start, end token.Pos 8045- var edit analysis.TextEdit 8046- if required == 0 { 8047- start, end = lbrack, rbrack+1 // erase the entire index 8048- edit = analysis.TextEdit{Pos: start, End: end} 8049- } else { 8050- start = indices[required].Pos() 8051- end = rbrack 8052- // erase from end of last arg to include last comma & white-spaces 8053- edit = analysis.TextEdit{Pos: indices[required-1].End(), End: end} 8054- } 8055- pass.Report(analysis.Diagnostic{ 8056- Pos: start, 8057- End: end, 8058- Message: "unnecessary type arguments", 8059- SuggestedFixes: []analysis.SuggestedFix{{ 8060- Message: "simplify type arguments", 8061- TextEdits: []analysis.TextEdit{edit}, 8062- }}, 8063- }) 8064- } 8065- }) 8066- 8067- return nil, nil 8068-} 8069- 8070-func calledIdent(x ast.Expr) *ast.Ident { 8071- switch x := x.(type) { 8072- case *ast.Ident: 8073- return x 8074- case *ast.SelectorExpr: 8075- return x.Sel 8076- } 8077- return nil 8078-} 8079diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go 8080--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go 2000-01-01 00:00:00.000000000 -0000 8081+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go 1970-01-01 00:00:00.000000000 +0000 8082@@ -1,20 +0,0 @@ 8083-// Copyright 2021 The Go Authors. All rights reserved. 8084-// Use of this source code is governed by a BSD-style 8085-// license that can be found in the LICENSE file. 8086- 8087-// This file contains tests for the infertyepargs checker. 8088- 8089-package a 8090- 8091-func f[T any](T) {} 8092- 8093-func g[T any]() T { var x T; return x } 8094- 8095-func h[P interface{ ~*T }, T any]() {} 8096- 8097-func _() { 8098- f[string]("hello") // want "unnecessary type arguments" 8099- f[int](2) // want "unnecessary type arguments" 8100- _ = g[int]() 8101- h[*int, int]() // want "unnecessary type arguments" 8102-} 8103diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden 8104--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden 2000-01-01 00:00:00.000000000 -0000 8105+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden 1970-01-01 00:00:00.000000000 +0000 8106@@ -1,20 +0,0 @@ 8107-// Copyright 2021 The Go Authors. All rights reserved. 8108-// Use of this source code is governed by a BSD-style 8109-// license that can be found in the LICENSE file. 8110- 8111-// This file contains tests for the infertyepargs checker. 8112- 8113-package a 8114- 8115-func f[T any](T) {} 8116- 8117-func g[T any]() T { var x T; return x } 8118- 8119-func h[P interface{ ~*T }, T any]() {} 8120- 8121-func _() { 8122- f("hello") // want "unnecessary type arguments" 8123- f(2) // want "unnecessary type arguments" 8124- _ = g[int]() 8125- h[*int]() // want "unnecessary type arguments" 8126-} 8127diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go 8128--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go 2000-01-01 00:00:00.000000000 -0000 8129+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go 1970-01-01 00:00:00.000000000 +0000 8130@@ -1,7 +0,0 @@ 8131-// Copyright 2021 The Go Authors. All rights reserved. 8132-// Use of this source code is governed by a BSD-style 8133-// license that can be found in the LICENSE file. 8134- 8135-package imported 8136- 8137-func F[T any](T) {} 8138diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go 8139--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go 2000-01-01 00:00:00.000000000 -0000 8140+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go 1970-01-01 00:00:00.000000000 +0000 8141@@ -1,12 +0,0 @@ 8142-// Copyright 2021 The Go Authors. All rights reserved. 8143-// Use of this source code is governed by a BSD-style 8144-// license that can be found in the LICENSE file. 8145- 8146-package a 8147- 8148-import "a/imported" 8149- 8150-func _() { 8151- var x int 8152- imported.F[int](x) // want "unnecessary type arguments" 8153-} 8154diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden 8155--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden 2000-01-01 00:00:00.000000000 -0000 8156+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden 1970-01-01 00:00:00.000000000 +0000 8157@@ -1,12 +0,0 @@ 8158-// Copyright 2021 The Go Authors. All rights reserved. 8159-// Use of this source code is governed by a BSD-style 8160-// license that can be found in the LICENSE file. 8161- 8162-package a 8163- 8164-import "a/imported" 8165- 8166-func _() { 8167- var x int 8168- imported.F(x) // want "unnecessary type arguments" 8169-} 8170diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go 8171--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go 2000-01-01 00:00:00.000000000 -0000 8172+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go 1970-01-01 00:00:00.000000000 +0000 8173@@ -1,26 +0,0 @@ 8174-// Copyright 2021 The Go Authors. All rights reserved. 8175-// Use of this source code is governed by a BSD-style 8176-// license that can be found in the LICENSE file. 8177- 8178-// We should not suggest removing type arguments if doing so would change the 8179-// resulting type. 8180- 8181-package a 8182- 8183-func id[T any](t T) T { return t } 8184- 8185-var _ = id[int](1) // want "unnecessary type arguments" 8186-var _ = id[string]("foo") // want "unnecessary type arguments" 8187-var _ = id[int64](2) 8188- 8189-func pair[T any](t T) (T, T) { return t, t } 8190- 8191-var _, _ = pair[int](3) // want "unnecessary type arguments" 8192-var _, _ = pair[int64](3) 8193- 8194-func noreturn[T any](t T) {} 8195- 8196-func _() { 8197- noreturn[int64](4) 8198- noreturn[int](4) // want "unnecessary type arguments" 8199-} 8200diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden 8201--- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden 2000-01-01 00:00:00.000000000 -0000 8202+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden 1970-01-01 00:00:00.000000000 +0000 8203@@ -1,26 +0,0 @@ 8204-// Copyright 2021 The Go Authors. All rights reserved. 8205-// Use of this source code is governed by a BSD-style 8206-// license that can be found in the LICENSE file. 8207- 8208-// We should not suggest removing type arguments if doing so would change the 8209-// resulting type. 8210- 8211-package a 8212- 8213-func id[T any](t T) T { return t } 8214- 8215-var _ = id(1) // want "unnecessary type arguments" 8216-var _ = id("foo") // want "unnecessary type arguments" 8217-var _ = id[int64](2) 8218- 8219-func pair[T any](t T) (T, T) { return t, t } 8220- 8221-var _, _ = pair(3) // want "unnecessary type arguments" 8222-var _, _ = pair[int64](3) 8223- 8224-func noreturn[T any](t T) {} 8225- 8226-func _() { 8227- noreturn[int64](4) 8228- noreturn(4) // want "unnecessary type arguments" 8229-} 8230diff -urN a/gopls/internal/lsp/analysis/nonewvars/nonewvars.go b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go 8231--- a/gopls/internal/lsp/analysis/nonewvars/nonewvars.go 2000-01-01 00:00:00.000000000 -0000 8232+++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go 1970-01-01 00:00:00.000000000 +0000 8233@@ -1,95 +0,0 @@ 8234-// Copyright 2020 The Go Authors. All rights reserved. 8235-// Use of this source code is governed by a BSD-style 8236-// license that can be found in the LICENSE file. 8237- 8238-// Package nonewvars defines an Analyzer that applies suggested fixes 8239-// to errors of the type "no new variables on left side of :=". 8240-package nonewvars 8241- 8242-import ( 8243- "bytes" 8244- "go/ast" 8245- "go/format" 8246- "go/token" 8247- 8248- "golang.org/x/tools/go/analysis" 8249- "golang.org/x/tools/go/analysis/passes/inspect" 8250- "golang.org/x/tools/go/ast/inspector" 8251- "golang.org/x/tools/internal/analysisinternal" 8252-) 8253- 8254-const Doc = `suggested fixes for "no new vars on left side of :=" 8255- 8256-This checker provides suggested fixes for type errors of the 8257-type "no new vars on left side of :=". For example: 8258- z := 1 8259- z := 2 8260-will turn into 8261- z := 1 8262- z = 2 8263-` 8264- 8265-var Analyzer = &analysis.Analyzer{ 8266- Name: "nonewvars", 8267- Doc: Doc, 8268- Requires: []*analysis.Analyzer{inspect.Analyzer}, 8269- Run: run, 8270- RunDespiteErrors: true, 8271-} 8272- 8273-func run(pass *analysis.Pass) (interface{}, error) { 8274- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 8275- if len(pass.TypeErrors) == 0 { 8276- return nil, nil 8277- } 8278- 8279- nodeFilter := []ast.Node{(*ast.AssignStmt)(nil)} 8280- inspect.Preorder(nodeFilter, func(n ast.Node) { 8281- assignStmt, _ := n.(*ast.AssignStmt) 8282- // We only care about ":=". 8283- if assignStmt.Tok != token.DEFINE { 8284- return 8285- } 8286- 8287- var file *ast.File 8288- for _, f := range pass.Files { 8289- if f.Pos() <= assignStmt.Pos() && assignStmt.Pos() < f.End() { 8290- file = f 8291- break 8292- } 8293- } 8294- if file == nil { 8295- return 8296- } 8297- 8298- for _, err := range pass.TypeErrors { 8299- if !FixesError(err.Msg) { 8300- continue 8301- } 8302- if assignStmt.Pos() > err.Pos || err.Pos >= assignStmt.End() { 8303- continue 8304- } 8305- var buf bytes.Buffer 8306- if err := format.Node(&buf, pass.Fset, file); err != nil { 8307- continue 8308- } 8309- pass.Report(analysis.Diagnostic{ 8310- Pos: err.Pos, 8311- End: analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos), 8312- Message: err.Msg, 8313- SuggestedFixes: []analysis.SuggestedFix{{ 8314- Message: "Change ':=' to '='", 8315- TextEdits: []analysis.TextEdit{{ 8316- Pos: err.Pos, 8317- End: err.Pos + 1, 8318- }}, 8319- }}, 8320- }) 8321- } 8322- }) 8323- return nil, nil 8324-} 8325- 8326-func FixesError(msg string) bool { 8327- return msg == "no new variables on left side of :=" 8328-} 8329diff -urN a/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go b/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go 8330--- a/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go 2000-01-01 00:00:00.000000000 -0000 8331+++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go 1970-01-01 00:00:00.000000000 +0000 8332@@ -1,22 +0,0 @@ 8333-// Copyright 2020 The Go Authors. All rights reserved. 8334-// Use of this source code is governed by a BSD-style 8335-// license that can be found in the LICENSE file. 8336- 8337-package nonewvars_test 8338- 8339-import ( 8340- "testing" 8341- 8342- "golang.org/x/tools/go/analysis/analysistest" 8343- "golang.org/x/tools/gopls/internal/lsp/analysis/nonewvars" 8344- "golang.org/x/tools/internal/typeparams" 8345-) 8346- 8347-func Test(t *testing.T) { 8348- testdata := analysistest.TestData() 8349- tests := []string{"a"} 8350- if typeparams.Enabled { 8351- tests = append(tests, "typeparams") 8352- } 8353- analysistest.RunWithSuggestedFixes(t, testdata, nonewvars.Analyzer, tests...) 8354-} 8355diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go 8356--- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 8357+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 8358@@ -1,16 +0,0 @@ 8359-// Copyright 2020 The Go Authors. All rights reserved. 8360-// Use of this source code is governed by a BSD-style 8361-// license that can be found in the LICENSE file. 8362- 8363-package nonewvars 8364- 8365-import "log" 8366- 8367-func x() { 8368- z := 1 8369- z := 2 // want "no new variables on left side of :=" 8370- 8371- _, z := 3, 100 // want "no new variables on left side of :=" 8372- 8373- log.Println(z) 8374-} 8375diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden 8376--- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 8377+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 8378@@ -1,16 +0,0 @@ 8379-// Copyright 2020 The Go Authors. All rights reserved. 8380-// Use of this source code is governed by a BSD-style 8381-// license that can be found in the LICENSE file. 8382- 8383-package nonewvars 8384- 8385-import "log" 8386- 8387-func x() { 8388- z := 1 8389- z = 2 // want "no new variables on left side of :=" 8390- 8391- _, z = 3, 100 // want "no new variables on left side of :=" 8392- 8393- log.Println(z) 8394-} 8395diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go 8396--- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go 2000-01-01 00:00:00.000000000 -0000 8397+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go 1970-01-01 00:00:00.000000000 +0000 8398@@ -1,6 +0,0 @@ 8399-package nonewvars 8400- 8401-func hello[T any]() int { 8402- var z T 8403- z := 1 // want "no new variables on left side of :=" 8404-} 8405diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden 8406--- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden 2000-01-01 00:00:00.000000000 -0000 8407+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden 1970-01-01 00:00:00.000000000 +0000 8408@@ -1,6 +0,0 @@ 8409-package nonewvars 8410- 8411-func hello[T any]() int { 8412- var z T 8413- z = 1 // want "no new variables on left side of :=" 8414-} 8415diff -urN a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go 8416--- a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go 2000-01-01 00:00:00.000000000 -0000 8417+++ b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go 1970-01-01 00:00:00.000000000 +0000 8418@@ -1,92 +0,0 @@ 8419-// Copyright 2020 The Go Authors. All rights reserved. 8420-// Use of this source code is governed by a BSD-style 8421-// license that can be found in the LICENSE file. 8422- 8423-// Package noresultvalues defines an Analyzer that applies suggested fixes 8424-// to errors of the type "no result values expected". 8425-package noresultvalues 8426- 8427-import ( 8428- "bytes" 8429- "go/ast" 8430- "go/format" 8431- "strings" 8432- 8433- "golang.org/x/tools/go/analysis" 8434- "golang.org/x/tools/go/analysis/passes/inspect" 8435- "golang.org/x/tools/go/ast/inspector" 8436- "golang.org/x/tools/internal/analysisinternal" 8437-) 8438- 8439-const Doc = `suggested fixes for unexpected return values 8440- 8441-This checker provides suggested fixes for type errors of the 8442-type "no result values expected" or "too many return values". 8443-For example: 8444- func z() { return nil } 8445-will turn into 8446- func z() { return } 8447-` 8448- 8449-var Analyzer = &analysis.Analyzer{ 8450- Name: "noresultvalues", 8451- Doc: Doc, 8452- Requires: []*analysis.Analyzer{inspect.Analyzer}, 8453- Run: run, 8454- RunDespiteErrors: true, 8455-} 8456- 8457-func run(pass *analysis.Pass) (interface{}, error) { 8458- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 8459- if len(pass.TypeErrors) == 0 { 8460- return nil, nil 8461- } 8462- 8463- nodeFilter := []ast.Node{(*ast.ReturnStmt)(nil)} 8464- inspect.Preorder(nodeFilter, func(n ast.Node) { 8465- retStmt, _ := n.(*ast.ReturnStmt) 8466- 8467- var file *ast.File 8468- for _, f := range pass.Files { 8469- if f.Pos() <= retStmt.Pos() && retStmt.Pos() < f.End() { 8470- file = f 8471- break 8472- } 8473- } 8474- if file == nil { 8475- return 8476- } 8477- 8478- for _, err := range pass.TypeErrors { 8479- if !FixesError(err.Msg) { 8480- continue 8481- } 8482- if retStmt.Pos() >= err.Pos || err.Pos >= retStmt.End() { 8483- continue 8484- } 8485- var buf bytes.Buffer 8486- if err := format.Node(&buf, pass.Fset, file); err != nil { 8487- continue 8488- } 8489- pass.Report(analysis.Diagnostic{ 8490- Pos: err.Pos, 8491- End: analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos), 8492- Message: err.Msg, 8493- SuggestedFixes: []analysis.SuggestedFix{{ 8494- Message: "Delete return values", 8495- TextEdits: []analysis.TextEdit{{ 8496- Pos: retStmt.Pos(), 8497- End: retStmt.End(), 8498- NewText: []byte("return"), 8499- }}, 8500- }}, 8501- }) 8502- } 8503- }) 8504- return nil, nil 8505-} 8506- 8507-func FixesError(msg string) bool { 8508- return msg == "no result values expected" || 8509- strings.HasPrefix(msg, "too many return values") && strings.Contains(msg, "want ()") 8510-} 8511diff -urN a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go 8512--- a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go 2000-01-01 00:00:00.000000000 -0000 8513+++ b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go 1970-01-01 00:00:00.000000000 +0000 8514@@ -1,22 +0,0 @@ 8515-// Copyright 2020 The Go Authors. All rights reserved. 8516-// Use of this source code is governed by a BSD-style 8517-// license that can be found in the LICENSE file. 8518- 8519-package noresultvalues_test 8520- 8521-import ( 8522- "testing" 8523- 8524- "golang.org/x/tools/go/analysis/analysistest" 8525- "golang.org/x/tools/gopls/internal/lsp/analysis/noresultvalues" 8526- "golang.org/x/tools/internal/typeparams" 8527-) 8528- 8529-func Test(t *testing.T) { 8530- testdata := analysistest.TestData() 8531- tests := []string{"a"} 8532- if typeparams.Enabled { 8533- tests = append(tests, "typeparams") 8534- } 8535- analysistest.RunWithSuggestedFixes(t, testdata, noresultvalues.Analyzer, tests...) 8536-} 8537diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go 8538--- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 8539+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 8540@@ -1,9 +0,0 @@ 8541-// Copyright 2020 The Go Authors. All rights reserved. 8542-// Use of this source code is governed by a BSD-style 8543-// license that can be found in the LICENSE file. 8544- 8545-package noresultvalues 8546- 8547-func x() { return nil } // want `no result values expected|too many return values` 8548- 8549-func y() { return nil, "hello" } // want `no result values expected|too many return values` 8550diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden 8551--- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 8552+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 8553@@ -1,9 +0,0 @@ 8554-// Copyright 2020 The Go Authors. All rights reserved. 8555-// Use of this source code is governed by a BSD-style 8556-// license that can be found in the LICENSE file. 8557- 8558-package noresultvalues 8559- 8560-func x() { return } // want `no result values expected|too many return values` 8561- 8562-func y() { return } // want `no result values expected|too many return values` 8563diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go 8564--- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go 2000-01-01 00:00:00.000000000 -0000 8565+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go 1970-01-01 00:00:00.000000000 +0000 8566@@ -1,6 +0,0 @@ 8567-package noresult 8568- 8569-func hello[T any]() { 8570- var z T 8571- return z // want `no result values expected|too many return values` 8572-} 8573diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden 8574--- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden 2000-01-01 00:00:00.000000000 -0000 8575+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden 1970-01-01 00:00:00.000000000 +0000 8576@@ -1,6 +0,0 @@ 8577-package noresult 8578- 8579-func hello[T any]() { 8580- var z T 8581- return // want `no result values expected|too many return values` 8582-} 8583diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go 8584--- a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go 2000-01-01 00:00:00.000000000 -0000 8585+++ b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go 1970-01-01 00:00:00.000000000 +0000 8586@@ -1,196 +0,0 @@ 8587-// Copyright 2020 The Go Authors. All rights reserved. 8588-// Use of this source code is governed by a BSD-style 8589-// license that can be found in the LICENSE file. 8590- 8591-// Package simplifycompositelit defines an Analyzer that simplifies composite literals. 8592-// https://github.com/golang/go/blob/master/src/cmd/gofmt/simplify.go 8593-// https://golang.org/cmd/gofmt/#hdr-The_simplify_command 8594-package simplifycompositelit 8595- 8596-import ( 8597- "bytes" 8598- "fmt" 8599- "go/ast" 8600- "go/printer" 8601- "go/token" 8602- "reflect" 8603- 8604- "golang.org/x/tools/go/analysis" 8605- "golang.org/x/tools/go/analysis/passes/inspect" 8606- "golang.org/x/tools/go/ast/inspector" 8607-) 8608- 8609-const Doc = `check for composite literal simplifications 8610- 8611-An array, slice, or map composite literal of the form: 8612- []T{T{}, T{}} 8613-will be simplified to: 8614- []T{{}, {}} 8615- 8616-This is one of the simplifications that "gofmt -s" applies.` 8617- 8618-var Analyzer = &analysis.Analyzer{ 8619- Name: "simplifycompositelit", 8620- Doc: Doc, 8621- Requires: []*analysis.Analyzer{inspect.Analyzer}, 8622- Run: run, 8623-} 8624- 8625-func run(pass *analysis.Pass) (interface{}, error) { 8626- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 8627- nodeFilter := []ast.Node{(*ast.CompositeLit)(nil)} 8628- inspect.Preorder(nodeFilter, func(n ast.Node) { 8629- expr := n.(*ast.CompositeLit) 8630- 8631- outer := expr 8632- var keyType, eltType ast.Expr 8633- switch typ := outer.Type.(type) { 8634- case *ast.ArrayType: 8635- eltType = typ.Elt 8636- case *ast.MapType: 8637- keyType = typ.Key 8638- eltType = typ.Value 8639- } 8640- 8641- if eltType == nil { 8642- return 8643- } 8644- var ktyp reflect.Value 8645- if keyType != nil { 8646- ktyp = reflect.ValueOf(keyType) 8647- } 8648- typ := reflect.ValueOf(eltType) 8649- for _, x := range outer.Elts { 8650- // look at value of indexed/named elements 8651- if t, ok := x.(*ast.KeyValueExpr); ok { 8652- if keyType != nil { 8653- simplifyLiteral(pass, ktyp, keyType, t.Key) 8654- } 8655- x = t.Value 8656- } 8657- simplifyLiteral(pass, typ, eltType, x) 8658- } 8659- }) 8660- return nil, nil 8661-} 8662- 8663-func simplifyLiteral(pass *analysis.Pass, typ reflect.Value, astType, x ast.Expr) { 8664- // if the element is a composite literal and its literal type 8665- // matches the outer literal's element type exactly, the inner 8666- // literal type may be omitted 8667- if inner, ok := x.(*ast.CompositeLit); ok && match(typ, reflect.ValueOf(inner.Type)) { 8668- var b bytes.Buffer 8669- printer.Fprint(&b, pass.Fset, inner.Type) 8670- createDiagnostic(pass, inner.Type.Pos(), inner.Type.End(), b.String()) 8671- } 8672- // if the outer literal's element type is a pointer type *T 8673- // and the element is & of a composite literal of type T, 8674- // the inner &T may be omitted. 8675- if ptr, ok := astType.(*ast.StarExpr); ok { 8676- if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND { 8677- if inner, ok := addr.X.(*ast.CompositeLit); ok { 8678- if match(reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) { 8679- var b bytes.Buffer 8680- printer.Fprint(&b, pass.Fset, inner.Type) 8681- // Account for the & by subtracting 1 from typ.Pos(). 8682- createDiagnostic(pass, inner.Type.Pos()-1, inner.Type.End(), "&"+b.String()) 8683- } 8684- } 8685- } 8686- } 8687-} 8688- 8689-func createDiagnostic(pass *analysis.Pass, start, end token.Pos, typ string) { 8690- pass.Report(analysis.Diagnostic{ 8691- Pos: start, 8692- End: end, 8693- Message: "redundant type from array, slice, or map composite literal", 8694- SuggestedFixes: []analysis.SuggestedFix{{ 8695- Message: fmt.Sprintf("Remove '%s'", typ), 8696- TextEdits: []analysis.TextEdit{{ 8697- Pos: start, 8698- End: end, 8699- NewText: []byte{}, 8700- }}, 8701- }}, 8702- }) 8703-} 8704- 8705-// match reports whether pattern matches val, 8706-// recording wildcard submatches in m. 8707-// If m == nil, match checks whether pattern == val. 8708-// from https://github.com/golang/go/blob/26154f31ad6c801d8bad5ef58df1e9263c6beec7/src/cmd/gofmt/rewrite.go#L160 8709-func match(pattern, val reflect.Value) bool { 8710- // Otherwise, pattern and val must match recursively. 8711- if !pattern.IsValid() || !val.IsValid() { 8712- return !pattern.IsValid() && !val.IsValid() 8713- } 8714- if pattern.Type() != val.Type() { 8715- return false 8716- } 8717- 8718- // Special cases. 8719- switch pattern.Type() { 8720- case identType: 8721- // For identifiers, only the names need to match 8722- // (and none of the other *ast.Object information). 8723- // This is a common case, handle it all here instead 8724- // of recursing down any further via reflection. 8725- p := pattern.Interface().(*ast.Ident) 8726- v := val.Interface().(*ast.Ident) 8727- return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name 8728- case objectPtrType, positionType: 8729- // object pointers and token positions always match 8730- return true 8731- case callExprType: 8732- // For calls, the Ellipsis fields (token.Position) must 8733- // match since that is how f(x) and f(x...) are different. 8734- // Check them here but fall through for the remaining fields. 8735- p := pattern.Interface().(*ast.CallExpr) 8736- v := val.Interface().(*ast.CallExpr) 8737- if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() { 8738- return false 8739- } 8740- } 8741- 8742- p := reflect.Indirect(pattern) 8743- v := reflect.Indirect(val) 8744- if !p.IsValid() || !v.IsValid() { 8745- return !p.IsValid() && !v.IsValid() 8746- } 8747- 8748- switch p.Kind() { 8749- case reflect.Slice: 8750- if p.Len() != v.Len() { 8751- return false 8752- } 8753- for i := 0; i < p.Len(); i++ { 8754- if !match(p.Index(i), v.Index(i)) { 8755- return false 8756- } 8757- } 8758- return true 8759- 8760- case reflect.Struct: 8761- for i := 0; i < p.NumField(); i++ { 8762- if !match(p.Field(i), v.Field(i)) { 8763- return false 8764- } 8765- } 8766- return true 8767- 8768- case reflect.Interface: 8769- return match(p.Elem(), v.Elem()) 8770- } 8771- 8772- // Handle token integers, etc. 8773- return p.Interface() == v.Interface() 8774-} 8775- 8776-// Values/types for special cases. 8777-var ( 8778- identType = reflect.TypeOf((*ast.Ident)(nil)) 8779- objectPtrType = reflect.TypeOf((*ast.Object)(nil)) 8780- positionType = reflect.TypeOf(token.NoPos) 8781- callExprType = reflect.TypeOf((*ast.CallExpr)(nil)) 8782-) 8783diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go 8784--- a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go 2000-01-01 00:00:00.000000000 -0000 8785+++ b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go 1970-01-01 00:00:00.000000000 +0000 8786@@ -1,17 +0,0 @@ 8787-// Copyright 2020 The Go Authors. All rights reserved. 8788-// Use of this source code is governed by a BSD-style 8789-// license that can be found in the LICENSE file. 8790- 8791-package simplifycompositelit_test 8792- 8793-import ( 8794- "testing" 8795- 8796- "golang.org/x/tools/go/analysis/analysistest" 8797- "golang.org/x/tools/gopls/internal/lsp/analysis/simplifycompositelit" 8798-) 8799- 8800-func Test(t *testing.T) { 8801- testdata := analysistest.TestData() 8802- analysistest.RunWithSuggestedFixes(t, testdata, simplifycompositelit.Analyzer, "a") 8803-} 8804diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go 8805--- a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 8806+++ b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 8807@@ -1,234 +0,0 @@ 8808-// Copyright 2020 The Go Authors. All rights reserved. 8809-// Use of this source code is governed by a BSD-style 8810-// license that can be found in the LICENSE file. 8811- 8812-package testdata 8813- 8814-type T struct { 8815- x, y int 8816-} 8817- 8818-type T2 struct { 8819- w, z int 8820-} 8821- 8822-var _ = [42]T{ 8823- T{}, // want "redundant type from array, slice, or map composite literal" 8824- T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8825- T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8826-} 8827- 8828-var _ = [...]T{ 8829- T{}, // want "redundant type from array, slice, or map composite literal" 8830- T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8831- T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8832-} 8833- 8834-var _ = []T{ 8835- T{}, // want "redundant type from array, slice, or map composite literal" 8836- T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8837- T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8838-} 8839- 8840-var _ = []T{ 8841- T{}, // want "redundant type from array, slice, or map composite literal" 8842- 10: T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8843- 20: T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8844-} 8845- 8846-var _ = []struct { 8847- x, y int 8848-}{ 8849- struct{ x, y int }{}, // want "redundant type from array, slice, or map composite literal" 8850- 10: struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal" 8851- 20: struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal" 8852-} 8853- 8854-var _ = []interface{}{ 8855- T{}, 8856- 10: T{1, 2}, 8857- 20: T{3, 4}, 8858-} 8859- 8860-var _ = [][]int{ 8861- []int{}, // want "redundant type from array, slice, or map composite literal" 8862- []int{1, 2}, // want "redundant type from array, slice, or map composite literal" 8863- []int{3, 4}, // want "redundant type from array, slice, or map composite literal" 8864-} 8865- 8866-var _ = [][]int{ 8867- ([]int{}), 8868- ([]int{1, 2}), 8869- []int{3, 4}, // want "redundant type from array, slice, or map composite literal" 8870-} 8871- 8872-var _ = [][][]int{ 8873- [][]int{}, // want "redundant type from array, slice, or map composite literal" 8874- [][]int{ // want "redundant type from array, slice, or map composite literal" 8875- []int{}, // want "redundant type from array, slice, or map composite literal" 8876- []int{0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal" 8877- []int{4, 5}, // want "redundant type from array, slice, or map composite literal" 8878- }, 8879-} 8880- 8881-var _ = map[string]T{ 8882- "foo": T{}, // want "redundant type from array, slice, or map composite literal" 8883- "bar": T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8884- "bal": T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8885-} 8886- 8887-var _ = map[string]struct { 8888- x, y int 8889-}{ 8890- "foo": struct{ x, y int }{}, // want "redundant type from array, slice, or map composite literal" 8891- "bar": struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal" 8892- "bal": struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal" 8893-} 8894- 8895-var _ = map[string]interface{}{ 8896- "foo": T{}, 8897- "bar": T{1, 2}, 8898- "bal": T{3, 4}, 8899-} 8900- 8901-var _ = map[string][]int{ 8902- "foo": []int{}, // want "redundant type from array, slice, or map composite literal" 8903- "bar": []int{1, 2}, // want "redundant type from array, slice, or map composite literal" 8904- "bal": []int{3, 4}, // want "redundant type from array, slice, or map composite literal" 8905-} 8906- 8907-var _ = map[string][]int{ 8908- "foo": ([]int{}), 8909- "bar": ([]int{1, 2}), 8910- "bal": []int{3, 4}, // want "redundant type from array, slice, or map composite literal" 8911-} 8912- 8913-type Point struct { 8914- a int 8915- b int 8916-} 8917- 8918-type Piece struct { 8919- a int 8920- b int 8921- c Point 8922- d []Point 8923- e *Point 8924- f *Point 8925-} 8926- 8927-// from exp/4s/data.go 8928-var pieces3 = []Piece{ 8929- Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 8930- Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 8931- Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 8932- Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 8933-} 8934- 8935-var _ = [42]*T{ 8936- &T{}, // want "redundant type from array, slice, or map composite literal" 8937- &T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8938- &T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8939-} 8940- 8941-var _ = [...]*T{ 8942- &T{}, // want "redundant type from array, slice, or map composite literal" 8943- &T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8944- &T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8945-} 8946- 8947-var _ = []*T{ 8948- &T{}, // want "redundant type from array, slice, or map composite literal" 8949- &T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8950- &T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8951-} 8952- 8953-var _ = []*T{ 8954- &T{}, // want "redundant type from array, slice, or map composite literal" 8955- 10: &T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8956- 20: &T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8957-} 8958- 8959-var _ = []*struct { 8960- x, y int 8961-}{ 8962- &struct{ x, y int }{}, // want "redundant type from array, slice, or map composite literal" 8963- 10: &struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal" 8964- 20: &struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal" 8965-} 8966- 8967-var _ = []interface{}{ 8968- &T{}, 8969- 10: &T{1, 2}, 8970- 20: &T{3, 4}, 8971-} 8972- 8973-var _ = []*[]int{ 8974- &[]int{}, // want "redundant type from array, slice, or map composite literal" 8975- &[]int{1, 2}, // want "redundant type from array, slice, or map composite literal" 8976- &[]int{3, 4}, // want "redundant type from array, slice, or map composite literal" 8977-} 8978- 8979-var _ = []*[]int{ 8980- (&[]int{}), 8981- (&[]int{1, 2}), 8982- &[]int{3, 4}, // want "redundant type from array, slice, or map composite literal" 8983-} 8984- 8985-var _ = []*[]*[]int{ 8986- &[]*[]int{}, // want "redundant type from array, slice, or map composite literal" 8987- &[]*[]int{ // want "redundant type from array, slice, or map composite literal" 8988- &[]int{}, // want "redundant type from array, slice, or map composite literal" 8989- &[]int{0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal" 8990- &[]int{4, 5}, // want "redundant type from array, slice, or map composite literal" 8991- }, 8992-} 8993- 8994-var _ = map[string]*T{ 8995- "foo": &T{}, // want "redundant type from array, slice, or map composite literal" 8996- "bar": &T{1, 2}, // want "redundant type from array, slice, or map composite literal" 8997- "bal": &T{3, 4}, // want "redundant type from array, slice, or map composite literal" 8998-} 8999- 9000-var _ = map[string]*struct { 9001- x, y int 9002-}{ 9003- "foo": &struct{ x, y int }{}, // want "redundant type from array, slice, or map composite literal" 9004- "bar": &struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal" 9005- "bal": &struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal" 9006-} 9007- 9008-var _ = map[string]interface{}{ 9009- "foo": &T{}, 9010- "bar": &T{1, 2}, 9011- "bal": &T{3, 4}, 9012-} 9013- 9014-var _ = map[string]*[]int{ 9015- "foo": &[]int{}, // want "redundant type from array, slice, or map composite literal" 9016- "bar": &[]int{1, 2}, // want "redundant type from array, slice, or map composite literal" 9017- "bal": &[]int{3, 4}, // want "redundant type from array, slice, or map composite literal" 9018-} 9019- 9020-var _ = map[string]*[]int{ 9021- "foo": (&[]int{}), 9022- "bar": (&[]int{1, 2}), 9023- "bal": &[]int{3, 4}, // want "redundant type from array, slice, or map composite literal" 9024-} 9025- 9026-var pieces4 = []*Piece{ 9027- &Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9028- &Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9029- &Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9030- &Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9031-} 9032- 9033-var _ = map[T]T2{ 9034- T{1, 2}: T2{3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9035- T{5, 6}: T2{7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9036-} 9037- 9038-var _ = map[*T]*T2{ 9039- &T{1, 2}: &T2{3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9040- &T{5, 6}: &T2{7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9041-} 9042diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden 9043--- a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 9044+++ b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 9045@@ -1,234 +0,0 @@ 9046-// Copyright 2020 The Go Authors. All rights reserved. 9047-// Use of this source code is governed by a BSD-style 9048-// license that can be found in the LICENSE file. 9049- 9050-package testdata 9051- 9052-type T struct { 9053- x, y int 9054-} 9055- 9056-type T2 struct { 9057- w, z int 9058-} 9059- 9060-var _ = [42]T{ 9061- {}, // want "redundant type from array, slice, or map composite literal" 9062- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9063- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9064-} 9065- 9066-var _ = [...]T{ 9067- {}, // want "redundant type from array, slice, or map composite literal" 9068- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9069- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9070-} 9071- 9072-var _ = []T{ 9073- {}, // want "redundant type from array, slice, or map composite literal" 9074- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9075- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9076-} 9077- 9078-var _ = []T{ 9079- {}, // want "redundant type from array, slice, or map composite literal" 9080- 10: {1, 2}, // want "redundant type from array, slice, or map composite literal" 9081- 20: {3, 4}, // want "redundant type from array, slice, or map composite literal" 9082-} 9083- 9084-var _ = []struct { 9085- x, y int 9086-}{ 9087- {}, // want "redundant type from array, slice, or map composite literal" 9088- 10: {1, 2}, // want "redundant type from array, slice, or map composite literal" 9089- 20: {3, 4}, // want "redundant type from array, slice, or map composite literal" 9090-} 9091- 9092-var _ = []interface{}{ 9093- T{}, 9094- 10: T{1, 2}, 9095- 20: T{3, 4}, 9096-} 9097- 9098-var _ = [][]int{ 9099- {}, // want "redundant type from array, slice, or map composite literal" 9100- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9101- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9102-} 9103- 9104-var _ = [][]int{ 9105- ([]int{}), 9106- ([]int{1, 2}), 9107- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9108-} 9109- 9110-var _ = [][][]int{ 9111- {}, // want "redundant type from array, slice, or map composite literal" 9112- { // want "redundant type from array, slice, or map composite literal" 9113- {}, // want "redundant type from array, slice, or map composite literal" 9114- {0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal" 9115- {4, 5}, // want "redundant type from array, slice, or map composite literal" 9116- }, 9117-} 9118- 9119-var _ = map[string]T{ 9120- "foo": {}, // want "redundant type from array, slice, or map composite literal" 9121- "bar": {1, 2}, // want "redundant type from array, slice, or map composite literal" 9122- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9123-} 9124- 9125-var _ = map[string]struct { 9126- x, y int 9127-}{ 9128- "foo": {}, // want "redundant type from array, slice, or map composite literal" 9129- "bar": {1, 2}, // want "redundant type from array, slice, or map composite literal" 9130- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9131-} 9132- 9133-var _ = map[string]interface{}{ 9134- "foo": T{}, 9135- "bar": T{1, 2}, 9136- "bal": T{3, 4}, 9137-} 9138- 9139-var _ = map[string][]int{ 9140- "foo": {}, // want "redundant type from array, slice, or map composite literal" 9141- "bar": {1, 2}, // want "redundant type from array, slice, or map composite literal" 9142- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9143-} 9144- 9145-var _ = map[string][]int{ 9146- "foo": ([]int{}), 9147- "bar": ([]int{1, 2}), 9148- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9149-} 9150- 9151-type Point struct { 9152- a int 9153- b int 9154-} 9155- 9156-type Piece struct { 9157- a int 9158- b int 9159- c Point 9160- d []Point 9161- e *Point 9162- f *Point 9163-} 9164- 9165-// from exp/4s/data.go 9166-var pieces3 = []Piece{ 9167- {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9168- {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9169- {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9170- {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9171-} 9172- 9173-var _ = [42]*T{ 9174- {}, // want "redundant type from array, slice, or map composite literal" 9175- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9176- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9177-} 9178- 9179-var _ = [...]*T{ 9180- {}, // want "redundant type from array, slice, or map composite literal" 9181- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9182- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9183-} 9184- 9185-var _ = []*T{ 9186- {}, // want "redundant type from array, slice, or map composite literal" 9187- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9188- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9189-} 9190- 9191-var _ = []*T{ 9192- {}, // want "redundant type from array, slice, or map composite literal" 9193- 10: {1, 2}, // want "redundant type from array, slice, or map composite literal" 9194- 20: {3, 4}, // want "redundant type from array, slice, or map composite literal" 9195-} 9196- 9197-var _ = []*struct { 9198- x, y int 9199-}{ 9200- {}, // want "redundant type from array, slice, or map composite literal" 9201- 10: {1, 2}, // want "redundant type from array, slice, or map composite literal" 9202- 20: {3, 4}, // want "redundant type from array, slice, or map composite literal" 9203-} 9204- 9205-var _ = []interface{}{ 9206- &T{}, 9207- 10: &T{1, 2}, 9208- 20: &T{3, 4}, 9209-} 9210- 9211-var _ = []*[]int{ 9212- {}, // want "redundant type from array, slice, or map composite literal" 9213- {1, 2}, // want "redundant type from array, slice, or map composite literal" 9214- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9215-} 9216- 9217-var _ = []*[]int{ 9218- (&[]int{}), 9219- (&[]int{1, 2}), 9220- {3, 4}, // want "redundant type from array, slice, or map composite literal" 9221-} 9222- 9223-var _ = []*[]*[]int{ 9224- {}, // want "redundant type from array, slice, or map composite literal" 9225- { // want "redundant type from array, slice, or map composite literal" 9226- {}, // want "redundant type from array, slice, or map composite literal" 9227- {0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal" 9228- {4, 5}, // want "redundant type from array, slice, or map composite literal" 9229- }, 9230-} 9231- 9232-var _ = map[string]*T{ 9233- "foo": {}, // want "redundant type from array, slice, or map composite literal" 9234- "bar": {1, 2}, // want "redundant type from array, slice, or map composite literal" 9235- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9236-} 9237- 9238-var _ = map[string]*struct { 9239- x, y int 9240-}{ 9241- "foo": {}, // want "redundant type from array, slice, or map composite literal" 9242- "bar": {1, 2}, // want "redundant type from array, slice, or map composite literal" 9243- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9244-} 9245- 9246-var _ = map[string]interface{}{ 9247- "foo": &T{}, 9248- "bar": &T{1, 2}, 9249- "bal": &T{3, 4}, 9250-} 9251- 9252-var _ = map[string]*[]int{ 9253- "foo": {}, // want "redundant type from array, slice, or map composite literal" 9254- "bar": {1, 2}, // want "redundant type from array, slice, or map composite literal" 9255- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9256-} 9257- 9258-var _ = map[string]*[]int{ 9259- "foo": (&[]int{}), 9260- "bar": (&[]int{1, 2}), 9261- "bal": {3, 4}, // want "redundant type from array, slice, or map composite literal" 9262-} 9263- 9264-var pieces4 = []*Piece{ 9265- {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9266- {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9267- {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9268- {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9269-} 9270- 9271-var _ = map[T]T2{ 9272- {1, 2}: {3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9273- {5, 6}: {7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9274-} 9275- 9276-var _ = map[*T]*T2{ 9277- {1, 2}: {3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9278- {5, 6}: {7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" 9279-} 9280diff -urN a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go 9281--- a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go 2000-01-01 00:00:00.000000000 -0000 9282+++ b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go 1970-01-01 00:00:00.000000000 +0000 9283@@ -1,116 +0,0 @@ 9284-// Copyright 2020 The Go Authors. All rights reserved. 9285-// Use of this source code is governed by a BSD-style 9286-// license that can be found in the LICENSE file. 9287- 9288-// Package simplifyrange defines an Analyzer that simplifies range statements. 9289-// https://golang.org/cmd/gofmt/#hdr-The_simplify_command 9290-// https://github.com/golang/go/blob/master/src/cmd/gofmt/simplify.go 9291-package simplifyrange 9292- 9293-import ( 9294- "bytes" 9295- "go/ast" 9296- "go/printer" 9297- "go/token" 9298- 9299- "golang.org/x/tools/go/analysis" 9300- "golang.org/x/tools/go/analysis/passes/inspect" 9301- "golang.org/x/tools/go/ast/inspector" 9302-) 9303- 9304-const Doc = `check for range statement simplifications 9305- 9306-A range of the form: 9307- for x, _ = range v {...} 9308-will be simplified to: 9309- for x = range v {...} 9310- 9311-A range of the form: 9312- for _ = range v {...} 9313-will be simplified to: 9314- for range v {...} 9315- 9316-This is one of the simplifications that "gofmt -s" applies.` 9317- 9318-var Analyzer = &analysis.Analyzer{ 9319- Name: "simplifyrange", 9320- Doc: Doc, 9321- Requires: []*analysis.Analyzer{inspect.Analyzer}, 9322- Run: run, 9323-} 9324- 9325-func run(pass *analysis.Pass) (interface{}, error) { 9326- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 9327- nodeFilter := []ast.Node{ 9328- (*ast.RangeStmt)(nil), 9329- } 9330- inspect.Preorder(nodeFilter, func(n ast.Node) { 9331- var copy *ast.RangeStmt 9332- if stmt, ok := n.(*ast.RangeStmt); ok { 9333- x := *stmt 9334- copy = &x 9335- } 9336- if copy == nil { 9337- return 9338- } 9339- end := newlineIndex(pass.Fset, copy) 9340- 9341- // Range statements of the form: for i, _ := range x {} 9342- var old ast.Expr 9343- if isBlank(copy.Value) { 9344- old = copy.Value 9345- copy.Value = nil 9346- } 9347- // Range statements of the form: for _ := range x {} 9348- if isBlank(copy.Key) && copy.Value == nil { 9349- old = copy.Key 9350- copy.Key = nil 9351- } 9352- // Return early if neither if condition is met. 9353- if old == nil { 9354- return 9355- } 9356- pass.Report(analysis.Diagnostic{ 9357- Pos: old.Pos(), 9358- End: old.End(), 9359- Message: "simplify range expression", 9360- SuggestedFixes: suggestedFixes(pass.Fset, copy, end), 9361- }) 9362- }) 9363- return nil, nil 9364-} 9365- 9366-func suggestedFixes(fset *token.FileSet, rng *ast.RangeStmt, end token.Pos) []analysis.SuggestedFix { 9367- var b bytes.Buffer 9368- printer.Fprint(&b, fset, rng) 9369- stmt := b.Bytes() 9370- index := bytes.Index(stmt, []byte("\n")) 9371- // If there is a new line character, then don't replace the body. 9372- if index != -1 { 9373- stmt = stmt[:index] 9374- } 9375- return []analysis.SuggestedFix{{ 9376- Message: "Remove empty value", 9377- TextEdits: []analysis.TextEdit{{ 9378- Pos: rng.Pos(), 9379- End: end, 9380- NewText: stmt[:index], 9381- }}, 9382- }} 9383-} 9384- 9385-func newlineIndex(fset *token.FileSet, rng *ast.RangeStmt) token.Pos { 9386- var b bytes.Buffer 9387- printer.Fprint(&b, fset, rng) 9388- contents := b.Bytes() 9389- index := bytes.Index(contents, []byte("\n")) 9390- if index == -1 { 9391- return rng.End() 9392- } 9393- return rng.Pos() + token.Pos(index) 9394-} 9395- 9396-func isBlank(x ast.Expr) bool { 9397- ident, ok := x.(*ast.Ident) 9398- return ok && ident.Name == "_" 9399-} 9400diff -urN a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go 9401--- a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go 2000-01-01 00:00:00.000000000 -0000 9402+++ b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go 1970-01-01 00:00:00.000000000 +0000 9403@@ -1,17 +0,0 @@ 9404-// Copyright 2020 The Go Authors. All rights reserved. 9405-// Use of this source code is governed by a BSD-style 9406-// license that can be found in the LICENSE file. 9407- 9408-package simplifyrange_test 9409- 9410-import ( 9411- "testing" 9412- 9413- "golang.org/x/tools/go/analysis/analysistest" 9414- "golang.org/x/tools/gopls/internal/lsp/analysis/simplifyrange" 9415-) 9416- 9417-func Test(t *testing.T) { 9418- testdata := analysistest.TestData() 9419- analysistest.RunWithSuggestedFixes(t, testdata, simplifyrange.Analyzer, "a") 9420-} 9421diff -urN a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go 9422--- a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 9423+++ b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 9424@@ -1,16 +0,0 @@ 9425-// Copyright 2020 The Go Authors. All rights reserved. 9426-// Use of this source code is governed by a BSD-style 9427-// license that can be found in the LICENSE file. 9428- 9429-package testdata 9430- 9431-import "log" 9432- 9433-func m() { 9434- maps := make(map[string]string) 9435- for k, _ := range maps { // want "simplify range expression" 9436- log.Println(k) 9437- } 9438- for _ = range maps { // want "simplify range expression" 9439- } 9440-} 9441diff -urN a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden 9442--- a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 9443+++ b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 9444@@ -1,16 +0,0 @@ 9445-// Copyright 2020 The Go Authors. All rights reserved. 9446-// Use of this source code is governed by a BSD-style 9447-// license that can be found in the LICENSE file. 9448- 9449-package testdata 9450- 9451-import "log" 9452- 9453-func m() { 9454- maps := make(map[string]string) 9455- for k := range maps { // want "simplify range expression" 9456- log.Println(k) 9457- } 9458- for range maps { // want "simplify range expression" 9459- } 9460-} 9461diff -urN a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go 9462--- a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go 2000-01-01 00:00:00.000000000 -0000 9463+++ b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go 1970-01-01 00:00:00.000000000 +0000 9464@@ -1,94 +0,0 @@ 9465-// Copyright 2020 The Go Authors. All rights reserved. 9466-// Use of this source code is governed by a BSD-style 9467-// license that can be found in the LICENSE file. 9468- 9469-// Package simplifyslice defines an Analyzer that simplifies slice statements. 9470-// https://github.com/golang/go/blob/master/src/cmd/gofmt/simplify.go 9471-// https://golang.org/cmd/gofmt/#hdr-The_simplify_command 9472-package simplifyslice 9473- 9474-import ( 9475- "bytes" 9476- "fmt" 9477- "go/ast" 9478- "go/printer" 9479- 9480- "golang.org/x/tools/go/analysis" 9481- "golang.org/x/tools/go/analysis/passes/inspect" 9482- "golang.org/x/tools/go/ast/inspector" 9483-) 9484- 9485-const Doc = `check for slice simplifications 9486- 9487-A slice expression of the form: 9488- s[a:len(s)] 9489-will be simplified to: 9490- s[a:] 9491- 9492-This is one of the simplifications that "gofmt -s" applies.` 9493- 9494-var Analyzer = &analysis.Analyzer{ 9495- Name: "simplifyslice", 9496- Doc: Doc, 9497- Requires: []*analysis.Analyzer{inspect.Analyzer}, 9498- Run: run, 9499-} 9500- 9501-// Note: We could also simplify slice expressions of the form s[0:b] to s[:b] 9502-// but we leave them as is since sometimes we want to be very explicit 9503-// about the lower bound. 9504-// An example where the 0 helps: 9505-// x, y, z := b[0:2], b[2:4], b[4:6] 9506-// An example where it does not: 9507-// x, y := b[:n], b[n:] 9508- 9509-func run(pass *analysis.Pass) (interface{}, error) { 9510- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 9511- nodeFilter := []ast.Node{ 9512- (*ast.SliceExpr)(nil), 9513- } 9514- inspect.Preorder(nodeFilter, func(n ast.Node) { 9515- expr := n.(*ast.SliceExpr) 9516- // - 3-index slices always require the 2nd and 3rd index 9517- if expr.Max != nil { 9518- return 9519- } 9520- s, ok := expr.X.(*ast.Ident) 9521- // the array/slice object is a single, resolved identifier 9522- if !ok || s.Obj == nil { 9523- return 9524- } 9525- call, ok := expr.High.(*ast.CallExpr) 9526- // the high expression is a function call with a single argument 9527- if !ok || len(call.Args) != 1 || call.Ellipsis.IsValid() { 9528- return 9529- } 9530- fun, ok := call.Fun.(*ast.Ident) 9531- // the function called is "len" and it is not locally defined; and 9532- // because we don't have dot imports, it must be the predefined len() 9533- if !ok || fun.Name != "len" || fun.Obj != nil { 9534- return 9535- } 9536- arg, ok := call.Args[0].(*ast.Ident) 9537- // the len argument is the array/slice object 9538- if !ok || arg.Obj != s.Obj { 9539- return 9540- } 9541- var b bytes.Buffer 9542- printer.Fprint(&b, pass.Fset, expr.High) 9543- pass.Report(analysis.Diagnostic{ 9544- Pos: expr.High.Pos(), 9545- End: expr.High.End(), 9546- Message: fmt.Sprintf("unneeded: %s", b.String()), 9547- SuggestedFixes: []analysis.SuggestedFix{{ 9548- Message: fmt.Sprintf("Remove '%s'", b.String()), 9549- TextEdits: []analysis.TextEdit{{ 9550- Pos: expr.High.Pos(), 9551- End: expr.High.End(), 9552- NewText: []byte{}, 9553- }}, 9554- }}, 9555- }) 9556- }) 9557- return nil, nil 9558-} 9559diff -urN a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go 9560--- a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go 2000-01-01 00:00:00.000000000 -0000 9561+++ b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go 1970-01-01 00:00:00.000000000 +0000 9562@@ -1,22 +0,0 @@ 9563-// Copyright 2020 The Go Authors. All rights reserved. 9564-// Use of this source code is governed by a BSD-style 9565-// license that can be found in the LICENSE file. 9566- 9567-package simplifyslice_test 9568- 9569-import ( 9570- "testing" 9571- 9572- "golang.org/x/tools/go/analysis/analysistest" 9573- "golang.org/x/tools/gopls/internal/lsp/analysis/simplifyslice" 9574- "golang.org/x/tools/internal/typeparams" 9575-) 9576- 9577-func Test(t *testing.T) { 9578- testdata := analysistest.TestData() 9579- tests := []string{"a"} 9580- if typeparams.Enabled { 9581- tests = append(tests, "typeparams") 9582- } 9583- analysistest.RunWithSuggestedFixes(t, testdata, simplifyslice.Analyzer, tests...) 9584-} 9585diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go 9586--- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 9587+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 9588@@ -1,70 +0,0 @@ 9589-// Copyright 2020 The Go Authors. All rights reserved. 9590-// Use of this source code is governed by a BSD-style 9591-// license that can be found in the LICENSE file. 9592- 9593-package testdata 9594- 9595-var ( 9596- a [10]byte 9597- b [20]float32 9598- s []int 9599- t struct { 9600- s []byte 9601- } 9602- 9603- _ = a[0:] 9604- _ = a[1:10] 9605- _ = a[2:len(a)] // want "unneeded: len\\(a\\)" 9606- _ = a[3:(len(a))] 9607- _ = a[len(a)-1 : len(a)] // want "unneeded: len\\(a\\)" 9608- _ = a[2:len(a):len(a)] 9609- 9610- _ = a[:] 9611- _ = a[:10] 9612- _ = a[:len(a)] // want "unneeded: len\\(a\\)" 9613- _ = a[:(len(a))] 9614- _ = a[:len(a)-1] 9615- _ = a[:len(a):len(a)] 9616- 9617- _ = s[0:] 9618- _ = s[1:10] 9619- _ = s[2:len(s)] // want "unneeded: len\\(s\\)" 9620- _ = s[3:(len(s))] 9621- _ = s[len(a) : len(s)-1] 9622- _ = s[0:len(b)] 9623- _ = s[2:len(s):len(s)] 9624- 9625- _ = s[:] 9626- _ = s[:10] 9627- _ = s[:len(s)] // want "unneeded: len\\(s\\)" 9628- _ = s[:(len(s))] 9629- _ = s[:len(s)-1] 9630- _ = s[:len(b)] 9631- _ = s[:len(s):len(s)] 9632- 9633- _ = t.s[0:] 9634- _ = t.s[1:10] 9635- _ = t.s[2:len(t.s)] 9636- _ = t.s[3:(len(t.s))] 9637- _ = t.s[len(a) : len(t.s)-1] 9638- _ = t.s[0:len(b)] 9639- _ = t.s[2:len(t.s):len(t.s)] 9640- 9641- _ = t.s[:] 9642- _ = t.s[:10] 9643- _ = t.s[:len(t.s)] 9644- _ = t.s[:(len(t.s))] 9645- _ = t.s[:len(t.s)-1] 9646- _ = t.s[:len(b)] 9647- _ = t.s[:len(t.s):len(t.s)] 9648-) 9649- 9650-func _() { 9651- s := s[0:len(s)] // want "unneeded: len\\(s\\)" 9652- _ = s 9653-} 9654- 9655-func m() { 9656- maps := []int{} 9657- _ = maps[1:len(maps)] // want "unneeded: len\\(maps\\)" 9658-} 9659diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden 9660--- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 9661+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 9662@@ -1,70 +0,0 @@ 9663-// Copyright 2020 The Go Authors. All rights reserved. 9664-// Use of this source code is governed by a BSD-style 9665-// license that can be found in the LICENSE file. 9666- 9667-package testdata 9668- 9669-var ( 9670- a [10]byte 9671- b [20]float32 9672- s []int 9673- t struct { 9674- s []byte 9675- } 9676- 9677- _ = a[0:] 9678- _ = a[1:10] 9679- _ = a[2:] // want "unneeded: len\\(a\\)" 9680- _ = a[3:(len(a))] 9681- _ = a[len(a)-1:] // want "unneeded: len\\(a\\)" 9682- _ = a[2:len(a):len(a)] 9683- 9684- _ = a[:] 9685- _ = a[:10] 9686- _ = a[:] // want "unneeded: len\\(a\\)" 9687- _ = a[:(len(a))] 9688- _ = a[:len(a)-1] 9689- _ = a[:len(a):len(a)] 9690- 9691- _ = s[0:] 9692- _ = s[1:10] 9693- _ = s[2:] // want "unneeded: len\\(s\\)" 9694- _ = s[3:(len(s))] 9695- _ = s[len(a) : len(s)-1] 9696- _ = s[0:len(b)] 9697- _ = s[2:len(s):len(s)] 9698- 9699- _ = s[:] 9700- _ = s[:10] 9701- _ = s[:] // want "unneeded: len\\(s\\)" 9702- _ = s[:(len(s))] 9703- _ = s[:len(s)-1] 9704- _ = s[:len(b)] 9705- _ = s[:len(s):len(s)] 9706- 9707- _ = t.s[0:] 9708- _ = t.s[1:10] 9709- _ = t.s[2:len(t.s)] 9710- _ = t.s[3:(len(t.s))] 9711- _ = t.s[len(a) : len(t.s)-1] 9712- _ = t.s[0:len(b)] 9713- _ = t.s[2:len(t.s):len(t.s)] 9714- 9715- _ = t.s[:] 9716- _ = t.s[:10] 9717- _ = t.s[:len(t.s)] 9718- _ = t.s[:(len(t.s))] 9719- _ = t.s[:len(t.s)-1] 9720- _ = t.s[:len(b)] 9721- _ = t.s[:len(t.s):len(t.s)] 9722-) 9723- 9724-func _() { 9725- s := s[0:] // want "unneeded: len\\(s\\)" 9726- _ = s 9727-} 9728- 9729-func m() { 9730- maps := []int{} 9731- _ = maps[1:] // want "unneeded: len\\(maps\\)" 9732-} 9733diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go 9734--- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go 2000-01-01 00:00:00.000000000 -0000 9735+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go 1970-01-01 00:00:00.000000000 +0000 9736@@ -1,39 +0,0 @@ 9737-// Copyright 2021 The Go Authors. All rights reserved. 9738-// Use of this source code is governed by a BSD-style 9739-// license that can be found in the LICENSE file. 9740-// 9741-//go:build go1.18 9742-// +build go1.18 9743- 9744-package testdata 9745- 9746-type List[E any] []E 9747- 9748-// TODO(suzmue): add a test for generic slice expressions when https://github.com/golang/go/issues/48618 is closed. 9749-// type S interface{ ~[]int } 9750- 9751-var ( 9752- a [10]byte 9753- b [20]float32 9754- p List[int] 9755- 9756- _ = p[0:] 9757- _ = p[1:10] 9758- _ = p[2:len(p)] // want "unneeded: len\\(p\\)" 9759- _ = p[3:(len(p))] 9760- _ = p[len(a) : len(p)-1] 9761- _ = p[0:len(b)] 9762- _ = p[2:len(p):len(p)] 9763- 9764- _ = p[:] 9765- _ = p[:10] 9766- _ = p[:len(p)] // want "unneeded: len\\(p\\)" 9767- _ = p[:(len(p))] 9768- _ = p[:len(p)-1] 9769- _ = p[:len(b)] 9770- _ = p[:len(p):len(p)] 9771-) 9772- 9773-func foo[E any](a List[E]) { 9774- _ = a[0:len(a)] // want "unneeded: len\\(a\\)" 9775-} 9776diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden 9777--- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden 2000-01-01 00:00:00.000000000 -0000 9778+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden 1970-01-01 00:00:00.000000000 +0000 9779@@ -1,39 +0,0 @@ 9780-// Copyright 2021 The Go Authors. All rights reserved. 9781-// Use of this source code is governed by a BSD-style 9782-// license that can be found in the LICENSE file. 9783-// 9784-//go:build go1.18 9785-// +build go1.18 9786- 9787-package testdata 9788- 9789-type List[E any] []E 9790- 9791-// TODO(suzmue): add a test for generic slice expressions when https://github.com/golang/go/issues/48618 is closed. 9792-// type S interface{ ~[]int } 9793- 9794-var ( 9795- a [10]byte 9796- b [20]float32 9797- p List[int] 9798- 9799- _ = p[0:] 9800- _ = p[1:10] 9801- _ = p[2:] // want "unneeded: len\\(p\\)" 9802- _ = p[3:(len(p))] 9803- _ = p[len(a) : len(p)-1] 9804- _ = p[0:len(b)] 9805- _ = p[2:len(p):len(p)] 9806- 9807- _ = p[:] 9808- _ = p[:10] 9809- _ = p[:] // want "unneeded: len\\(p\\)" 9810- _ = p[:(len(p))] 9811- _ = p[:len(p)-1] 9812- _ = p[:len(b)] 9813- _ = p[:len(p):len(p)] 9814-) 9815- 9816-func foo[E any](a List[E]) { 9817- _ = a[0:] // want "unneeded: len\\(a\\)" 9818-} 9819diff -urN a/gopls/internal/lsp/analysis/stubmethods/stubmethods.go b/gopls/internal/lsp/analysis/stubmethods/stubmethods.go 9820--- a/gopls/internal/lsp/analysis/stubmethods/stubmethods.go 2000-01-01 00:00:00.000000000 -0000 9821+++ b/gopls/internal/lsp/analysis/stubmethods/stubmethods.go 1970-01-01 00:00:00.000000000 +0000 9822@@ -1,418 +0,0 @@ 9823-// Copyright 2022 The Go Authors. All rights reserved. 9824-// Use of this source code is governed by a BSD-style 9825-// license that can be found in the LICENSE file. 9826- 9827-package stubmethods 9828- 9829-import ( 9830- "bytes" 9831- "fmt" 9832- "go/ast" 9833- "go/format" 9834- "go/token" 9835- "go/types" 9836- "strconv" 9837- "strings" 9838- 9839- "golang.org/x/tools/go/analysis" 9840- "golang.org/x/tools/go/analysis/passes/inspect" 9841- "golang.org/x/tools/go/ast/astutil" 9842- "golang.org/x/tools/internal/analysisinternal" 9843- "golang.org/x/tools/internal/typesinternal" 9844-) 9845- 9846-const Doc = `stub methods analyzer 9847- 9848-This analyzer generates method stubs for concrete types 9849-in order to implement a target interface` 9850- 9851-var Analyzer = &analysis.Analyzer{ 9852- Name: "stubmethods", 9853- Doc: Doc, 9854- Requires: []*analysis.Analyzer{inspect.Analyzer}, 9855- Run: run, 9856- RunDespiteErrors: true, 9857-} 9858- 9859-func run(pass *analysis.Pass) (interface{}, error) { 9860- for _, err := range pass.TypeErrors { 9861- ifaceErr := strings.Contains(err.Msg, "missing method") || strings.HasPrefix(err.Msg, "cannot convert") 9862- if !ifaceErr { 9863- continue 9864- } 9865- var file *ast.File 9866- for _, f := range pass.Files { 9867- if f.Pos() <= err.Pos && err.Pos < f.End() { 9868- file = f 9869- break 9870- } 9871- } 9872- if file == nil { 9873- continue 9874- } 9875- // Get the end position of the error. 9876- _, _, endPos, ok := typesinternal.ReadGo116ErrorData(err) 9877- if !ok { 9878- var buf bytes.Buffer 9879- if err := format.Node(&buf, pass.Fset, file); err != nil { 9880- continue 9881- } 9882- endPos = analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos) 9883- } 9884- path, _ := astutil.PathEnclosingInterval(file, err.Pos, endPos) 9885- si := GetStubInfo(pass.Fset, pass.TypesInfo, path, err.Pos) 9886- if si == nil { 9887- continue 9888- } 9889- qf := RelativeToFiles(si.Concrete.Obj().Pkg(), file, nil, nil) 9890- pass.Report(analysis.Diagnostic{ 9891- Pos: err.Pos, 9892- End: endPos, 9893- Message: fmt.Sprintf("Implement %s", types.TypeString(si.Interface.Type(), qf)), 9894- }) 9895- } 9896- return nil, nil 9897-} 9898- 9899-// StubInfo represents a concrete type 9900-// that wants to stub out an interface type 9901-type StubInfo struct { 9902- // Interface is the interface that the client wants to implement. 9903- // When the interface is defined, the underlying object will be a TypeName. 9904- // Note that we keep track of types.Object instead of types.Type in order 9905- // to keep a reference to the declaring object's package and the ast file 9906- // in the case where the concrete type file requires a new import that happens to be renamed 9907- // in the interface file. 9908- // TODO(marwan-at-work): implement interface literals. 9909- Fset *token.FileSet // the FileSet used to type-check the types below 9910- Interface *types.TypeName 9911- Concrete *types.Named 9912- Pointer bool 9913-} 9914- 9915-// GetStubInfo determines whether the "missing method error" 9916-// can be used to deduced what the concrete and interface types are. 9917-// 9918-// TODO(adonovan): this function (and its following 5 helpers) tries 9919-// to deduce a pair of (concrete, interface) types that are related by 9920-// an assignment, either explictly or through a return statement or 9921-// function call. This is essentially what the refactor/satisfy does, 9922-// more generally. Refactor to share logic, after auditing 'satisfy' 9923-// for safety on ill-typed code. 9924-func GetStubInfo(fset *token.FileSet, ti *types.Info, path []ast.Node, pos token.Pos) *StubInfo { 9925- for _, n := range path { 9926- switch n := n.(type) { 9927- case *ast.ValueSpec: 9928- return fromValueSpec(fset, ti, n, pos) 9929- case *ast.ReturnStmt: 9930- // An error here may not indicate a real error the user should know about, but it may. 9931- // Therefore, it would be best to log it out for debugging/reporting purposes instead of ignoring 9932- // it. However, event.Log takes a context which is not passed via the analysis package. 9933- // TODO(marwan-at-work): properly log this error. 9934- si, _ := fromReturnStmt(fset, ti, pos, path, n) 9935- return si 9936- case *ast.AssignStmt: 9937- return fromAssignStmt(fset, ti, n, pos) 9938- case *ast.CallExpr: 9939- // Note that some call expressions don't carry the interface type 9940- // because they don't point to a function or method declaration elsewhere. 9941- // For eaxmple, "var Interface = (*Concrete)(nil)". In that case, continue 9942- // this loop to encounter other possibilities such as *ast.ValueSpec or others. 9943- si := fromCallExpr(fset, ti, pos, n) 9944- if si != nil { 9945- return si 9946- } 9947- } 9948- } 9949- return nil 9950-} 9951- 9952-// fromCallExpr tries to find an *ast.CallExpr's function declaration and 9953-// analyzes a function call's signature against the passed in parameter to deduce 9954-// the concrete and interface types. 9955-func fromCallExpr(fset *token.FileSet, ti *types.Info, pos token.Pos, ce *ast.CallExpr) *StubInfo { 9956- paramIdx := -1 9957- for i, p := range ce.Args { 9958- if pos >= p.Pos() && pos <= p.End() { 9959- paramIdx = i 9960- break 9961- } 9962- } 9963- if paramIdx == -1 { 9964- return nil 9965- } 9966- p := ce.Args[paramIdx] 9967- concObj, pointer := concreteType(p, ti) 9968- if concObj == nil || concObj.Obj().Pkg() == nil { 9969- return nil 9970- } 9971- tv, ok := ti.Types[ce.Fun] 9972- if !ok { 9973- return nil 9974- } 9975- sig, ok := tv.Type.(*types.Signature) 9976- if !ok { 9977- return nil 9978- } 9979- sigVar := sig.Params().At(paramIdx) 9980- iface := ifaceObjFromType(sigVar.Type()) 9981- if iface == nil { 9982- return nil 9983- } 9984- return &StubInfo{ 9985- Fset: fset, 9986- Concrete: concObj, 9987- Pointer: pointer, 9988- Interface: iface, 9989- } 9990-} 9991- 9992-// fromReturnStmt analyzes a "return" statement to extract 9993-// a concrete type that is trying to be returned as an interface type. 9994-// 9995-// For example, func() io.Writer { return myType{} } 9996-// would return StubInfo with the interface being io.Writer and the concrete type being myType{}. 9997-func fromReturnStmt(fset *token.FileSet, ti *types.Info, pos token.Pos, path []ast.Node, rs *ast.ReturnStmt) (*StubInfo, error) { 9998- returnIdx := -1 9999- for i, r := range rs.Results { 10000- if pos >= r.Pos() && pos <= r.End() { 10001- returnIdx = i 10002- } 10003- } 10004- if returnIdx == -1 { 10005- return nil, fmt.Errorf("pos %d not within return statement bounds: [%d-%d]", pos, rs.Pos(), rs.End()) 10006- } 10007- concObj, pointer := concreteType(rs.Results[returnIdx], ti) 10008- if concObj == nil || concObj.Obj().Pkg() == nil { 10009- return nil, nil 10010- } 10011- ef := enclosingFunction(path, ti) 10012- if ef == nil { 10013- return nil, fmt.Errorf("could not find the enclosing function of the return statement") 10014- } 10015- iface := ifaceType(ef.Results.List[returnIdx].Type, ti) 10016- if iface == nil { 10017- return nil, nil 10018- } 10019- return &StubInfo{ 10020- Fset: fset, 10021- Concrete: concObj, 10022- Pointer: pointer, 10023- Interface: iface, 10024- }, nil 10025-} 10026- 10027-// fromValueSpec returns *StubInfo from a variable declaration such as 10028-// var x io.Writer = &T{} 10029-func fromValueSpec(fset *token.FileSet, ti *types.Info, vs *ast.ValueSpec, pos token.Pos) *StubInfo { 10030- var idx int 10031- for i, vs := range vs.Values { 10032- if pos >= vs.Pos() && pos <= vs.End() { 10033- idx = i 10034- break 10035- } 10036- } 10037- 10038- valueNode := vs.Values[idx] 10039- ifaceNode := vs.Type 10040- callExp, ok := valueNode.(*ast.CallExpr) 10041- // if the ValueSpec is `var _ = myInterface(...)` 10042- // as opposed to `var _ myInterface = ...` 10043- if ifaceNode == nil && ok && len(callExp.Args) == 1 { 10044- ifaceNode = callExp.Fun 10045- valueNode = callExp.Args[0] 10046- } 10047- concObj, pointer := concreteType(valueNode, ti) 10048- if concObj == nil || concObj.Obj().Pkg() == nil { 10049- return nil 10050- } 10051- ifaceObj := ifaceType(ifaceNode, ti) 10052- if ifaceObj == nil { 10053- return nil 10054- } 10055- return &StubInfo{ 10056- Fset: fset, 10057- Concrete: concObj, 10058- Interface: ifaceObj, 10059- Pointer: pointer, 10060- } 10061-} 10062- 10063-// fromAssignStmt returns *StubInfo from a variable re-assignment such as 10064-// var x io.Writer 10065-// x = &T{} 10066-func fromAssignStmt(fset *token.FileSet, ti *types.Info, as *ast.AssignStmt, pos token.Pos) *StubInfo { 10067- idx := -1 10068- var lhs, rhs ast.Expr 10069- // Given a re-assignment interface conversion error, 10070- // the compiler error shows up on the right hand side of the expression. 10071- // For example, x = &T{} where x is io.Writer highlights the error 10072- // under "&T{}" and not "x". 10073- for i, hs := range as.Rhs { 10074- if pos >= hs.Pos() && pos <= hs.End() { 10075- idx = i 10076- break 10077- } 10078- } 10079- if idx == -1 { 10080- return nil 10081- } 10082- // Technically, this should never happen as 10083- // we would get a "cannot assign N values to M variables" 10084- // before we get an interface conversion error. Nonetheless, 10085- // guard against out of range index errors. 10086- if idx >= len(as.Lhs) { 10087- return nil 10088- } 10089- lhs, rhs = as.Lhs[idx], as.Rhs[idx] 10090- ifaceObj := ifaceType(lhs, ti) 10091- if ifaceObj == nil { 10092- return nil 10093- } 10094- concType, pointer := concreteType(rhs, ti) 10095- if concType == nil || concType.Obj().Pkg() == nil { 10096- return nil 10097- } 10098- return &StubInfo{ 10099- Fset: fset, 10100- Concrete: concType, 10101- Interface: ifaceObj, 10102- Pointer: pointer, 10103- } 10104-} 10105- 10106-// RelativeToFiles returns a types.Qualifier that formats package 10107-// names according to the import environments of the files that define 10108-// the concrete type and the interface type. (Only the imports of the 10109-// latter file are provided.) 10110-// 10111-// This is similar to types.RelativeTo except if a file imports the package with a different name, 10112-// then it will use it. And if the file does import the package but it is ignored, 10113-// then it will return the original name. It also prefers package names in importEnv in case 10114-// an import is missing from concFile but is present among importEnv. 10115-// 10116-// Additionally, if missingImport is not nil, the function will be called whenever the concFile 10117-// is presented with a package that is not imported. This is useful so that as types.TypeString is 10118-// formatting a function signature, it is identifying packages that will need to be imported when 10119-// stubbing an interface. 10120-// 10121-// TODO(rfindley): investigate if this can be merged with source.Qualifier. 10122-func RelativeToFiles(concPkg *types.Package, concFile *ast.File, ifaceImports []*ast.ImportSpec, missingImport func(name, path string)) types.Qualifier { 10123- return func(other *types.Package) string { 10124- if other == concPkg { 10125- return "" 10126- } 10127- 10128- // Check if the concrete file already has the given import, 10129- // if so return the default package name or the renamed import statement. 10130- for _, imp := range concFile.Imports { 10131- impPath, _ := strconv.Unquote(imp.Path.Value) 10132- isIgnored := imp.Name != nil && (imp.Name.Name == "." || imp.Name.Name == "_") 10133- // TODO(adonovan): this comparison disregards a vendor prefix in 'other'. 10134- if impPath == other.Path() && !isIgnored { 10135- importName := other.Name() 10136- if imp.Name != nil { 10137- importName = imp.Name.Name 10138- } 10139- return importName 10140- } 10141- } 10142- 10143- // If the concrete file does not have the import, check if the package 10144- // is renamed in the interface file and prefer that. 10145- var importName string 10146- for _, imp := range ifaceImports { 10147- impPath, _ := strconv.Unquote(imp.Path.Value) 10148- isIgnored := imp.Name != nil && (imp.Name.Name == "." || imp.Name.Name == "_") 10149- // TODO(adonovan): this comparison disregards a vendor prefix in 'other'. 10150- if impPath == other.Path() && !isIgnored { 10151- if imp.Name != nil && imp.Name.Name != concPkg.Name() { 10152- importName = imp.Name.Name 10153- } 10154- break 10155- } 10156- } 10157- 10158- if missingImport != nil { 10159- missingImport(importName, other.Path()) 10160- } 10161- 10162- // Up until this point, importName must stay empty when calling missingImport, 10163- // otherwise we'd end up with `import time "time"` which doesn't look idiomatic. 10164- if importName == "" { 10165- importName = other.Name() 10166- } 10167- return importName 10168- } 10169-} 10170- 10171-// ifaceType will try to extract the types.Object that defines 10172-// the interface given the ast.Expr where the "missing method" 10173-// or "conversion" errors happen. 10174-func ifaceType(n ast.Expr, ti *types.Info) *types.TypeName { 10175- tv, ok := ti.Types[n] 10176- if !ok { 10177- return nil 10178- } 10179- return ifaceObjFromType(tv.Type) 10180-} 10181- 10182-func ifaceObjFromType(t types.Type) *types.TypeName { 10183- named, ok := t.(*types.Named) 10184- if !ok { 10185- return nil 10186- } 10187- _, ok = named.Underlying().(*types.Interface) 10188- if !ok { 10189- return nil 10190- } 10191- // Interfaces defined in the "builtin" package return nil a Pkg(). 10192- // But they are still real interfaces that we need to make a special case for. 10193- // Therefore, protect gopls from panicking if a new interface type was added in the future. 10194- if named.Obj().Pkg() == nil && named.Obj().Name() != "error" { 10195- return nil 10196- } 10197- return named.Obj() 10198-} 10199- 10200-// concreteType tries to extract the *types.Named that defines 10201-// the concrete type given the ast.Expr where the "missing method" 10202-// or "conversion" errors happened. If the concrete type is something 10203-// that cannot have methods defined on it (such as basic types), this 10204-// method will return a nil *types.Named. The second return parameter 10205-// is a boolean that indicates whether the concreteType was defined as a 10206-// pointer or value. 10207-func concreteType(n ast.Expr, ti *types.Info) (*types.Named, bool) { 10208- tv, ok := ti.Types[n] 10209- if !ok { 10210- return nil, false 10211- } 10212- typ := tv.Type 10213- ptr, isPtr := typ.(*types.Pointer) 10214- if isPtr { 10215- typ = ptr.Elem() 10216- } 10217- named, ok := typ.(*types.Named) 10218- if !ok { 10219- return nil, false 10220- } 10221- return named, isPtr 10222-} 10223- 10224-// enclosingFunction returns the signature and type of the function 10225-// enclosing the given position. 10226-func enclosingFunction(path []ast.Node, info *types.Info) *ast.FuncType { 10227- for _, node := range path { 10228- switch t := node.(type) { 10229- case *ast.FuncDecl: 10230- if _, ok := info.Defs[t.Name]; ok { 10231- return t.Type 10232- } 10233- case *ast.FuncLit: 10234- if _, ok := info.Types[t]; ok { 10235- return t.Type 10236- } 10237- } 10238- } 10239- return nil 10240-} 10241diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go 10242--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 10243+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 10244@@ -1,28 +0,0 @@ 10245-// Copyright 2020 The Go Authors. All rights reserved. 10246-// Use of this source code is governed by a BSD-style 10247-// license that can be found in the LICENSE file. 10248- 10249-package undeclared 10250- 10251-func x() int { 10252- var z int 10253- z = y // want "(undeclared name|undefined): y" 10254- 10255- if z == m { // want "(undeclared name|undefined): m" 10256- z = 1 10257- } 10258- 10259- if z == 1 { 10260- z = 1 10261- } else if z == n+1 { // want "(undeclared name|undefined): n" 10262- z = 1 10263- } 10264- 10265- switch z { 10266- case 10: 10267- z = 1 10268- case a: // want "(undeclared name|undefined): a" 10269- z = 1 10270- } 10271- return z 10272-} 10273diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go 10274--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go 2000-01-01 00:00:00.000000000 -0000 10275+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go 1970-01-01 00:00:00.000000000 +0000 10276@@ -1,13 +0,0 @@ 10277-// Copyright 2021 The Go Authors. All rights reserved. 10278-// Use of this source code is governed by a BSD-style 10279-// license that can be found in the LICENSE file. 10280- 10281-package undeclared 10282- 10283-func channels(s string) { 10284- undefinedChannels(c()) // want "(undeclared name|undefined): undefinedChannels" 10285-} 10286- 10287-func c() (<-chan string, chan string) { 10288- return make(<-chan string), make(chan string) 10289-} 10290diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go 10291--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go 2000-01-01 00:00:00.000000000 -0000 10292+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go 1970-01-01 00:00:00.000000000 +0000 10293@@ -1,10 +0,0 @@ 10294-// Copyright 2021 The Go Authors. All rights reserved. 10295-// Use of this source code is governed by a BSD-style 10296-// license that can be found in the LICENSE file. 10297- 10298-package undeclared 10299- 10300-func consecutiveParams() { 10301- var s string 10302- undefinedConsecutiveParams(s, s) // want "(undeclared name|undefined): undefinedConsecutiveParams" 10303-} 10304diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go 10305--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go 2000-01-01 00:00:00.000000000 -0000 10306+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go 1970-01-01 00:00:00.000000000 +0000 10307@@ -1,10 +0,0 @@ 10308-// Copyright 2021 The Go Authors. All rights reserved. 10309-// Use of this source code is governed by a BSD-style 10310-// license that can be found in the LICENSE file. 10311- 10312-package undeclared 10313- 10314-func errorParam() { 10315- var err error 10316- undefinedErrorParam(err) // want "(undeclared name|undefined): undefinedErrorParam" 10317-} 10318diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go 10319--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go 2000-01-01 00:00:00.000000000 -0000 10320+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go 1970-01-01 00:00:00.000000000 +0000 10321@@ -1,11 +0,0 @@ 10322-// Copyright 2021 The Go Authors. All rights reserved. 10323-// Use of this source code is governed by a BSD-style 10324-// license that can be found in the LICENSE file. 10325- 10326-package undeclared 10327- 10328-type T struct{} 10329- 10330-func literals() { 10331- undefinedLiterals("hey compiler", T{}, &T{}) // want "(undeclared name|undefined): undefinedLiterals" 10332-} 10333diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go 10334--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go 2000-01-01 00:00:00.000000000 -0000 10335+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go 1970-01-01 00:00:00.000000000 +0000 10336@@ -1,11 +0,0 @@ 10337-// Copyright 2021 The Go Authors. All rights reserved. 10338-// Use of this source code is governed by a BSD-style 10339-// license that can be found in the LICENSE file. 10340- 10341-package undeclared 10342- 10343-import "time" 10344- 10345-func operation() { 10346- undefinedOperation(10 * time.Second) // want "(undeclared name|undefined): undefinedOperation" 10347-} 10348diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go 10349--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go 2000-01-01 00:00:00.000000000 -0000 10350+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go 1970-01-01 00:00:00.000000000 +0000 10351@@ -1,10 +0,0 @@ 10352-// Copyright 2021 The Go Authors. All rights reserved. 10353-// Use of this source code is governed by a BSD-style 10354-// license that can be found in the LICENSE file. 10355- 10356-package undeclared 10357- 10358-func selector() { 10359- m := map[int]bool{} 10360- undefinedSelector(m[1]) // want "(undeclared name|undefined): undefinedSelector" 10361-} 10362diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go 10363--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go 2000-01-01 00:00:00.000000000 -0000 10364+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go 1970-01-01 00:00:00.000000000 +0000 10365@@ -1,9 +0,0 @@ 10366-// Copyright 2021 The Go Authors. All rights reserved. 10367-// Use of this source code is governed by a BSD-style 10368-// license that can be found in the LICENSE file. 10369- 10370-package undeclared 10371- 10372-func slice() { 10373- undefinedSlice([]int{1, 2}) // want "(undeclared name|undefined): undefinedSlice" 10374-} 10375diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go 10376--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go 2000-01-01 00:00:00.000000000 -0000 10377+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go 1970-01-01 00:00:00.000000000 +0000 10378@@ -1,13 +0,0 @@ 10379-// Copyright 2021 The Go Authors. All rights reserved. 10380-// Use of this source code is governed by a BSD-style 10381-// license that can be found in the LICENSE file. 10382- 10383-package undeclared 10384- 10385-func tuple() { 10386- undefinedTuple(b()) // want "(undeclared name|undefined): undefinedTuple" 10387-} 10388- 10389-func b() (string, error) { 10390- return "", nil 10391-} 10392diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go 10393--- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go 2000-01-01 00:00:00.000000000 -0000 10394+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go 1970-01-01 00:00:00.000000000 +0000 10395@@ -1,11 +0,0 @@ 10396-// Copyright 2021 The Go Authors. All rights reserved. 10397-// Use of this source code is governed by a BSD-style 10398-// license that can be found in the LICENSE file. 10399- 10400-package undeclared 10401- 10402-func uniqueArguments() { 10403- var s string 10404- var i int 10405- undefinedUniqueArguments(s, i, s) // want "(undeclared name|undefined): undefinedUniqueArguments" 10406-} 10407diff -urN a/gopls/internal/lsp/analysis/undeclaredname/undeclared.go b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go 10408--- a/gopls/internal/lsp/analysis/undeclaredname/undeclared.go 2000-01-01 00:00:00.000000000 -0000 10409+++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go 1970-01-01 00:00:00.000000000 +0000 10410@@ -1,347 +0,0 @@ 10411-// Copyright 2020 The Go Authors. All rights reserved. 10412-// Use of this source code is governed by a BSD-style 10413-// license that can be found in the LICENSE file. 10414- 10415-// Package undeclaredname defines an Analyzer that applies suggested fixes 10416-// to errors of the type "undeclared name: %s". 10417-package undeclaredname 10418- 10419-import ( 10420- "bytes" 10421- "fmt" 10422- "go/ast" 10423- "go/format" 10424- "go/token" 10425- "go/types" 10426- "strings" 10427- "unicode" 10428- 10429- "golang.org/x/tools/go/analysis" 10430- "golang.org/x/tools/go/ast/astutil" 10431- "golang.org/x/tools/gopls/internal/lsp/safetoken" 10432- "golang.org/x/tools/internal/analysisinternal" 10433-) 10434- 10435-const Doc = `suggested fixes for "undeclared name: <>" 10436- 10437-This checker provides suggested fixes for type errors of the 10438-type "undeclared name: <>". It will either insert a new statement, 10439-such as: 10440- 10441-"<> := " 10442- 10443-or a new function declaration, such as: 10444- 10445-func <>(inferred parameters) { 10446- panic("implement me!") 10447-} 10448-` 10449- 10450-var Analyzer = &analysis.Analyzer{ 10451- Name: "undeclaredname", 10452- Doc: Doc, 10453- Requires: []*analysis.Analyzer{}, 10454- Run: run, 10455- RunDespiteErrors: true, 10456-} 10457- 10458-// The prefix for this error message changed in Go 1.20. 10459-var undeclaredNamePrefixes = []string{"undeclared name: ", "undefined: "} 10460- 10461-func run(pass *analysis.Pass) (interface{}, error) { 10462- for _, err := range pass.TypeErrors { 10463- runForError(pass, err) 10464- } 10465- return nil, nil 10466-} 10467- 10468-func runForError(pass *analysis.Pass, err types.Error) { 10469- var name string 10470- for _, prefix := range undeclaredNamePrefixes { 10471- if !strings.HasPrefix(err.Msg, prefix) { 10472- continue 10473- } 10474- name = strings.TrimPrefix(err.Msg, prefix) 10475- } 10476- if name == "" { 10477- return 10478- } 10479- var file *ast.File 10480- for _, f := range pass.Files { 10481- if f.Pos() <= err.Pos && err.Pos < f.End() { 10482- file = f 10483- break 10484- } 10485- } 10486- if file == nil { 10487- return 10488- } 10489- 10490- // Get the path for the relevant range. 10491- path, _ := astutil.PathEnclosingInterval(file, err.Pos, err.Pos) 10492- if len(path) < 2 { 10493- return 10494- } 10495- ident, ok := path[0].(*ast.Ident) 10496- if !ok || ident.Name != name { 10497- return 10498- } 10499- 10500- // Undeclared quick fixes only work in function bodies. 10501- inFunc := false 10502- for i := range path { 10503- if _, inFunc = path[i].(*ast.FuncDecl); inFunc { 10504- if i == 0 { 10505- return 10506- } 10507- if _, isBody := path[i-1].(*ast.BlockStmt); !isBody { 10508- return 10509- } 10510- break 10511- } 10512- } 10513- if !inFunc { 10514- return 10515- } 10516- // Skip selector expressions because it might be too complex 10517- // to try and provide a suggested fix for fields and methods. 10518- if _, ok := path[1].(*ast.SelectorExpr); ok { 10519- return 10520- } 10521- tok := pass.Fset.File(file.Pos()) 10522- if tok == nil { 10523- return 10524- } 10525- offset := safetoken.StartPosition(pass.Fset, err.Pos).Offset 10526- end := tok.Pos(offset + len(name)) // TODO(adonovan): dubious! err.Pos + len(name)?? 10527- pass.Report(analysis.Diagnostic{ 10528- Pos: err.Pos, 10529- End: end, 10530- Message: err.Msg, 10531- }) 10532-} 10533- 10534-func SuggestedFix(fset *token.FileSet, start, end token.Pos, content []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) { 10535- pos := start // don't use the end 10536- path, _ := astutil.PathEnclosingInterval(file, pos, pos) 10537- if len(path) < 2 { 10538- return nil, fmt.Errorf("no expression found") 10539- } 10540- ident, ok := path[0].(*ast.Ident) 10541- if !ok { 10542- return nil, fmt.Errorf("no identifier found") 10543- } 10544- 10545- // Check for a possible call expression, in which case we should add a 10546- // new function declaration. 10547- if len(path) > 1 { 10548- if _, ok := path[1].(*ast.CallExpr); ok { 10549- return newFunctionDeclaration(path, file, pkg, info, fset) 10550- } 10551- } 10552- 10553- // Get the place to insert the new statement. 10554- insertBeforeStmt := analysisinternal.StmtToInsertVarBefore(path) 10555- if insertBeforeStmt == nil { 10556- return nil, fmt.Errorf("could not locate insertion point") 10557- } 10558- 10559- insertBefore := safetoken.StartPosition(fset, insertBeforeStmt.Pos()).Offset 10560- 10561- // Get the indent to add on the line after the new statement. 10562- // Since this will have a parse error, we can not use format.Source(). 10563- contentBeforeStmt, indent := content[:insertBefore], "\n" 10564- if nl := bytes.LastIndex(contentBeforeStmt, []byte("\n")); nl != -1 { 10565- indent = string(contentBeforeStmt[nl:]) 10566- } 10567- 10568- // Create the new local variable statement. 10569- newStmt := fmt.Sprintf("%s := %s", ident.Name, indent) 10570- return &analysis.SuggestedFix{ 10571- Message: fmt.Sprintf("Create variable \"%s\"", ident.Name), 10572- TextEdits: []analysis.TextEdit{{ 10573- Pos: insertBeforeStmt.Pos(), 10574- End: insertBeforeStmt.Pos(), 10575- NewText: []byte(newStmt), 10576- }}, 10577- }, nil 10578-} 10579- 10580-func newFunctionDeclaration(path []ast.Node, file *ast.File, pkg *types.Package, info *types.Info, fset *token.FileSet) (*analysis.SuggestedFix, error) { 10581- if len(path) < 3 { 10582- return nil, fmt.Errorf("unexpected set of enclosing nodes: %v", path) 10583- } 10584- ident, ok := path[0].(*ast.Ident) 10585- if !ok { 10586- return nil, fmt.Errorf("no name for function declaration %v (%T)", path[0], path[0]) 10587- } 10588- call, ok := path[1].(*ast.CallExpr) 10589- if !ok { 10590- return nil, fmt.Errorf("no call expression found %v (%T)", path[1], path[1]) 10591- } 10592- 10593- // Find the enclosing function, so that we can add the new declaration 10594- // below. 10595- var enclosing *ast.FuncDecl 10596- for _, n := range path { 10597- if n, ok := n.(*ast.FuncDecl); ok { 10598- enclosing = n 10599- break 10600- } 10601- } 10602- // TODO(rstambler): Support the situation when there is no enclosing 10603- // function. 10604- if enclosing == nil { 10605- return nil, fmt.Errorf("no enclosing function found: %v", path) 10606- } 10607- 10608- pos := enclosing.End() 10609- 10610- var paramNames []string 10611- var paramTypes []types.Type 10612- // keep track of all param names to later ensure uniqueness 10613- nameCounts := map[string]int{} 10614- for _, arg := range call.Args { 10615- typ := info.TypeOf(arg) 10616- if typ == nil { 10617- return nil, fmt.Errorf("unable to determine type for %s", arg) 10618- } 10619- 10620- switch t := typ.(type) { 10621- // this is the case where another function call returning multiple 10622- // results is used as an argument 10623- case *types.Tuple: 10624- n := t.Len() 10625- for i := 0; i < n; i++ { 10626- name := typeToArgName(t.At(i).Type()) 10627- nameCounts[name]++ 10628- 10629- paramNames = append(paramNames, name) 10630- paramTypes = append(paramTypes, types.Default(t.At(i).Type())) 10631- } 10632- 10633- default: 10634- // does the argument have a name we can reuse? 10635- // only happens in case of a *ast.Ident 10636- var name string 10637- if ident, ok := arg.(*ast.Ident); ok { 10638- name = ident.Name 10639- } 10640- 10641- if name == "" { 10642- name = typeToArgName(typ) 10643- } 10644- 10645- nameCounts[name]++ 10646- 10647- paramNames = append(paramNames, name) 10648- paramTypes = append(paramTypes, types.Default(typ)) 10649- } 10650- } 10651- 10652- for n, c := range nameCounts { 10653- // Any names we saw more than once will need a unique suffix added 10654- // on. Reset the count to 1 to act as the suffix for the first 10655- // occurrence of that name. 10656- if c >= 2 { 10657- nameCounts[n] = 1 10658- } else { 10659- delete(nameCounts, n) 10660- } 10661- } 10662- 10663- params := &ast.FieldList{} 10664- 10665- for i, name := range paramNames { 10666- if suffix, repeats := nameCounts[name]; repeats { 10667- nameCounts[name]++ 10668- name = fmt.Sprintf("%s%d", name, suffix) 10669- } 10670- 10671- // only worth checking after previous param in the list 10672- if i > 0 { 10673- // if type of parameter at hand is the same as the previous one, 10674- // add it to the previous param list of identifiers so to have: 10675- // (s1, s2 string) 10676- // and not 10677- // (s1 string, s2 string) 10678- if paramTypes[i] == paramTypes[i-1] { 10679- params.List[len(params.List)-1].Names = append(params.List[len(params.List)-1].Names, ast.NewIdent(name)) 10680- continue 10681- } 10682- } 10683- 10684- params.List = append(params.List, &ast.Field{ 10685- Names: []*ast.Ident{ 10686- ast.NewIdent(name), 10687- }, 10688- Type: analysisinternal.TypeExpr(file, pkg, paramTypes[i]), 10689- }) 10690- } 10691- 10692- decl := &ast.FuncDecl{ 10693- Name: ast.NewIdent(ident.Name), 10694- Type: &ast.FuncType{ 10695- Params: params, 10696- // TODO(rstambler): Also handle result parameters here. 10697- }, 10698- Body: &ast.BlockStmt{ 10699- List: []ast.Stmt{ 10700- &ast.ExprStmt{ 10701- X: &ast.CallExpr{ 10702- Fun: ast.NewIdent("panic"), 10703- Args: []ast.Expr{ 10704- &ast.BasicLit{ 10705- Value: `"unimplemented"`, 10706- }, 10707- }, 10708- }, 10709- }, 10710- }, 10711- }, 10712- } 10713- 10714- b := bytes.NewBufferString("\n\n") 10715- if err := format.Node(b, fset, decl); err != nil { 10716- return nil, err 10717- } 10718- return &analysis.SuggestedFix{ 10719- Message: fmt.Sprintf("Create function \"%s\"", ident.Name), 10720- TextEdits: []analysis.TextEdit{{ 10721- Pos: pos, 10722- End: pos, 10723- NewText: b.Bytes(), 10724- }}, 10725- }, nil 10726-} 10727-func typeToArgName(ty types.Type) string { 10728- s := types.Default(ty).String() 10729- 10730- switch t := ty.(type) { 10731- case *types.Basic: 10732- // use first letter in type name for basic types 10733- return s[0:1] 10734- case *types.Slice: 10735- // use element type to decide var name for slices 10736- return typeToArgName(t.Elem()) 10737- case *types.Array: 10738- // use element type to decide var name for arrays 10739- return typeToArgName(t.Elem()) 10740- case *types.Chan: 10741- return "ch" 10742- } 10743- 10744- s = strings.TrimFunc(s, func(r rune) bool { 10745- return !unicode.IsLetter(r) 10746- }) 10747- 10748- if s == "error" { 10749- return "err" 10750- } 10751- 10752- // remove package (if present) 10753- // and make first letter lowercase 10754- a := []rune(s[strings.LastIndexByte(s, '.')+1:]) 10755- a[0] = unicode.ToLower(a[0]) 10756- return string(a) 10757-} 10758diff -urN a/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go b/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go 10759--- a/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go 2000-01-01 00:00:00.000000000 -0000 10760+++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go 1970-01-01 00:00:00.000000000 +0000 10761@@ -1,17 +0,0 @@ 10762-// Copyright 2020 The Go Authors. All rights reserved. 10763-// Use of this source code is governed by a BSD-style 10764-// license that can be found in the LICENSE file. 10765- 10766-package undeclaredname_test 10767- 10768-import ( 10769- "testing" 10770- 10771- "golang.org/x/tools/go/analysis/analysistest" 10772- "golang.org/x/tools/gopls/internal/lsp/analysis/undeclaredname" 10773-) 10774- 10775-func Test(t *testing.T) { 10776- testdata := analysistest.TestData() 10777- analysistest.Run(t, testdata, undeclaredname.Analyzer, "a") 10778-} 10779diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go 10780--- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 10781+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 10782@@ -1,55 +0,0 @@ 10783-// Copyright 2022 The Go Authors. All rights reserved. 10784-// Use of this source code is governed by a BSD-style 10785-// license that can be found in the LICENSE file. 10786- 10787-package a 10788- 10789-import ( 10790- "bytes" 10791- "fmt" 10792- "net/http" 10793-) 10794- 10795-type parent interface { 10796- n(f bool) 10797-} 10798- 10799-type yuh struct { 10800- a int 10801-} 10802- 10803-func (y *yuh) n(f bool) { 10804- for i := 0; i < 10; i++ { 10805- fmt.Println(i) 10806- } 10807-} 10808- 10809-func a(i1 int, i2 int, i3 int) int { // want "potentially unused parameter: 'i2'" 10810- i3 += i1 10811- _ = func(z int) int { // want "potentially unused parameter: 'z'" 10812- _ = 1 10813- return 1 10814- } 10815- return i3 10816-} 10817- 10818-func b(c bytes.Buffer) { // want "potentially unused parameter: 'c'" 10819- _ = 1 10820-} 10821- 10822-func z(h http.ResponseWriter, _ *http.Request) { // want "potentially unused parameter: 'h'" 10823- fmt.Println("Before") 10824-} 10825- 10826-func l(h http.Handler) http.Handler { 10827- return http.HandlerFunc(z) 10828-} 10829- 10830-func mult(a, b int) int { // want "potentially unused parameter: 'b'" 10831- a += 1 10832- return a 10833-} 10834- 10835-func y(a int) { 10836- panic("yo") 10837-} 10838diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden 10839--- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 10840+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 10841@@ -1,55 +0,0 @@ 10842-// Copyright 2022 The Go Authors. All rights reserved. 10843-// Use of this source code is governed by a BSD-style 10844-// license that can be found in the LICENSE file. 10845- 10846-package a 10847- 10848-import ( 10849- "bytes" 10850- "fmt" 10851- "net/http" 10852-) 10853- 10854-type parent interface { 10855- n(f bool) 10856-} 10857- 10858-type yuh struct { 10859- a int 10860-} 10861- 10862-func (y *yuh) n(f bool) { 10863- for i := 0; i < 10; i++ { 10864- fmt.Println(i) 10865- } 10866-} 10867- 10868-func a(i1 int, _ int, i3 int) int { // want "potentially unused parameter: 'i2'" 10869- i3 += i1 10870- _ = func(_ int) int { // want "potentially unused parameter: 'z'" 10871- _ = 1 10872- return 1 10873- } 10874- return i3 10875-} 10876- 10877-func b(_ bytes.Buffer) { // want "potentially unused parameter: 'c'" 10878- _ = 1 10879-} 10880- 10881-func z(_ http.ResponseWriter, _ *http.Request) { // want "potentially unused parameter: 'h'" 10882- fmt.Println("Before") 10883-} 10884- 10885-func l(h http.Handler) http.Handler { 10886- return http.HandlerFunc(z) 10887-} 10888- 10889-func mult(a, _ int) int { // want "potentially unused parameter: 'b'" 10890- a += 1 10891- return a 10892-} 10893- 10894-func y(a int) { 10895- panic("yo") 10896-} 10897diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go 10898--- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go 2000-01-01 00:00:00.000000000 -0000 10899+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go 1970-01-01 00:00:00.000000000 +0000 10900@@ -1,55 +0,0 @@ 10901-// Copyright 2022 The Go Authors. All rights reserved. 10902-// Use of this source code is governed by a BSD-style 10903-// license that can be found in the LICENSE file. 10904- 10905-package typeparams 10906- 10907-import ( 10908- "bytes" 10909- "fmt" 10910- "net/http" 10911-) 10912- 10913-type parent[T any] interface { 10914- n(f T) 10915-} 10916- 10917-type yuh[T any] struct { 10918- a T 10919-} 10920- 10921-func (y *yuh[int]) n(f bool) { 10922- for i := 0; i < 10; i++ { 10923- fmt.Println(i) 10924- } 10925-} 10926- 10927-func a[T comparable](i1 int, i2 T, i3 int) int { // want "potentially unused parameter: 'i2'" 10928- i3 += i1 10929- _ = func(z int) int { // want "potentially unused parameter: 'z'" 10930- _ = 1 10931- return 1 10932- } 10933- return i3 10934-} 10935- 10936-func b[T any](c bytes.Buffer) { // want "potentially unused parameter: 'c'" 10937- _ = 1 10938-} 10939- 10940-func z[T http.ResponseWriter](h T, _ *http.Request) { // want "potentially unused parameter: 'h'" 10941- fmt.Println("Before") 10942-} 10943- 10944-func l(h http.Handler) http.Handler { 10945- return http.HandlerFunc(z[http.ResponseWriter]) 10946-} 10947- 10948-func mult(a, b int) int { // want "potentially unused parameter: 'b'" 10949- a += 1 10950- return a 10951-} 10952- 10953-func y[T any](a T) { 10954- panic("yo") 10955-} 10956diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden 10957--- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden 2000-01-01 00:00:00.000000000 -0000 10958+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden 1970-01-01 00:00:00.000000000 +0000 10959@@ -1,55 +0,0 @@ 10960-// Copyright 2022 The Go Authors. All rights reserved. 10961-// Use of this source code is governed by a BSD-style 10962-// license that can be found in the LICENSE file. 10963- 10964-package typeparams 10965- 10966-import ( 10967- "bytes" 10968- "fmt" 10969- "net/http" 10970-) 10971- 10972-type parent[T any] interface { 10973- n(f T) 10974-} 10975- 10976-type yuh[T any] struct { 10977- a T 10978-} 10979- 10980-func (y *yuh[int]) n(f bool) { 10981- for i := 0; i < 10; i++ { 10982- fmt.Println(i) 10983- } 10984-} 10985- 10986-func a[T comparable](i1 int, _ T, i3 int) int { // want "potentially unused parameter: 'i2'" 10987- i3 += i1 10988- _ = func(_ int) int { // want "potentially unused parameter: 'z'" 10989- _ = 1 10990- return 1 10991- } 10992- return i3 10993-} 10994- 10995-func b[T any](_ bytes.Buffer) { // want "potentially unused parameter: 'c'" 10996- _ = 1 10997-} 10998- 10999-func z[T http.ResponseWriter](_ T, _ *http.Request) { // want "potentially unused parameter: 'h'" 11000- fmt.Println("Before") 11001-} 11002- 11003-func l(h http.Handler) http.Handler { 11004- return http.HandlerFunc(z[http.ResponseWriter]) 11005-} 11006- 11007-func mult(a, _ int) int { // want "potentially unused parameter: 'b'" 11008- a += 1 11009- return a 11010-} 11011- 11012-func y[T any](a T) { 11013- panic("yo") 11014-} 11015diff -urN a/gopls/internal/lsp/analysis/unusedparams/unusedparams.go b/gopls/internal/lsp/analysis/unusedparams/unusedparams.go 11016--- a/gopls/internal/lsp/analysis/unusedparams/unusedparams.go 2000-01-01 00:00:00.000000000 -0000 11017+++ b/gopls/internal/lsp/analysis/unusedparams/unusedparams.go 1970-01-01 00:00:00.000000000 +0000 11018@@ -1,152 +0,0 @@ 11019-// Copyright 2020 The Go Authors. All rights reserved. 11020-// Use of this source code is governed by a BSD-style 11021-// license that can be found in the LICENSE file. 11022- 11023-// Package unusedparams defines an analyzer that checks for unused 11024-// parameters of functions. 11025-package unusedparams 11026- 11027-import ( 11028- "fmt" 11029- "go/ast" 11030- "go/types" 11031- "strings" 11032- 11033- "golang.org/x/tools/go/analysis" 11034- "golang.org/x/tools/go/analysis/passes/inspect" 11035- "golang.org/x/tools/go/ast/inspector" 11036-) 11037- 11038-const Doc = `check for unused parameters of functions 11039- 11040-The unusedparams analyzer checks functions to see if there are 11041-any parameters that are not being used. 11042- 11043-To reduce false positives it ignores: 11044-- methods 11045-- parameters that do not have a name or are underscored 11046-- functions in test files 11047-- functions with empty bodies or those with just a return stmt` 11048- 11049-var Analyzer = &analysis.Analyzer{ 11050- Name: "unusedparams", 11051- Doc: Doc, 11052- Requires: []*analysis.Analyzer{inspect.Analyzer}, 11053- Run: run, 11054-} 11055- 11056-type paramData struct { 11057- field *ast.Field 11058- ident *ast.Ident 11059- typObj types.Object 11060-} 11061- 11062-func run(pass *analysis.Pass) (interface{}, error) { 11063- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 11064- nodeFilter := []ast.Node{ 11065- (*ast.FuncDecl)(nil), 11066- (*ast.FuncLit)(nil), 11067- } 11068- 11069- inspect.Preorder(nodeFilter, func(n ast.Node) { 11070- var fieldList *ast.FieldList 11071- var body *ast.BlockStmt 11072- 11073- // Get the fieldList and body from the function node. 11074- switch f := n.(type) { 11075- case *ast.FuncDecl: 11076- fieldList, body = f.Type.Params, f.Body 11077- // TODO(golang/go#36602): add better handling for methods, if we enable methods 11078- // we will get false positives if a struct is potentially implementing 11079- // an interface. 11080- if f.Recv != nil { 11081- return 11082- } 11083- // Ignore functions in _test.go files to reduce false positives. 11084- if file := pass.Fset.File(n.Pos()); file != nil && strings.HasSuffix(file.Name(), "_test.go") { 11085- return 11086- } 11087- case *ast.FuncLit: 11088- fieldList, body = f.Type.Params, f.Body 11089- } 11090- // If there are no arguments or the function is empty, then return. 11091- if fieldList.NumFields() == 0 || body == nil || len(body.List) == 0 { 11092- return 11093- } 11094- 11095- switch expr := body.List[0].(type) { 11096- case *ast.ReturnStmt: 11097- // Ignore functions that only contain a return statement to reduce false positives. 11098- return 11099- case *ast.ExprStmt: 11100- callExpr, ok := expr.X.(*ast.CallExpr) 11101- if !ok || len(body.List) > 1 { 11102- break 11103- } 11104- // Ignore functions that only contain a panic statement to reduce false positives. 11105- if fun, ok := callExpr.Fun.(*ast.Ident); ok && fun.Name == "panic" { 11106- return 11107- } 11108- } 11109- 11110- // Get the useful data from each field. 11111- params := make(map[string]*paramData) 11112- unused := make(map[*paramData]bool) 11113- for _, f := range fieldList.List { 11114- for _, i := range f.Names { 11115- if i.Name == "_" { 11116- continue 11117- } 11118- params[i.Name] = ¶mData{ 11119- field: f, 11120- ident: i, 11121- typObj: pass.TypesInfo.ObjectOf(i), 11122- } 11123- unused[params[i.Name]] = true 11124- } 11125- } 11126- 11127- // Traverse through the body of the function and 11128- // check to see which parameters are unused. 11129- ast.Inspect(body, func(node ast.Node) bool { 11130- n, ok := node.(*ast.Ident) 11131- if !ok { 11132- return true 11133- } 11134- param, ok := params[n.Name] 11135- if !ok { 11136- return false 11137- } 11138- if nObj := pass.TypesInfo.ObjectOf(n); nObj != param.typObj { 11139- return false 11140- } 11141- delete(unused, param) 11142- return false 11143- }) 11144- 11145- // Create the reports for the unused parameters. 11146- for u := range unused { 11147- start, end := u.field.Pos(), u.field.End() 11148- if len(u.field.Names) > 1 { 11149- start, end = u.ident.Pos(), u.ident.End() 11150- } 11151- // TODO(golang/go#36602): Add suggested fixes to automatically 11152- // remove the unused parameter from every use of this 11153- // function. 11154- pass.Report(analysis.Diagnostic{ 11155- Pos: start, 11156- End: end, 11157- Message: fmt.Sprintf("potentially unused parameter: '%s'", u.ident.Name), 11158- SuggestedFixes: []analysis.SuggestedFix{{ 11159- Message: `Replace with "_"`, 11160- TextEdits: []analysis.TextEdit{{ 11161- Pos: u.ident.Pos(), 11162- End: u.ident.End(), 11163- NewText: []byte("_"), 11164- }}, 11165- }}, 11166- }) 11167- } 11168- }) 11169- return nil, nil 11170-} 11171diff -urN a/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go b/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go 11172--- a/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go 2000-01-01 00:00:00.000000000 -0000 11173+++ b/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go 1970-01-01 00:00:00.000000000 +0000 11174@@ -1,22 +0,0 @@ 11175-// Copyright 2020 The Go Authors. All rights reserved. 11176-// Use of this source code is governed by a BSD-style 11177-// license that can be found in the LICENSE file. 11178- 11179-package unusedparams_test 11180- 11181-import ( 11182- "testing" 11183- 11184- "golang.org/x/tools/go/analysis/analysistest" 11185- "golang.org/x/tools/gopls/internal/lsp/analysis/unusedparams" 11186- "golang.org/x/tools/internal/typeparams" 11187-) 11188- 11189-func Test(t *testing.T) { 11190- testdata := analysistest.TestData() 11191- tests := []string{"a"} 11192- if typeparams.Enabled { 11193- tests = append(tests, "typeparams") 11194- } 11195- analysistest.RunWithSuggestedFixes(t, testdata, unusedparams.Analyzer, tests...) 11196-} 11197diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go 11198--- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go 2000-01-01 00:00:00.000000000 -0000 11199+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go 1970-01-01 00:00:00.000000000 +0000 11200@@ -1,74 +0,0 @@ 11201-// Copyright 2022 The Go Authors. All rights reserved. 11202-// Use of this source code is governed by a BSD-style 11203-// license that can be found in the LICENSE file. 11204- 11205-package a 11206- 11207-import ( 11208- "fmt" 11209- "os" 11210-) 11211- 11212-type A struct { 11213- b int 11214-} 11215- 11216-func singleAssignment() { 11217- v := "s" // want `v declared (and|but) not used` 11218- 11219- s := []int{ // want `s declared (and|but) not used` 11220- 1, 11221- 2, 11222- } 11223- 11224- a := func(s string) bool { // want `a declared (and|but) not used` 11225- return false 11226- } 11227- 11228- if 1 == 1 { 11229- s := "v" // want `s declared (and|but) not used` 11230- } 11231- 11232- panic("I should survive") 11233-} 11234- 11235-func noOtherStmtsInBlock() { 11236- v := "s" // want `v declared (and|but) not used` 11237-} 11238- 11239-func partOfMultiAssignment() { 11240- f, err := os.Open("file") // want `f declared (and|but) not used` 11241- panic(err) 11242-} 11243- 11244-func sideEffects(cBool chan bool, cInt chan int) { 11245- b := <-c // want `b declared (and|but) not used` 11246- s := fmt.Sprint("") // want `s declared (and|but) not used` 11247- a := A{ // want `a declared (and|but) not used` 11248- b: func() int { 11249- return 1 11250- }(), 11251- } 11252- c := A{<-cInt} // want `c declared (and|but) not used` 11253- d := fInt() + <-cInt // want `d declared (and|but) not used` 11254- e := fBool() && <-cBool // want `e declared (and|but) not used` 11255- f := map[int]int{ // want `f declared (and|but) not used` 11256- fInt(): <-cInt, 11257- } 11258- g := []int{<-cInt} // want `g declared (and|but) not used` 11259- h := func(s string) {} // want `h declared (and|but) not used` 11260- i := func(s string) {}() // want `i declared (and|but) not used` 11261-} 11262- 11263-func commentAbove() { 11264- // v is a variable 11265- v := "s" // want `v declared (and|but) not used` 11266-} 11267- 11268-func fBool() bool { 11269- return true 11270-} 11271- 11272-func fInt() int { 11273- return 1 11274-} 11275diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden 11276--- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden 2000-01-01 00:00:00.000000000 -0000 11277+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden 1970-01-01 00:00:00.000000000 +0000 11278@@ -1,59 +0,0 @@ 11279-// Copyright 2022 The Go Authors. All rights reserved. 11280-// Use of this source code is governed by a BSD-style 11281-// license that can be found in the LICENSE file. 11282- 11283-package a 11284- 11285-import ( 11286- "fmt" 11287- "os" 11288-) 11289- 11290-type A struct { 11291- b int 11292-} 11293- 11294-func singleAssignment() { 11295- if 1 == 1 { 11296- } 11297- 11298- panic("I should survive") 11299-} 11300- 11301-func noOtherStmtsInBlock() { 11302-} 11303- 11304-func partOfMultiAssignment() { 11305- _, err := os.Open("file") // want `f declared (and|but) not used` 11306- panic(err) 11307-} 11308- 11309-func sideEffects(cBool chan bool, cInt chan int) { 11310- <-c // want `b declared (and|but) not used` 11311- fmt.Sprint("") // want `s declared (and|but) not used` 11312- A{ // want `a declared (and|but) not used` 11313- b: func() int { 11314- return 1 11315- }(), 11316- } 11317- A{<-cInt} // want `c declared (and|but) not used` 11318- fInt() + <-cInt // want `d declared (and|but) not used` 11319- fBool() && <-cBool // want `e declared (and|but) not used` 11320- map[int]int{ // want `f declared (and|but) not used` 11321- fInt(): <-cInt, 11322- } 11323- []int{<-cInt} // want `g declared (and|but) not used` 11324- func(s string) {}() // want `i declared (and|but) not used` 11325-} 11326- 11327-func commentAbove() { 11328- // v is a variable 11329-} 11330- 11331-func fBool() bool { 11332- return true 11333-} 11334- 11335-func fInt() int { 11336- return 1 11337-} 11338diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go 11339--- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go 2000-01-01 00:00:00.000000000 -0000 11340+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go 1970-01-01 00:00:00.000000000 +0000 11341@@ -1,30 +0,0 @@ 11342-// Copyright 2022 The Go Authors. All rights reserved. 11343-// Use of this source code is governed by a BSD-style 11344-// license that can be found in the LICENSE file. 11345- 11346-package decl 11347- 11348-func a() { 11349- var b, c bool // want `b declared (and|but) not used` 11350- panic(c) 11351- 11352- if 1 == 1 { 11353- var s string // want `s declared (and|but) not used` 11354- } 11355-} 11356- 11357-func b() { 11358- // b is a variable 11359- var b bool // want `b declared (and|but) not used` 11360-} 11361- 11362-func c() { 11363- var ( 11364- d string 11365- 11366- // some comment for c 11367- c bool // want `c declared (and|but) not used` 11368- ) 11369- 11370- panic(d) 11371-} 11372diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden 11373--- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden 2000-01-01 00:00:00.000000000 -0000 11374+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden 1970-01-01 00:00:00.000000000 +0000 11375@@ -1,24 +0,0 @@ 11376-// Copyright 2022 The Go Authors. All rights reserved. 11377-// Use of this source code is governed by a BSD-style 11378-// license that can be found in the LICENSE file. 11379- 11380-package decl 11381- 11382-func a() { 11383- var c bool // want `b declared (and|but) not used` 11384- panic(c) 11385- 11386- if 1 == 1 { 11387- } 11388-} 11389- 11390-func b() { 11391- // b is a variable 11392-} 11393- 11394-func c() { 11395- var ( 11396- d string 11397- ) 11398- panic(d) 11399-} 11400diff -urN a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go 11401--- a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go 2000-01-01 00:00:00.000000000 -0000 11402+++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go 1970-01-01 00:00:00.000000000 +0000 11403@@ -1,300 +0,0 @@ 11404-// Copyright 2020 The Go Authors. All rights reserved. 11405-// Use of this source code is governed by a BSD-style 11406-// license that can be found in the LICENSE file. 11407- 11408-// Package unusedvariable defines an analyzer that checks for unused variables. 11409-package unusedvariable 11410- 11411-import ( 11412- "bytes" 11413- "fmt" 11414- "go/ast" 11415- "go/format" 11416- "go/token" 11417- "go/types" 11418- "strings" 11419- 11420- "golang.org/x/tools/go/analysis" 11421- "golang.org/x/tools/go/ast/astutil" 11422-) 11423- 11424-const Doc = `check for unused variables 11425- 11426-The unusedvariable analyzer suggests fixes for unused variables errors. 11427-` 11428- 11429-var Analyzer = &analysis.Analyzer{ 11430- Name: "unusedvariable", 11431- Doc: Doc, 11432- Requires: []*analysis.Analyzer{}, 11433- Run: run, 11434- RunDespiteErrors: true, // an unusedvariable diagnostic is a compile error 11435-} 11436- 11437-// The suffix for this error message changed in Go 1.20. 11438-var unusedVariableSuffixes = []string{" declared and not used", " declared but not used"} 11439- 11440-func run(pass *analysis.Pass) (interface{}, error) { 11441- for _, typeErr := range pass.TypeErrors { 11442- for _, suffix := range unusedVariableSuffixes { 11443- if strings.HasSuffix(typeErr.Msg, suffix) { 11444- varName := strings.TrimSuffix(typeErr.Msg, suffix) 11445- err := runForError(pass, typeErr, varName) 11446- if err != nil { 11447- return nil, err 11448- } 11449- } 11450- } 11451- } 11452- 11453- return nil, nil 11454-} 11455- 11456-func runForError(pass *analysis.Pass, err types.Error, name string) error { 11457- var file *ast.File 11458- for _, f := range pass.Files { 11459- if f.Pos() <= err.Pos && err.Pos < f.End() { 11460- file = f 11461- break 11462- } 11463- } 11464- if file == nil { 11465- return nil 11466- } 11467- 11468- path, _ := astutil.PathEnclosingInterval(file, err.Pos, err.Pos) 11469- if len(path) < 2 { 11470- return nil 11471- } 11472- 11473- ident, ok := path[0].(*ast.Ident) 11474- if !ok || ident.Name != name { 11475- return nil 11476- } 11477- 11478- diag := analysis.Diagnostic{ 11479- Pos: ident.Pos(), 11480- End: ident.End(), 11481- Message: err.Msg, 11482- } 11483- 11484- for i := range path { 11485- switch stmt := path[i].(type) { 11486- case *ast.ValueSpec: 11487- // Find GenDecl to which offending ValueSpec belongs. 11488- if decl, ok := path[i+1].(*ast.GenDecl); ok { 11489- fixes := removeVariableFromSpec(pass, path, stmt, decl, ident) 11490- // fixes may be nil 11491- if len(fixes) > 0 { 11492- diag.SuggestedFixes = fixes 11493- pass.Report(diag) 11494- } 11495- } 11496- 11497- case *ast.AssignStmt: 11498- if stmt.Tok != token.DEFINE { 11499- continue 11500- } 11501- 11502- containsIdent := false 11503- for _, expr := range stmt.Lhs { 11504- if expr == ident { 11505- containsIdent = true 11506- } 11507- } 11508- if !containsIdent { 11509- continue 11510- } 11511- 11512- fixes := removeVariableFromAssignment(pass, path, stmt, ident) 11513- // fixes may be nil 11514- if len(fixes) > 0 { 11515- diag.SuggestedFixes = fixes 11516- pass.Report(diag) 11517- } 11518- } 11519- } 11520- 11521- return nil 11522-} 11523- 11524-func removeVariableFromSpec(pass *analysis.Pass, path []ast.Node, stmt *ast.ValueSpec, decl *ast.GenDecl, ident *ast.Ident) []analysis.SuggestedFix { 11525- newDecl := new(ast.GenDecl) 11526- *newDecl = *decl 11527- newDecl.Specs = nil 11528- 11529- for _, spec := range decl.Specs { 11530- if spec != stmt { 11531- newDecl.Specs = append(newDecl.Specs, spec) 11532- continue 11533- } 11534- 11535- newSpec := new(ast.ValueSpec) 11536- *newSpec = *stmt 11537- newSpec.Names = nil 11538- 11539- for _, n := range stmt.Names { 11540- if n != ident { 11541- newSpec.Names = append(newSpec.Names, n) 11542- } 11543- } 11544- 11545- if len(newSpec.Names) > 0 { 11546- newDecl.Specs = append(newDecl.Specs, newSpec) 11547- } 11548- } 11549- 11550- // decl.End() does not include any comments, so if a comment is present we 11551- // need to account for it when we delete the statement 11552- end := decl.End() 11553- if stmt.Comment != nil && stmt.Comment.End() > end { 11554- end = stmt.Comment.End() 11555- } 11556- 11557- // There are no other specs left in the declaration, the whole statement can 11558- // be deleted 11559- if len(newDecl.Specs) == 0 { 11560- // Find parent DeclStmt and delete it 11561- for _, node := range path { 11562- if declStmt, ok := node.(*ast.DeclStmt); ok { 11563- return []analysis.SuggestedFix{ 11564- { 11565- Message: suggestedFixMessage(ident.Name), 11566- TextEdits: deleteStmtFromBlock(path, declStmt), 11567- }, 11568- } 11569- } 11570- } 11571- } 11572- 11573- var b bytes.Buffer 11574- if err := format.Node(&b, pass.Fset, newDecl); err != nil { 11575- return nil 11576- } 11577- 11578- return []analysis.SuggestedFix{ 11579- { 11580- Message: suggestedFixMessage(ident.Name), 11581- TextEdits: []analysis.TextEdit{ 11582- { 11583- Pos: decl.Pos(), 11584- // Avoid adding a new empty line 11585- End: end + 1, 11586- NewText: b.Bytes(), 11587- }, 11588- }, 11589- }, 11590- } 11591-} 11592- 11593-func removeVariableFromAssignment(pass *analysis.Pass, path []ast.Node, stmt *ast.AssignStmt, ident *ast.Ident) []analysis.SuggestedFix { 11594- // The only variable in the assignment is unused 11595- if len(stmt.Lhs) == 1 { 11596- // If LHS has only one expression to be valid it has to have 1 expression 11597- // on RHS 11598- // 11599- // RHS may have side effects, preserve RHS 11600- if exprMayHaveSideEffects(stmt.Rhs[0]) { 11601- // Delete until RHS 11602- return []analysis.SuggestedFix{ 11603- { 11604- Message: suggestedFixMessage(ident.Name), 11605- TextEdits: []analysis.TextEdit{ 11606- { 11607- Pos: ident.Pos(), 11608- End: stmt.Rhs[0].Pos(), 11609- }, 11610- }, 11611- }, 11612- } 11613- } 11614- 11615- // RHS does not have any side effects, delete the whole statement 11616- return []analysis.SuggestedFix{ 11617- { 11618- Message: suggestedFixMessage(ident.Name), 11619- TextEdits: deleteStmtFromBlock(path, stmt), 11620- }, 11621- } 11622- } 11623- 11624- // Otherwise replace ident with `_` 11625- return []analysis.SuggestedFix{ 11626- { 11627- Message: suggestedFixMessage(ident.Name), 11628- TextEdits: []analysis.TextEdit{ 11629- { 11630- Pos: ident.Pos(), 11631- End: ident.End(), 11632- NewText: []byte("_"), 11633- }, 11634- }, 11635- }, 11636- } 11637-} 11638- 11639-func suggestedFixMessage(name string) string { 11640- return fmt.Sprintf("Remove variable %s", name) 11641-} 11642- 11643-func deleteStmtFromBlock(path []ast.Node, stmt ast.Stmt) []analysis.TextEdit { 11644- // Find innermost enclosing BlockStmt. 11645- var block *ast.BlockStmt 11646- for i := range path { 11647- if blockStmt, ok := path[i].(*ast.BlockStmt); ok { 11648- block = blockStmt 11649- break 11650- } 11651- } 11652- 11653- nodeIndex := -1 11654- for i, blockStmt := range block.List { 11655- if blockStmt == stmt { 11656- nodeIndex = i 11657- break 11658- } 11659- } 11660- 11661- // The statement we need to delete was not found in BlockStmt 11662- if nodeIndex == -1 { 11663- return nil 11664- } 11665- 11666- // Delete until the end of the block unless there is another statement after 11667- // the one we are trying to delete 11668- end := block.Rbrace 11669- if nodeIndex < len(block.List)-1 { 11670- end = block.List[nodeIndex+1].Pos() 11671- } 11672- 11673- return []analysis.TextEdit{ 11674- { 11675- Pos: stmt.Pos(), 11676- End: end, 11677- }, 11678- } 11679-} 11680- 11681-// exprMayHaveSideEffects reports whether the expression may have side effects 11682-// (because it contains a function call or channel receive). We disregard 11683-// runtime panics as well written programs should not encounter them. 11684-func exprMayHaveSideEffects(expr ast.Expr) bool { 11685- var mayHaveSideEffects bool 11686- ast.Inspect(expr, func(n ast.Node) bool { 11687- switch n := n.(type) { 11688- case *ast.CallExpr: // possible function call 11689- mayHaveSideEffects = true 11690- return false 11691- case *ast.UnaryExpr: 11692- if n.Op == token.ARROW { // channel receive 11693- mayHaveSideEffects = true 11694- return false 11695- } 11696- case *ast.FuncLit: 11697- return false // evaluating what's inside a FuncLit has no effect 11698- } 11699- return true 11700- }) 11701- 11702- return mayHaveSideEffects 11703-} 11704diff -urN a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go 11705--- a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go 2000-01-01 00:00:00.000000000 -0000 11706+++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go 1970-01-01 00:00:00.000000000 +0000 11707@@ -1,24 +0,0 @@ 11708-// Copyright 2020 The Go Authors. All rights reserved. 11709-// Use of this source code is governed by a BSD-style 11710-// license that can be found in the LICENSE file. 11711- 11712-package unusedvariable_test 11713- 11714-import ( 11715- "testing" 11716- 11717- "golang.org/x/tools/go/analysis/analysistest" 11718- "golang.org/x/tools/gopls/internal/lsp/analysis/unusedvariable" 11719-) 11720- 11721-func Test(t *testing.T) { 11722- testdata := analysistest.TestData() 11723- 11724- t.Run("decl", func(t *testing.T) { 11725- analysistest.RunWithSuggestedFixes(t, testdata, unusedvariable.Analyzer, "decl") 11726- }) 11727- 11728- t.Run("assign", func(t *testing.T) { 11729- analysistest.RunWithSuggestedFixes(t, testdata, unusedvariable.Analyzer, "assign") 11730- }) 11731-} 11732diff -urN a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go 11733--- a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go 2000-01-01 00:00:00.000000000 -0000 11734+++ b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go 1970-01-01 00:00:00.000000000 +0000 11735@@ -1,25 +0,0 @@ 11736-// Copyright 2021 The Go Authors. All rights reserved. 11737-// Use of this source code is governed by a BSD-style 11738-// license that can be found in the LICENSE file. 11739- 11740-// This file contains tests for the useany checker. 11741- 11742-package a 11743- 11744-type Any interface{} 11745- 11746-func _[T interface{}]() {} // want "could use \"any\" for this empty interface" 11747-func _[X any, T interface{}]() {} // want "could use \"any\" for this empty interface" 11748-func _[any interface{}]() {} // want "could use \"any\" for this empty interface" 11749-func _[T Any]() {} // want "could use \"any\" for this empty interface" 11750-func _[T interface{ int | interface{} }]() {} // want "could use \"any\" for this empty interface" 11751-func _[T interface{ int | Any }]() {} // want "could use \"any\" for this empty interface" 11752-func _[T any]() {} 11753- 11754-type _[T interface{}] int // want "could use \"any\" for this empty interface" 11755-type _[X any, T interface{}] int // want "could use \"any\" for this empty interface" 11756-type _[any interface{}] int // want "could use \"any\" for this empty interface" 11757-type _[T Any] int // want "could use \"any\" for this empty interface" 11758-type _[T interface{ int | interface{} }] int // want "could use \"any\" for this empty interface" 11759-type _[T interface{ int | Any }] int // want "could use \"any\" for this empty interface" 11760-type _[T any] int 11761diff -urN a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden 11762--- a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden 2000-01-01 00:00:00.000000000 -0000 11763+++ b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden 1970-01-01 00:00:00.000000000 +0000 11764@@ -1,25 +0,0 @@ 11765-// Copyright 2021 The Go Authors. All rights reserved. 11766-// Use of this source code is governed by a BSD-style 11767-// license that can be found in the LICENSE file. 11768- 11769-// This file contains tests for the useany checker. 11770- 11771-package a 11772- 11773-type Any interface{} 11774- 11775-func _[T any]() {} // want "could use \"any\" for this empty interface" 11776-func _[X any, T any]() {} // want "could use \"any\" for this empty interface" 11777-func _[any interface{}]() {} // want "could use \"any\" for this empty interface" 11778-func _[T any]() {} // want "could use \"any\" for this empty interface" 11779-func _[T any]() {} // want "could use \"any\" for this empty interface" 11780-func _[T any]() {} // want "could use \"any\" for this empty interface" 11781-func _[T any]() {} 11782- 11783-type _[T any] int // want "could use \"any\" for this empty interface" 11784-type _[X any, T any] int // want "could use \"any\" for this empty interface" 11785-type _[any interface{}] int // want "could use \"any\" for this empty interface" 11786-type _[T any] int // want "could use \"any\" for this empty interface" 11787-type _[T any] int // want "could use \"any\" for this empty interface" 11788-type _[T any] int // want "could use \"any\" for this empty interface" 11789-type _[T any] int 11790diff -urN a/gopls/internal/lsp/analysis/useany/useany.go b/gopls/internal/lsp/analysis/useany/useany.go 11791--- a/gopls/internal/lsp/analysis/useany/useany.go 2000-01-01 00:00:00.000000000 -0000 11792+++ b/gopls/internal/lsp/analysis/useany/useany.go 1970-01-01 00:00:00.000000000 +0000 11793@@ -1,102 +0,0 @@ 11794-// Copyright 2021 The Go Authors. All rights reserved. 11795-// Use of this source code is governed by a BSD-style 11796-// license that can be found in the LICENSE file. 11797- 11798-// Package useany defines an Analyzer that checks for usage of interface{} in 11799-// constraints, rather than the predeclared any. 11800-package useany 11801- 11802-import ( 11803- "fmt" 11804- "go/ast" 11805- "go/token" 11806- "go/types" 11807- 11808- "golang.org/x/tools/go/analysis" 11809- "golang.org/x/tools/go/analysis/passes/inspect" 11810- "golang.org/x/tools/go/ast/inspector" 11811- "golang.org/x/tools/internal/typeparams" 11812-) 11813- 11814-const Doc = `check for constraints that could be simplified to "any"` 11815- 11816-var Analyzer = &analysis.Analyzer{ 11817- Name: "useany", 11818- Doc: Doc, 11819- Requires: []*analysis.Analyzer{inspect.Analyzer}, 11820- Run: run, 11821-} 11822- 11823-func run(pass *analysis.Pass) (interface{}, error) { 11824- inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 11825- 11826- universeAny := types.Universe.Lookup("any") 11827- if universeAny == nil { 11828- // Go <= 1.17. Nothing to check. 11829- return nil, nil 11830- } 11831- 11832- nodeFilter := []ast.Node{ 11833- (*ast.TypeSpec)(nil), 11834- (*ast.FuncType)(nil), 11835- } 11836- 11837- inspect.Preorder(nodeFilter, func(node ast.Node) { 11838- var tparams *ast.FieldList 11839- switch node := node.(type) { 11840- case *ast.TypeSpec: 11841- tparams = typeparams.ForTypeSpec(node) 11842- case *ast.FuncType: 11843- tparams = typeparams.ForFuncType(node) 11844- default: 11845- panic(fmt.Sprintf("unexpected node type %T", node)) 11846- } 11847- if tparams.NumFields() == 0 { 11848- return 11849- } 11850- 11851- for _, field := range tparams.List { 11852- typ := pass.TypesInfo.Types[field.Type].Type 11853- if typ == nil { 11854- continue // something is wrong, but not our concern 11855- } 11856- iface, ok := typ.Underlying().(*types.Interface) 11857- if !ok { 11858- continue // invalid constraint 11859- } 11860- 11861- // If the constraint is the empty interface, offer a fix to use 'any' 11862- // instead. 11863- if iface.Empty() { 11864- id, _ := field.Type.(*ast.Ident) 11865- if id != nil && pass.TypesInfo.Uses[id] == universeAny { 11866- continue 11867- } 11868- 11869- diag := analysis.Diagnostic{ 11870- Pos: field.Type.Pos(), 11871- End: field.Type.End(), 11872- Message: `could use "any" for this empty interface`, 11873- } 11874- 11875- // Only suggest a fix to 'any' if we actually resolve the predeclared 11876- // any in this scope. 11877- if scope := pass.TypesInfo.Scopes[node]; scope != nil { 11878- if _, any := scope.LookupParent("any", token.NoPos); any == universeAny { 11879- diag.SuggestedFixes = []analysis.SuggestedFix{{ 11880- Message: `use "any"`, 11881- TextEdits: []analysis.TextEdit{{ 11882- Pos: field.Type.Pos(), 11883- End: field.Type.End(), 11884- NewText: []byte("any"), 11885- }}, 11886- }} 11887- } 11888- } 11889- 11890- pass.Report(diag) 11891- } 11892- } 11893- }) 11894- return nil, nil 11895-} 11896diff -urN a/gopls/internal/lsp/analysis/useany/useany_test.go b/gopls/internal/lsp/analysis/useany/useany_test.go 11897--- a/gopls/internal/lsp/analysis/useany/useany_test.go 2000-01-01 00:00:00.000000000 -0000 11898+++ b/gopls/internal/lsp/analysis/useany/useany_test.go 1970-01-01 00:00:00.000000000 +0000 11899@@ -1,21 +0,0 @@ 11900-// Copyright 2021 The Go Authors. All rights reserved. 11901-// Use of this source code is governed by a BSD-style 11902-// license that can be found in the LICENSE file. 11903- 11904-package useany_test 11905- 11906-import ( 11907- "testing" 11908- 11909- "golang.org/x/tools/go/analysis/analysistest" 11910- "golang.org/x/tools/gopls/internal/lsp/analysis/useany" 11911- "golang.org/x/tools/internal/typeparams" 11912-) 11913- 11914-func Test(t *testing.T) { 11915- if !typeparams.Enabled { 11916- t.Skip("type params are not enabled") 11917- } 11918- testdata := analysistest.TestData() 11919- analysistest.RunWithSuggestedFixes(t, testdata, useany.Analyzer, "a") 11920-} 11921diff -urN a/gopls/internal/lsp/browser/browser.go b/gopls/internal/lsp/browser/browser.go 11922--- a/gopls/internal/lsp/browser/browser.go 2000-01-01 00:00:00.000000000 -0000 11923+++ b/gopls/internal/lsp/browser/browser.go 1970-01-01 00:00:00.000000000 +0000 11924@@ -1,67 +0,0 @@ 11925-// Copyright 2016 The Go Authors. All rights reserved. 11926-// Use of this source code is governed by a BSD-style 11927-// license that can be found in the LICENSE file. 11928- 11929-// Package browser provides utilities for interacting with users' browsers. 11930-package browser 11931- 11932-import ( 11933- exec "golang.org/x/sys/execabs" 11934- "os" 11935- "runtime" 11936- "time" 11937-) 11938- 11939-// Commands returns a list of possible commands to use to open a url. 11940-func Commands() [][]string { 11941- var cmds [][]string 11942- if exe := os.Getenv("BROWSER"); exe != "" { 11943- cmds = append(cmds, []string{exe}) 11944- } 11945- switch runtime.GOOS { 11946- case "darwin": 11947- cmds = append(cmds, []string{"/usr/bin/open"}) 11948- case "windows": 11949- cmds = append(cmds, []string{"cmd", "/c", "start"}) 11950- default: 11951- if os.Getenv("DISPLAY") != "" { 11952- // xdg-open is only for use in a desktop environment. 11953- cmds = append(cmds, []string{"xdg-open"}) 11954- } 11955- } 11956- cmds = append(cmds, 11957- []string{"chrome"}, 11958- []string{"google-chrome"}, 11959- []string{"chromium"}, 11960- []string{"firefox"}, 11961- ) 11962- return cmds 11963-} 11964- 11965-// Open tries to open url in a browser and reports whether it succeeded. 11966-func Open(url string) bool { 11967- for _, args := range Commands() { 11968- cmd := exec.Command(args[0], append(args[1:], url)...) 11969- if cmd.Start() == nil && appearsSuccessful(cmd, 3*time.Second) { 11970- return true 11971- } 11972- } 11973- return false 11974-} 11975- 11976-// appearsSuccessful reports whether the command appears to have run successfully. 11977-// If the command runs longer than the timeout, it's deemed successful. 11978-// If the command runs within the timeout, it's deemed successful if it exited cleanly. 11979-func appearsSuccessful(cmd *exec.Cmd, timeout time.Duration) bool { 11980- errc := make(chan error, 1) 11981- go func() { 11982- errc <- cmd.Wait() 11983- }() 11984- 11985- select { 11986- case <-time.After(timeout): 11987- return true 11988- case err := <-errc: 11989- return err == nil 11990- } 11991-} 11992diff -urN a/gopls/internal/lsp/browser/README.md b/gopls/internal/lsp/browser/README.md 11993--- a/gopls/internal/lsp/browser/README.md 2000-01-01 00:00:00.000000000 -0000 11994+++ b/gopls/internal/lsp/browser/README.md 1970-01-01 00:00:00.000000000 +0000 11995@@ -1 +0,0 @@ 11996-This package is a copy of cmd/internal/browser from the go distribution 11997\ No newline at end of file 11998diff -urN a/gopls/internal/lsp/cache/analysis.go b/gopls/internal/lsp/cache/analysis.go 11999--- a/gopls/internal/lsp/cache/analysis.go 2000-01-01 00:00:00.000000000 -0000 12000+++ b/gopls/internal/lsp/cache/analysis.go 1970-01-01 00:00:00.000000000 +0000 12001@@ -1,1247 +0,0 @@ 12002-// Copyright 2019 The Go Authors. All rights reserved. 12003-// Use of this source code is governed by a BSD-style 12004-// license that can be found in the LICENSE file. 12005- 12006-package cache 12007- 12008-// This file defines gopls' driver for modular static analysis (go/analysis). 12009- 12010-import ( 12011- "bytes" 12012- "context" 12013- "crypto/sha256" 12014- "encoding/gob" 12015- "encoding/json" 12016- "errors" 12017- "fmt" 12018- "go/ast" 12019- "go/token" 12020- "go/types" 12021- "log" 12022- "reflect" 12023- "runtime/debug" 12024- "sort" 12025- "strings" 12026- "sync" 12027- "time" 12028- 12029- "golang.org/x/sync/errgroup" 12030- "golang.org/x/tools/go/analysis" 12031- "golang.org/x/tools/gopls/internal/lsp/filecache" 12032- "golang.org/x/tools/gopls/internal/lsp/protocol" 12033- "golang.org/x/tools/gopls/internal/lsp/source" 12034- "golang.org/x/tools/internal/bug" 12035- "golang.org/x/tools/internal/facts" 12036- "golang.org/x/tools/internal/gcimporter" 12037- "golang.org/x/tools/internal/memoize" 12038- "golang.org/x/tools/internal/typeparams" 12039- "golang.org/x/tools/internal/typesinternal" 12040-) 12041- 12042-/* 12043- 12044- DESIGN 12045- 12046- An analysis request is for a set of analyzers and an individual 12047- package ID, notated (a*, p). The result is the set of diagnostics 12048- for that package. It could easily be generalized to a set of 12049- packages, (a*, p*), and perhaps should be, to improve performance 12050- versus calling it in a loop. 12051- 12052- The snapshot holds a cache (persistent.Map) of entries keyed by 12053- (a*, p) pairs ("analysisKey") that have been requested so far. Some 12054- of these entries may be invalidated during snapshot cloning after a 12055- modification event. The cache maps each (a*, p) to a promise of 12056- the analysis result or "analysisSummary". The summary contains the 12057- results of analysis (e.g. diagnostics) as well as the intermediate 12058- results required by the recursion, such as serialized types and 12059- facts. 12060- 12061- The promise represents the result of a call to analyzeImpl, which 12062- type-checks a package and then applies a graph of analyzers to it 12063- in parallel postorder. (These graph edges are "horizontal": within 12064- the same package.) First, analyzeImpl reads the source files of 12065- package p, and obtains (recursively) the results of the "vertical" 12066- dependencies (i.e. analyzers applied to the packages imported by 12067- p). Only the subset of analyzers that use facts need be executed 12068- recursively, but even if this subset is empty, the step is still 12069- necessary because it provides type information. It is possible that 12070- a package may need to be type-checked and analyzed twice, for 12071- different subsets of analyzers, but the overlap is typically 12072- insignificant. 12073- 12074- With the file contents and the results of vertical dependencies, 12075- analyzeImpl is then in a position to produce a key representing the 12076- unit of work (parsing, type-checking, and analysis) that it has to 12077- do. The key is a cryptographic hash of the "recipe" for this step, 12078- including the Metadata, the file contents, the set of analyzers, 12079- and the type and fact information from the vertical dependencies. 12080- 12081- The key is sought in a machine-global persistent file-system based 12082- cache. If this gopls process, or another gopls process on the same 12083- machine, has already performed this analysis step, analyzeImpl will 12084- make a cache hit and load the serialized summary of the results. If 12085- not, it will have to proceed to type-checking and analysis, and 12086- write a new cache entry. The entry contains serialized types 12087- (export data) and analysis facts. 12088- 12089- For types, we use "shallow" export data. Historically, the Go 12090- compiler always produced a summary of the types for a given package 12091- that included types from other packages that it indirectly 12092- referenced: "deep" export data. This had the advantage that the 12093- compiler (and analogous tools such as gopls) need only load one 12094- file per direct import. However, it meant that the files tended to 12095- get larger based on the level of the package in the import 12096- graph. For example, higher-level packages in the kubernetes module 12097- have over 1MB of "deep" export data, even when they have almost no 12098- content of their own, merely because they mention a major type that 12099- references many others. In pathological cases the export data was 12100- 300x larger than the source for a package due to this quadratic 12101- growth. 12102- 12103- "Shallow" export data means that the serialized types describe only 12104- a single package. If those types mention types from other packages, 12105- the type checker may need to request additional packages beyond 12106- just the direct imports. This means type information for the entire 12107- transitive closure of imports may need to be available just in 12108- case. After a cache hit or a cache miss, the summary is 12109- postprocessed so that it contains the union of export data payloads 12110- of all its direct dependencies. 12111- 12112- For correct dependency analysis, the digest used as a cache key 12113- must reflect the "deep" export data, so it is derived recursively 12114- from the transitive closure. As an optimization, we needn't include 12115- every package of the transitive closure in the deep hash, only the 12116- packages that were actually requested by the type checker. This 12117- allows changes to a package that have no effect on its export data 12118- to be "pruned". The direct consumer will need to be re-executed, 12119- but if its export data is unchanged as a result, then indirect 12120- consumers may not need to be re-executed. This allows, for example, 12121- one to insert a print statement in a function and not "rebuild" the 12122- whole application (though export data does record line numbers of 12123- types which may be perturbed by otherwise insignificant changes.) 12124- 12125- The summary must record whether a package is transitively 12126- error-free (whether it would compile) because many analyzers are 12127- not safe to run on packages with inconsistent types. 12128- 12129- For fact encoding, we use the same fact set as the unitchecker 12130- (vet) to record and serialize analysis facts. The fact 12131- serialization mechanism is analogous to "deep" export data. 12132- 12133-*/ 12134- 12135-// TODO(adonovan): 12136-// - Profile + optimize: 12137-// - on a cold run, mostly type checking + export data, unsurprisingly. 12138-// - on a hot-disk run, mostly type checking the IWL. 12139-// Would be nice to have a benchmark that separates this out. 12140-// - measure and record in the code the typical operation times 12141-// and file sizes (export data + facts = cache entries). 12142-// - Do "port the old logic" tasks (see TODO in actuallyAnalyze). 12143-// - Add a (white-box) test of pruning when a change doesn't affect export data. 12144-// - Optimise pruning based on subset of packages mentioned in exportdata. 12145-// - Better logging so that it is possible to deduce why an analyzer 12146-// is not being run--often due to very indirect failures. 12147-// Even if the ultimate consumer decides to ignore errors, 12148-// tests and other situations want to be assured of freedom from 12149-// errors, not just missing results. This should be recorded. 12150-// - Check that the event trace is intelligible. 12151-// - Split this into a subpackage, gopls/internal/lsp/cache/driver, 12152-// consisting of this file and three helpers from errors.go. 12153-// The (*snapshot).Analyze method would stay behind and make calls 12154-// to the driver package. 12155-// Steps: 12156-// - define a narrow driver.Snapshot interface with only these methods: 12157-// Metadata(PackageID) source.Metadata 12158-// GetFile(Context, URI) (source.FileHandle, error) 12159-// View() *View // for Options 12160-// - define a State type that encapsulates the persistent map 12161-// (with its own mutex), and has methods: 12162-// New() *State 12163-// Clone(invalidate map[PackageID]bool) *State 12164-// Destroy() 12165-// - share cache.{goVersionRx,parseGoImpl} 12166- 12167-var born = time.Now() 12168- 12169-// Analyze applies a set of analyzers to the package denoted by id, 12170-// and returns their diagnostics for that package. 12171-// 12172-// The analyzers list must be duplicate free; order does not matter. 12173-// 12174-// Precondition: all analyzers within the process have distinct names. 12175-// (The names are relied on by the serialization logic.) 12176-func (s *snapshot) Analyze(ctx context.Context, id PackageID, analyzers []*source.Analyzer) ([]*source.Diagnostic, error) { 12177- if false { // debugging 12178- log.Println("Analyze@", time.Since(born)) // called after the 7s IWL in k8s 12179- } 12180- 12181- // Filter and sort enabled root analyzers. 12182- // A disabled analyzer may still be run if required by another. 12183- toSrc := make(map[*analysis.Analyzer]*source.Analyzer) 12184- var enabled []*analysis.Analyzer 12185- for _, a := range analyzers { 12186- if a.IsEnabled(s.view.Options()) { 12187- toSrc[a.Analyzer] = a 12188- enabled = append(enabled, a.Analyzer) 12189- } 12190- } 12191- sort.Slice(enabled, func(i, j int) bool { 12192- return enabled[i].Name < enabled[j].Name 12193- }) 12194- 12195- // Register fact types of required analyzers. 12196- for _, a := range requiredAnalyzers(enabled) { 12197- for _, f := range a.FactTypes { 12198- gob.Register(f) 12199- } 12200- } 12201- 12202- if false { // debugging 12203- // TODO(adonovan): use proper tracing. 12204- t0 := time.Now() 12205- defer func() { 12206- log.Printf("%v for analyze(%s, %s)", time.Since(t0), id, enabled) 12207- }() 12208- } 12209- 12210- // Run the analysis. 12211- res, err := s.analyze(ctx, id, enabled) 12212- if err != nil { 12213- return nil, err 12214- } 12215- 12216- // Report diagnostics only from enabled actions that succeeded. 12217- // Errors from creating or analyzing packages are ignored. 12218- // Diagnostics are reported in the order of the analyzers argument. 12219- // 12220- // TODO(adonovan): ignoring action errors gives the caller no way 12221- // to distinguish "there are no problems in this code" from 12222- // "the code (or analyzers!) are so broken that we couldn't even 12223- // begin the analysis you asked for". 12224- // Even if current callers choose to discard the 12225- // results, we should propagate the per-action errors. 12226- var results []*source.Diagnostic 12227- for _, a := range enabled { 12228- summary := res.Actions[a.Name] 12229- if summary.Err != "" { 12230- continue // action failed 12231- } 12232- for _, gobDiag := range summary.Diagnostics { 12233- results = append(results, toSourceDiagnostic(toSrc[a], &gobDiag)) 12234- } 12235- } 12236- return results, nil 12237-} 12238- 12239-// analysisKey is the type of keys in the snapshot.analyses map. 12240-type analysisKey struct { 12241- analyzerNames string 12242- pkgid PackageID 12243-} 12244- 12245-func (key analysisKey) String() string { 12246- return fmt.Sprintf("%s@%s", key.analyzerNames, key.pkgid) 12247-} 12248- 12249-// analyzeSummary is a gob-serializable summary of successfully 12250-// applying a list of analyzers to a package. 12251-type analyzeSummary struct { 12252- PkgPath PackagePath // types.Package.Path() (needed to decode export data) 12253- Export []byte 12254- DeepExportHash source.Hash // hash of reflexive transitive closure of export data 12255- Compiles bool // transitively free of list/parse/type errors 12256- Actions actionsMap // map from analyzer name to analysis results (*actionSummary) 12257- 12258- // Not serialized: populated after the summary is computed or deserialized. 12259- allExport map[PackagePath][]byte // transitive export data 12260-} 12261- 12262-// actionsMap defines a stable Gob encoding for a map. 12263-// TODO(adonovan): generalize and move to a library when we can use generics. 12264-type actionsMap map[string]*actionSummary 12265- 12266-var _ gob.GobEncoder = (actionsMap)(nil) 12267-var _ gob.GobDecoder = (*actionsMap)(nil) 12268- 12269-type actionsMapEntry struct { 12270- K string 12271- V *actionSummary 12272-} 12273- 12274-func (m actionsMap) GobEncode() ([]byte, error) { 12275- entries := make([]actionsMapEntry, 0, len(m)) 12276- for k, v := range m { 12277- entries = append(entries, actionsMapEntry{k, v}) 12278- } 12279- sort.Slice(entries, func(i, j int) bool { 12280- return entries[i].K < entries[j].K 12281- }) 12282- var buf bytes.Buffer 12283- err := gob.NewEncoder(&buf).Encode(entries) 12284- return buf.Bytes(), err 12285-} 12286- 12287-func (m *actionsMap) GobDecode(data []byte) error { 12288- var entries []actionsMapEntry 12289- if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&entries); err != nil { 12290- return err 12291- } 12292- *m = make(actionsMap, len(entries)) 12293- for _, e := range entries { 12294- (*m)[e.K] = e.V 12295- } 12296- return nil 12297-} 12298- 12299-// actionSummary is a gob-serializable summary of one possibly failed analysis action. 12300-// If Err is non-empty, the other fields are undefined. 12301-type actionSummary struct { 12302- Facts []byte // the encoded facts.Set 12303- FactsHash source.Hash // hash(Facts) 12304- Diagnostics []gobDiagnostic 12305- Err string // "" => success 12306-} 12307- 12308-// analyze is a memoization of analyzeImpl. 12309-func (s *snapshot) analyze(ctx context.Context, id PackageID, analyzers []*analysis.Analyzer) (*analyzeSummary, error) { 12310- // Use the sorted list of names of analyzers in the key. 12311- // 12312- // TODO(adonovan): opt: account for analysis results at a 12313- // finer grain to avoid duplicate work when a 12314- // a proper subset of analyzers is requested? 12315- // In particular, TypeErrorAnalyzers don't use facts 12316- // but need to request vdeps just for type information. 12317- names := make([]string, 0, len(analyzers)) 12318- for _, a := range analyzers { 12319- names = append(names, a.Name) 12320- } 12321- // This key describes the result of applying a list of analyzers to a package. 12322- key := analysisKey{strings.Join(names, ","), id} 12323- 12324- // An analysisPromise represents the result of loading, parsing, 12325- // type-checking and analyzing a single package. 12326- type analysisPromise struct { 12327- promise *memoize.Promise // [analyzeImplResult] 12328- } 12329- 12330- type analyzeImplResult struct { 12331- summary *analyzeSummary 12332- err error 12333- } 12334- 12335- // Access the map once, briefly, and atomically. 12336- s.mu.Lock() 12337- entry, hit := s.analyses.Get(key) 12338- if !hit { 12339- entry = analysisPromise{ 12340- promise: memoize.NewPromise("analysis", func(ctx context.Context, arg interface{}) interface{} { 12341- summary, err := analyzeImpl(ctx, arg.(*snapshot), analyzers, id) 12342- return analyzeImplResult{summary, err} 12343- }), 12344- } 12345- s.analyses.Set(key, entry, nil) // nothing needs releasing 12346- } 12347- s.mu.Unlock() 12348- 12349- // Await result. 12350- ap := entry.(analysisPromise) 12351- v, err := s.awaitPromise(ctx, ap.promise) 12352- if err != nil { 12353- return nil, err // e.g. cancelled 12354- } 12355- res := v.(analyzeImplResult) 12356- return res.summary, res.err 12357-} 12358- 12359-// analyzeImpl applies a list of analyzers (plus any others 12360-// transitively required by them) to a package. It succeeds as long 12361-// as it could produce a types.Package, even if there were direct or 12362-// indirect list/parse/type errors, and even if all the analysis 12363-// actions failed. It usually fails only if the package was unknown, 12364-// a file was missing, or the operation was cancelled. 12365-// 12366-// Postcondition: analyzeImpl must not continue to use the snapshot 12367-// (in background goroutines) after it has returned; see memoize.RefCounted. 12368-func analyzeImpl(ctx context.Context, snapshot *snapshot, analyzers []*analysis.Analyzer, id PackageID) (*analyzeSummary, error) { 12369- m := snapshot.Metadata(id) 12370- if m == nil { 12371- return nil, fmt.Errorf("no metadata for %s", id) 12372- } 12373- 12374- // Recursively analyze each "vertical" dependency 12375- // for its types.Package and (perhaps) analysis.Facts. 12376- // If any of them fails to produce a package, we cannot continue. 12377- // We request only the analyzers that produce facts. 12378- // 12379- // Also, load the contents of each "compiled" Go file through 12380- // the snapshot's cache. 12381- // 12382- // Both loops occur in parallel, and parallel with each other. 12383- vdeps := make(map[PackageID]*analyzeSummary) 12384- compiledGoFiles := make([]source.FileHandle, len(m.CompiledGoFiles)) 12385- { 12386- var group errgroup.Group 12387- 12388- // Analyze vertical dependencies. 12389- // We request only the required analyzers that use facts. 12390- var useFacts []*analysis.Analyzer 12391- for _, a := range requiredAnalyzers(analyzers) { 12392- if len(a.FactTypes) > 0 { 12393- useFacts = append(useFacts, a) 12394- } 12395- } 12396- var vdepsMu sync.Mutex 12397- for _, id := range m.DepsByPkgPath { 12398- id := id 12399- group.Go(func() error { 12400- res, err := snapshot.analyze(ctx, id, useFacts) 12401- if err != nil { 12402- return err // cancelled, or failed to produce a package 12403- } 12404- 12405- vdepsMu.Lock() 12406- vdeps[id] = res 12407- vdepsMu.Unlock() 12408- return nil 12409- }) 12410- } 12411- 12412- // Read file contents. 12413- // (In practice these will be cache hits 12414- // on reads done by the initial workspace load 12415- // or after a change modification event.) 12416- for i, uri := range m.CompiledGoFiles { 12417- i, uri := i, uri 12418- group.Go(func() error { 12419- fh, err := snapshot.GetFile(ctx, uri) // ~25us 12420- compiledGoFiles[i] = fh 12421- return err // e.g. cancelled 12422- }) 12423- } 12424- 12425- if err := group.Wait(); err != nil { 12426- return nil, err 12427- } 12428- } 12429- 12430- // Inv: analyze() of all vdeps succeeded (though some actions may have failed). 12431- 12432- // We no longer depend on the snapshot. 12433- snapshot = nil 12434- 12435- // At this point we have the action results (serialized 12436- // packages and facts) of our immediate dependencies, 12437- // and the metadata and content of this package. 12438- // 12439- // We now compute a hash for all our inputs, and consult a 12440- // global cache of promised results. If nothing material 12441- // has changed, we'll make a hit in the shared cache. 12442- // 12443- // The hash of our inputs is based on the serialized export 12444- // data and facts so that immaterial changes can be pruned 12445- // without decoding. 12446- key := analysisCacheKey(analyzers, m, compiledGoFiles, vdeps) 12447- 12448- // Access the cache. 12449- var summary *analyzeSummary 12450- const cacheKind = "analysis" 12451- if data, err := filecache.Get(cacheKind, key); err == nil { 12452- // cache hit 12453- mustDecode(data, &summary) 12454- 12455- } else if err != filecache.ErrNotFound { 12456- return nil, bug.Errorf("internal error reading shared cache: %v", err) 12457- 12458- } else { 12459- // Cache miss: do the work. 12460- var err error 12461- summary, err = actuallyAnalyze(ctx, analyzers, m, vdeps, compiledGoFiles) 12462- if err != nil { 12463- return nil, err 12464- } 12465- data := mustEncode(summary) 12466- if false { 12467- log.Printf("Set key=%d value=%d id=%s\n", len(key), len(data), id) 12468- } 12469- if err := filecache.Set(cacheKind, key, data); err != nil { 12470- return nil, fmt.Errorf("internal error updating shared cache: %v", err) 12471- } 12472- } 12473- 12474- // Hit or miss, we need to merge the export data from 12475- // dependencies so that it includes all the types 12476- // that might be summoned by the type checker. 12477- // 12478- // TODO(adonovan): opt: reduce this set by recording 12479- // which packages were actually summoned by insert(). 12480- // (Just makes map smaller; probably marginal?) 12481- allExport := make(map[PackagePath][]byte) 12482- for _, vdep := range vdeps { 12483- for k, v := range vdep.allExport { 12484- allExport[k] = v 12485- } 12486- } 12487- allExport[m.PkgPath] = summary.Export 12488- summary.allExport = allExport 12489- 12490- return summary, nil 12491-} 12492- 12493-// analysisCacheKey returns a cache key that is a cryptographic digest 12494-// of the all the values that might affect type checking and analysis: 12495-// the analyzer names, package metadata, names and contents of 12496-// compiled Go files, and vdeps information (export data and facts). 12497-// 12498-// TODO(adonovan): safety: define our own flavor of Metadata 12499-// containing just the fields we need, and using it in the subsequent 12500-// logic, to keep us honest about hashing all parts that matter? 12501-func analysisCacheKey(analyzers []*analysis.Analyzer, m *source.Metadata, compiledGoFiles []source.FileHandle, vdeps map[PackageID]*analyzeSummary) [sha256.Size]byte { 12502- hasher := sha256.New() 12503- 12504- // In principle, a key must be the hash of an 12505- // unambiguous encoding of all the relevant data. 12506- // If it's ambiguous, we risk collisions. 12507- 12508- // analyzers 12509- fmt.Fprintf(hasher, "analyzers: %d\n", len(analyzers)) 12510- for _, a := range analyzers { 12511- fmt.Fprintln(hasher, a.Name) 12512- } 12513- 12514- // package metadata 12515- fmt.Fprintf(hasher, "package: %s %s %s\n", m.ID, m.Name, m.PkgPath) 12516- // We can ignore m.DepsBy{Pkg,Import}Path: although the logic 12517- // uses those fields, we account for them by hashing vdeps. 12518- 12519- // type sizes 12520- // This assertion is safe, but if a black-box implementation 12521- // is ever needed, record Sizeof(*int) and Alignof(int64). 12522- sz := m.TypesSizes.(*types.StdSizes) 12523- fmt.Fprintf(hasher, "sizes: %d %d\n", sz.WordSize, sz.MaxAlign) 12524- 12525- // metadata errors: used for 'compiles' field 12526- fmt.Fprintf(hasher, "errors: %d", len(m.Errors)) 12527- 12528- // module Go version 12529- if m.Module != nil && m.Module.GoVersion != "" { 12530- fmt.Fprintf(hasher, "go %s\n", m.Module.GoVersion) 12531- } 12532- 12533- // file names and contents 12534- fmt.Fprintf(hasher, "files: %d\n", len(compiledGoFiles)) 12535- for _, fh := range compiledGoFiles { 12536- fmt.Fprintln(hasher, fh.FileIdentity()) 12537- } 12538- 12539- // vdeps, in PackageID order 12540- depIDs := make([]string, 0, len(vdeps)) 12541- for depID := range vdeps { 12542- depIDs = append(depIDs, string(depID)) 12543- } 12544- sort.Strings(depIDs) 12545- for _, depID := range depIDs { 12546- vdep := vdeps[PackageID(depID)] 12547- fmt.Fprintf(hasher, "dep: %s\n", vdep.PkgPath) 12548- fmt.Fprintf(hasher, "export: %s\n", vdep.DeepExportHash) 12549- 12550- // action results: errors and facts 12551- names := make([]string, 0, len(vdep.Actions)) 12552- for name := range vdep.Actions { 12553- names = append(names, name) 12554- } 12555- sort.Strings(names) 12556- for _, name := range names { 12557- summary := vdep.Actions[name] 12558- fmt.Fprintf(hasher, "action %s\n", name) 12559- if summary.Err != "" { 12560- fmt.Fprintf(hasher, "error %s\n", summary.Err) 12561- } else { 12562- fmt.Fprintf(hasher, "facts %s\n", summary.FactsHash) 12563- // We can safely omit summary.diagnostics 12564- // from the key since they have no downstream effect. 12565- } 12566- } 12567- } 12568- 12569- var hash [sha256.Size]byte 12570- hasher.Sum(hash[:0]) 12571- return hash 12572-} 12573- 12574-// actuallyAnalyze implements the cache-miss case. 12575-// This function does not access the snapshot. 12576-func actuallyAnalyze(ctx context.Context, analyzers []*analysis.Analyzer, m *source.Metadata, vdeps map[PackageID]*analyzeSummary, compiledGoFiles []source.FileHandle) (*analyzeSummary, error) { 12577- 12578- // Create a local FileSet for processing this package only. 12579- fset := token.NewFileSet() 12580- 12581- // Parse only the "compiled" Go files. 12582- // Do the computation in parallel. 12583- parsed := make([]*source.ParsedGoFile, len(compiledGoFiles)) 12584- { 12585- var group errgroup.Group 12586- for i, fh := range compiledGoFiles { 12587- i, fh := i, fh 12588- group.Go(func() error { 12589- // Call parseGoImpl directly, not the caching wrapper, 12590- // as cached ASTs require the global FileSet. 12591- pgf, err := parseGoImpl(ctx, fset, fh, source.ParseFull) 12592- parsed[i] = pgf 12593- return err 12594- }) 12595- } 12596- if err := group.Wait(); err != nil { 12597- return nil, err // cancelled, or catastrophic error (e.g. missing file) 12598- } 12599- } 12600- 12601- // Type-check the package. 12602- pkg := typeCheckForAnalysis(fset, parsed, m, vdeps) 12603- 12604- // Build a map of PkgPath to *Package for all packages mentioned 12605- // in exportdata for use by facts. 12606- pkg.factsDecoder = facts.NewDecoder(pkg.types) 12607- 12608- // Poll cancellation state. 12609- if err := ctx.Err(); err != nil { 12610- return nil, err 12611- } 12612- 12613- // TODO(adonovan): port the old logic to: 12614- // - gather go/packages diagnostics from m.Errors? (port goPackagesErrorDiagnostics) 12615- // - record unparseable file URIs so we can suppress type errors for these files. 12616- // - gather diagnostics from expandErrors + typeErrorDiagnostics + depsErrors. 12617- 12618- // -- analysis -- 12619- 12620- // Build action graph for this package. 12621- // Each graph node (action) is one unit of analysis. 12622- actions := make(map[*analysis.Analyzer]*action) 12623- var mkAction func(a *analysis.Analyzer) *action 12624- mkAction = func(a *analysis.Analyzer) *action { 12625- act, ok := actions[a] 12626- if !ok { 12627- var hdeps []*action 12628- for _, req := range a.Requires { 12629- hdeps = append(hdeps, mkAction(req)) 12630- } 12631- act = &action{a: a, pkg: pkg, vdeps: vdeps, hdeps: hdeps} 12632- actions[a] = act 12633- } 12634- return act 12635- } 12636- 12637- // Build actions for initial package. 12638- var roots []*action 12639- for _, a := range analyzers { 12640- roots = append(roots, mkAction(a)) 12641- } 12642- 12643- // Execute the graph in parallel. 12644- execActions(roots) 12645- 12646- // Don't return (or cache) the result in case of cancellation. 12647- if err := ctx.Err(); err != nil { 12648- return nil, err // cancelled 12649- } 12650- 12651- // Return summaries only for the requested actions. 12652- summaries := make(map[string]*actionSummary) 12653- for _, act := range roots { 12654- summaries[act.a.Name] = act.summary 12655- } 12656- 12657- return &analyzeSummary{ 12658- PkgPath: PackagePath(pkg.types.Path()), 12659- Export: pkg.export, 12660- DeepExportHash: pkg.deepExportHash, 12661- Compiles: pkg.compiles, 12662- Actions: summaries, 12663- }, nil 12664-} 12665- 12666-func typeCheckForAnalysis(fset *token.FileSet, parsed []*source.ParsedGoFile, m *source.Metadata, vdeps map[PackageID]*analyzeSummary) *analysisPackage { 12667- if false { // debugging 12668- log.Println("typeCheckForAnalysis", m.PkgPath) 12669- } 12670- 12671- pkg := &analysisPackage{ 12672- m: m, 12673- fset: fset, 12674- parsed: parsed, 12675- files: make([]*ast.File, len(parsed)), 12676- compiles: len(m.Errors) == 0, // false => list error 12677- types: types.NewPackage(string(m.PkgPath), string(m.Name)), 12678- typesInfo: &types.Info{ 12679- Types: make(map[ast.Expr]types.TypeAndValue), 12680- Defs: make(map[*ast.Ident]types.Object), 12681- Uses: make(map[*ast.Ident]types.Object), 12682- Implicits: make(map[ast.Node]types.Object), 12683- Selections: make(map[*ast.SelectorExpr]*types.Selection), 12684- Scopes: make(map[ast.Node]*types.Scope), 12685- }, 12686- typesSizes: m.TypesSizes, 12687- } 12688- typeparams.InitInstanceInfo(pkg.typesInfo) 12689- 12690- for i, p := range parsed { 12691- pkg.files[i] = p.File 12692- if p.ParseErr != nil { 12693- pkg.compiles = false // parse error 12694- } 12695- } 12696- 12697- // Unsafe is special. 12698- if m.PkgPath == "unsafe" { 12699- pkg.types = types.Unsafe 12700- return pkg 12701- } 12702- 12703- // Compute the union of transitive export data. 12704- // (The actual values are shared, and not serialized.) 12705- allExport := make(map[PackagePath][]byte) 12706- for _, vdep := range vdeps { 12707- for k, v := range vdep.allExport { 12708- allExport[k] = v 12709- } 12710- 12711- if !vdep.Compiles { 12712- pkg.compiles = false // transitive error 12713- } 12714- } 12715- 12716- // exportHasher computes a hash of the names and export data of 12717- // each package that was actually loaded during type checking. 12718- // 12719- // Because we use shallow export data, the hash for dependency 12720- // analysis must incorporate indirect dependencies. As an 12721- // optimization, we include only those that were actually 12722- // used, which may be a small subset of those available. 12723- // 12724- // TODO(adonovan): opt: even better would be to implement a 12725- // traversal over the package API like facts.NewDecoder does 12726- // and only mention that set of packages in the hash. 12727- // Perhaps there's a way to do that more efficiently. 12728- // 12729- // TODO(adonovan): opt: record the shallow hash alongside the 12730- // shallow export data in the allExport map to avoid repeatedly 12731- // hashing the export data. 12732- // 12733- // The writes to hasher below assume that type checking imports 12734- // packages in a deterministic order. 12735- exportHasher := sha256.New() 12736- hashExport := func(pkgPath PackagePath, export []byte) { 12737- fmt.Fprintf(exportHasher, "%s %d ", pkgPath, len(export)) 12738- exportHasher.Write(export) 12739- } 12740- 12741- // importer state 12742- var ( 12743- insert func(p *types.Package, name string) 12744- importMap = make(map[string]*types.Package) // keys are PackagePaths 12745- ) 12746- loadFromExportData := func(pkgPath PackagePath) (*types.Package, error) { 12747- export, ok := allExport[pkgPath] 12748- if !ok { 12749- return nil, bug.Errorf("missing export data for %q", pkgPath) 12750- } 12751- hashExport(pkgPath, export) 12752- imported, err := gcimporter.IImportShallow(fset, importMap, export, string(pkgPath), insert) 12753- if err != nil { 12754- return nil, bug.Errorf("invalid export data for %q: %v", pkgPath, err) 12755- } 12756- return imported, nil 12757- } 12758- insert = func(p *types.Package, name string) { 12759- imported, err := loadFromExportData(PackagePath(p.Path())) 12760- if err != nil { 12761- log.Fatalf("internal error: %v", err) 12762- } 12763- if imported != p { 12764- log.Fatalf("internal error: inconsistent packages") 12765- } 12766- } 12767- 12768- cfg := &types.Config{ 12769- Sizes: m.TypesSizes, 12770- Error: func(e error) { 12771- pkg.compiles = false // type error 12772- pkg.typeErrors = append(pkg.typeErrors, e.(types.Error)) 12773- }, 12774- Importer: importerFunc(func(importPath string) (*types.Package, error) { 12775- if importPath == "unsafe" { 12776- return types.Unsafe, nil // unsafe has no export data 12777- } 12778- 12779- // Beware that returning an error from this function 12780- // will cause the type checker to synthesize a fake 12781- // package whose Path is importPath, potentially 12782- // losing a vendor/ prefix. If type-checking errors 12783- // are swallowed, these packages may be confusing. 12784- 12785- id, ok := m.DepsByImpPath[ImportPath(importPath)] 12786- if !ok { 12787- // The import syntax is inconsistent with the metadata. 12788- // This could be because the import declaration was 12789- // incomplete and the metadata only includes complete 12790- // imports; or because the metadata ignores import 12791- // edges that would lead to cycles in the graph. 12792- return nil, fmt.Errorf("missing metadata for import of %q", importPath) 12793- } 12794- 12795- depResult, ok := vdeps[id] // id may be "" 12796- if !ok { 12797- // Analogous to (*snapshot).missingPkgError 12798- // in the logic for regular type-checking, 12799- // but without a snapshot we can't provide 12800- // such detail, and anyway most analysis 12801- // failures aren't surfaced in the UI. 12802- return nil, fmt.Errorf("no required module provides package %q (id=%q)", importPath, id) 12803- } 12804- 12805- // (Duplicates logic from check.go.) 12806- if !source.IsValidImport(m.PkgPath, depResult.PkgPath) { 12807- return nil, fmt.Errorf("invalid use of internal package %s", importPath) 12808- } 12809- 12810- return loadFromExportData(depResult.PkgPath) 12811- }), 12812- } 12813- 12814- // Set Go dialect. 12815- if m.Module != nil && m.Module.GoVersion != "" { 12816- goVersion := "go" + m.Module.GoVersion 12817- // types.NewChecker panics if GoVersion is invalid. 12818- // An unparsable mod file should probably stop us 12819- // before we get here, but double check just in case. 12820- if goVersionRx.MatchString(goVersion) { 12821- typesinternal.SetGoVersion(cfg, goVersion) 12822- } 12823- } 12824- 12825- // We want to type check cgo code if go/types supports it. 12826- // We passed typecheckCgo to go/packages when we Loaded. 12827- // TODO(adonovan): do we actually need this?? 12828- typesinternal.SetUsesCgo(cfg) 12829- 12830- check := types.NewChecker(cfg, fset, pkg.types, pkg.typesInfo) 12831- 12832- // Type checking errors are handled via the config, so ignore them here. 12833- _ = check.Files(pkg.files) 12834- 12835- // debugging (type errors are quite normal) 12836- if false { 12837- if pkg.typeErrors != nil { 12838- log.Printf("package %s has type errors: %v", pkg.types.Path(), pkg.typeErrors) 12839- } 12840- } 12841- 12842- // Emit the export data and compute the deep hash. 12843- export, err := gcimporter.IExportShallow(pkg.fset, pkg.types) 12844- if err != nil { 12845- // TODO(adonovan): in light of exporter bugs such as #57729, 12846- // consider using bug.Report here and retrying the IExportShallow 12847- // call here using an empty types.Package. 12848- log.Fatalf("internal error writing shallow export data: %v", err) 12849- } 12850- pkg.export = export 12851- hashExport(m.PkgPath, export) 12852- exportHasher.Sum(pkg.deepExportHash[:0]) 12853- 12854- return pkg 12855-} 12856- 12857-// analysisPackage contains information about a package, including 12858-// syntax trees, used transiently during its type-checking and analysis. 12859-type analysisPackage struct { 12860- m *source.Metadata 12861- fset *token.FileSet // local to this package 12862- parsed []*source.ParsedGoFile 12863- files []*ast.File // same as parsed[i].File 12864- types *types.Package 12865- compiles bool // package is transitively free of list/parse/type errors 12866- factsDecoder *facts.Decoder 12867- export []byte // encoding of types.Package 12868- deepExportHash source.Hash // reflexive transitive hash of export data 12869- typesInfo *types.Info 12870- typeErrors []types.Error 12871- typesSizes types.Sizes 12872-} 12873- 12874-// An action represents one unit of analysis work: the application of 12875-// one analysis to one package. Actions form a DAG, both within a 12876-// package (as different analyzers are applied, either in sequence or 12877-// parallel), and across packages (as dependencies are analyzed). 12878-type action struct { 12879- once sync.Once 12880- a *analysis.Analyzer 12881- pkg *analysisPackage 12882- hdeps []*action // horizontal dependencies 12883- vdeps map[PackageID]*analyzeSummary // vertical dependencies 12884- 12885- // results of action.exec(): 12886- result interface{} // result of Run function, of type a.ResultType 12887- summary *actionSummary 12888- err error 12889-} 12890- 12891-func (act *action) String() string { 12892- return fmt.Sprintf("%s@%s", act.a.Name, act.pkg.m.ID) 12893-} 12894- 12895-// execActions executes a set of action graph nodes in parallel. 12896-func execActions(actions []*action) { 12897- var wg sync.WaitGroup 12898- for _, act := range actions { 12899- act := act 12900- wg.Add(1) 12901- go func() { 12902- defer wg.Done() 12903- act.once.Do(func() { 12904- execActions(act.hdeps) // analyze "horizontal" dependencies 12905- act.result, act.summary, act.err = act.exec() 12906- if act.err != nil { 12907- act.summary = &actionSummary{Err: act.err.Error()} 12908- // TODO(adonovan): suppress logging. But 12909- // shouldn't the root error's causal chain 12910- // include this information? 12911- if false { // debugging 12912- log.Printf("act.exec(%v) failed: %v", act, act.err) 12913- } 12914- } 12915- }) 12916- }() 12917- } 12918- wg.Wait() 12919-} 12920- 12921-// exec defines the execution of a single action. 12922-// It returns the (ephemeral) result of the analyzer's Run function, 12923-// along with its (serializable) facts and diagnostics. 12924-// Or it returns an error if the analyzer did not run to 12925-// completion and deliver a valid result. 12926-func (act *action) exec() (interface{}, *actionSummary, error) { 12927- analyzer := act.a 12928- pkg := act.pkg 12929- 12930- hasFacts := len(analyzer.FactTypes) > 0 12931- 12932- // Report an error if any action dependency (vertical or horizontal) failed. 12933- // To avoid long error messages describing chains of failure, 12934- // we return the dependencies' error' unadorned. 12935- if hasFacts { 12936- // TODO(adonovan): use deterministic order. 12937- for _, res := range act.vdeps { 12938- if vdep := res.Actions[analyzer.Name]; vdep.Err != "" { 12939- return nil, nil, errors.New(vdep.Err) 12940- } 12941- } 12942- } 12943- for _, dep := range act.hdeps { 12944- if dep.err != nil { 12945- return nil, nil, dep.err 12946- } 12947- } 12948- // Inv: all action dependencies succeeded. 12949- 12950- // Were there list/parse/type errors that might prevent analysis? 12951- if !pkg.compiles && !analyzer.RunDespiteErrors { 12952- return nil, nil, fmt.Errorf("skipping analysis %q because package %q does not compile", analyzer.Name, pkg.m.ID) 12953- } 12954- // Inv: package is well-formed enough to proceed with analysis. 12955- 12956- if false { // debugging 12957- log.Println("action.exec", act) 12958- } 12959- 12960- // Gather analysis Result values from horizontal dependencies. 12961- var inputs = make(map[*analysis.Analyzer]interface{}) 12962- for _, dep := range act.hdeps { 12963- inputs[dep.a] = dep.result 12964- } 12965- 12966- // TODO(adonovan): opt: facts.Set works but it may be more 12967- // efficient to fork and tailor it to our precise needs. 12968- // 12969- // We've already sharded the fact encoding by action 12970- // so that it can be done in parallel (hoisting the 12971- // ImportMap call so that we build the map once per package). 12972- // We could eliminate locking. 12973- // We could also dovetail more closely with the export data 12974- // decoder to obtain a more compact representation of 12975- // packages and objects (e.g. its internal IDs, instead 12976- // of PkgPaths and objectpaths.) 12977- 12978- // Read and decode analysis facts for each imported package. 12979- factset, err := pkg.factsDecoder.Decode(func(imp *types.Package) ([]byte, error) { 12980- if !hasFacts { 12981- return nil, nil // analyzer doesn't use facts, so no vdeps 12982- } 12983- 12984- // Package.Imports() may contain a fake "C" package. Ignore it. 12985- if imp.Path() == "C" { 12986- return nil, nil 12987- } 12988- 12989- id, ok := pkg.m.DepsByPkgPath[PackagePath(imp.Path())] 12990- if !ok { 12991- // This may mean imp was synthesized by the type 12992- // checker because it failed to import it for any reason 12993- // (e.g. bug processing export data; metadata ignoring 12994- // a cycle-forming import). 12995- // In that case, the fake package's imp.Path 12996- // is set to the failed importPath (and thus 12997- // it may lack a "vendor/" prefix). 12998- // 12999- // For now, silently ignore it on the assumption 13000- // that the error is already reported elsewhere. 13001- // return nil, fmt.Errorf("missing metadata") 13002- return nil, nil 13003- } 13004- 13005- vdep, ok := act.vdeps[id] 13006- if !ok { 13007- return nil, bug.Errorf("internal error in %s: missing vdep for id=%s", pkg.types.Path(), id) 13008- } 13009- return vdep.Actions[analyzer.Name].Facts, nil 13010- }) 13011- if err != nil { 13012- return nil, nil, fmt.Errorf("internal error decoding analysis facts: %w", err) 13013- } 13014- 13015- // TODO(adonovan): make Export*Fact panic rather than discarding 13016- // undeclared fact types, so that we discover bugs in analyzers. 13017- factFilter := make(map[reflect.Type]bool) 13018- for _, f := range analyzer.FactTypes { 13019- factFilter[reflect.TypeOf(f)] = true 13020- } 13021- 13022- // posToLocation converts from token.Pos to protocol form. 13023- // TODO(adonovan): improve error messages. 13024- posToLocation := func(start, end token.Pos) (protocol.Location, error) { 13025- tokFile := pkg.fset.File(start) 13026- for _, p := range pkg.parsed { 13027- if p.Tok == tokFile { 13028- if end == token.NoPos { 13029- end = start 13030- } 13031- return p.PosLocation(start, end) 13032- } 13033- } 13034- return protocol.Location{}, 13035- bug.Errorf("internal error: token.Pos not within package") 13036- } 13037- 13038- // Now run the (pkg, analyzer) action. 13039- var diagnostics []gobDiagnostic 13040- pass := &analysis.Pass{ 13041- Analyzer: analyzer, 13042- Fset: pkg.fset, 13043- Files: pkg.files, 13044- Pkg: pkg.types, 13045- TypesInfo: pkg.typesInfo, 13046- TypesSizes: pkg.typesSizes, 13047- TypeErrors: pkg.typeErrors, 13048- ResultOf: inputs, 13049- Report: func(d analysis.Diagnostic) { 13050- // Prefix the diagnostic category with the analyzer's name. 13051- if d.Category == "" { 13052- d.Category = analyzer.Name 13053- } else { 13054- d.Category = analyzer.Name + "." + d.Category 13055- } 13056- 13057- diagnostic, err := toGobDiagnostic(posToLocation, d) 13058- if err != nil { 13059- bug.Reportf("internal error converting diagnostic from analyzer %q: %v", analyzer.Name, err) 13060- return 13061- } 13062- diagnostics = append(diagnostics, diagnostic) 13063- }, 13064- ImportObjectFact: factset.ImportObjectFact, 13065- ExportObjectFact: factset.ExportObjectFact, 13066- ImportPackageFact: factset.ImportPackageFact, 13067- ExportPackageFact: factset.ExportPackageFact, 13068- AllObjectFacts: func() []analysis.ObjectFact { return factset.AllObjectFacts(factFilter) }, 13069- AllPackageFacts: func() []analysis.PackageFact { return factset.AllPackageFacts(factFilter) }, 13070- } 13071- 13072- // Recover from panics (only) within the analyzer logic. 13073- // (Use an anonymous function to limit the recover scope.) 13074- var result interface{} 13075- func() { 13076- defer func() { 13077- if r := recover(); r != nil { 13078- // An Analyzer panicked, likely due to a bug. 13079- // 13080- // In general we want to discover and fix such panics quickly, 13081- // so we don't suppress them, but some bugs in third-party 13082- // analyzers cannot be quickly fixed, so we use an allowlist 13083- // to suppress panics. 13084- const strict = true 13085- if strict && bug.PanicOnBugs && 13086- analyzer.Name != "buildir" { // see https://github.com/dominikh/go-tools/issues/1343 13087- // Uncomment this when debugging suspected failures 13088- // in the driver, not the analyzer. 13089- if false { 13090- debug.SetTraceback("all") // show all goroutines 13091- } 13092- panic(r) 13093- } else { 13094- // In production, suppress the panic and press on. 13095- err = fmt.Errorf("analysis %s for package %s panicked: %v", analyzer.Name, pass.Pkg.Path(), r) 13096- } 13097- } 13098- }() 13099- result, err = pass.Analyzer.Run(pass) 13100- }() 13101- if err != nil { 13102- return nil, nil, err 13103- } 13104- 13105- if got, want := reflect.TypeOf(result), pass.Analyzer.ResultType; got != want { 13106- return nil, nil, bug.Errorf( 13107- "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v", 13108- pass.Pkg.Path(), pass.Analyzer, got, want) 13109- } 13110- 13111- // Disallow Export*Fact calls after Run. 13112- // (A panic means the Analyzer is abusing concurrency.) 13113- pass.ExportObjectFact = func(obj types.Object, fact analysis.Fact) { 13114- panic(fmt.Sprintf("%v: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact)) 13115- } 13116- pass.ExportPackageFact = func(fact analysis.Fact) { 13117- panic(fmt.Sprintf("%v: Pass.ExportPackageFact(%T) called after Run", act, fact)) 13118- } 13119- 13120- factsdata := factset.Encode() 13121- return result, &actionSummary{ 13122- Diagnostics: diagnostics, 13123- Facts: factsdata, 13124- FactsHash: source.HashOf(factsdata), 13125- }, nil 13126-} 13127- 13128-// requiredAnalyzers returns the transitive closure of required analyzers in preorder. 13129-func requiredAnalyzers(analyzers []*analysis.Analyzer) []*analysis.Analyzer { 13130- var result []*analysis.Analyzer 13131- seen := make(map[*analysis.Analyzer]bool) 13132- var visitAll func([]*analysis.Analyzer) 13133- visitAll = func(analyzers []*analysis.Analyzer) { 13134- for _, a := range analyzers { 13135- if !seen[a] { 13136- seen[a] = true 13137- result = append(result, a) 13138- visitAll(a.Requires) 13139- } 13140- } 13141- } 13142- visitAll(analyzers) 13143- return result 13144-} 13145- 13146-func mustEncode(x interface{}) []byte { 13147- var buf bytes.Buffer 13148- if err := gob.NewEncoder(&buf).Encode(x); err != nil { 13149- log.Fatalf("internal error encoding %T: %v", x, err) 13150- } 13151- return buf.Bytes() 13152-} 13153- 13154-func mustDecode(data []byte, ptr interface{}) { 13155- if err := gob.NewDecoder(bytes.NewReader(data)).Decode(ptr); err != nil { 13156- log.Fatalf("internal error decoding %T: %v", ptr, err) 13157- } 13158-} 13159- 13160-// -- data types for serialization of analysis.Diagnostic and source.Diagnostic -- 13161- 13162-type gobDiagnostic struct { 13163- Location protocol.Location 13164- Severity protocol.DiagnosticSeverity 13165- Code string 13166- CodeHref string 13167- Source string 13168- Message string 13169- SuggestedFixes []gobSuggestedFix 13170- Related []gobRelatedInformation 13171- Tags []protocol.DiagnosticTag 13172-} 13173- 13174-type gobRelatedInformation struct { 13175- Location protocol.Location 13176- Message string 13177-} 13178- 13179-type gobSuggestedFix struct { 13180- Message string 13181- TextEdits []gobTextEdit 13182- Command *gobCommand 13183- ActionKind protocol.CodeActionKind 13184-} 13185- 13186-type gobCommand struct { 13187- Title string 13188- Command string 13189- Arguments []json.RawMessage 13190-} 13191- 13192-type gobTextEdit struct { 13193- Location protocol.Location 13194- NewText []byte 13195-} 13196- 13197-// toGobDiagnostic converts an analysis.Diagnosic to a serializable gobDiagnostic, 13198-// which requires expanding token.Pos positions into protocol.Location form. 13199-func toGobDiagnostic(posToLocation func(start, end token.Pos) (protocol.Location, error), diag analysis.Diagnostic) (gobDiagnostic, error) { 13200- var fixes []gobSuggestedFix 13201- for _, fix := range diag.SuggestedFixes { 13202- var gobEdits []gobTextEdit 13203- for _, textEdit := range fix.TextEdits { 13204- loc, err := posToLocation(textEdit.Pos, textEdit.End) 13205- if err != nil { 13206- return gobDiagnostic{}, fmt.Errorf("in SuggestedFixes: %w", err) 13207- } 13208- gobEdits = append(gobEdits, gobTextEdit{ 13209- Location: loc, 13210- NewText: textEdit.NewText, 13211- }) 13212- } 13213- fixes = append(fixes, gobSuggestedFix{ 13214- Message: fix.Message, 13215- TextEdits: gobEdits, 13216- }) 13217- } 13218- 13219- var related []gobRelatedInformation 13220- for _, r := range diag.Related { 13221- loc, err := posToLocation(r.Pos, r.End) 13222- if err != nil { 13223- return gobDiagnostic{}, fmt.Errorf("in Related: %w", err) 13224- } 13225- related = append(related, gobRelatedInformation{ 13226- Location: loc, 13227- Message: r.Message, 13228- }) 13229- } 13230- 13231- loc, err := posToLocation(diag.Pos, diag.End) 13232- if err != nil { 13233- return gobDiagnostic{}, err 13234- } 13235- 13236- return gobDiagnostic{ 13237- Location: loc, 13238- // Severity for analysis diagnostics is dynamic, based on user 13239- // configuration per analyzer. 13240- // Code and CodeHref are unset for Analysis diagnostics, 13241- // TODO(rfindley): set Code fields if/when golang/go#57906 is accepted. 13242- Source: diag.Category, 13243- Message: diag.Message, 13244- SuggestedFixes: fixes, 13245- Related: related, 13246- // Analysis diagnostics do not contain tags. 13247- }, nil 13248-} 13249diff -urN a/gopls/internal/lsp/cache/cache.go b/gopls/internal/lsp/cache/cache.go 13250--- a/gopls/internal/lsp/cache/cache.go 2000-01-01 00:00:00.000000000 -0000 13251+++ b/gopls/internal/lsp/cache/cache.go 1970-01-01 00:00:00.000000000 +0000 13252@@ -1,78 +0,0 @@ 13253-// Copyright 2019 The Go Authors. All rights reserved. 13254-// Use of this source code is governed by a BSD-style 13255-// license that can be found in the LICENSE file. 13256- 13257-package cache 13258- 13259-import ( 13260- "context" 13261- "reflect" 13262- "strconv" 13263- "sync/atomic" 13264- 13265- "golang.org/x/tools/gopls/internal/lsp/source" 13266- "golang.org/x/tools/internal/event" 13267- "golang.org/x/tools/internal/gocommand" 13268- "golang.org/x/tools/internal/memoize" 13269- "golang.org/x/tools/internal/robustio" 13270-) 13271- 13272-// New Creates a new cache for gopls operation results, using the given file 13273-// set, shared store, and session options. 13274-// 13275-// Both the fset and store may be nil, but if store is non-nil so must be fset 13276-// (and they must always be used together), otherwise it may be possible to get 13277-// cached data referencing token.Pos values not mapped by the FileSet. 13278-func New(store *memoize.Store) *Cache { 13279- index := atomic.AddInt64(&cacheIndex, 1) 13280- 13281- if store == nil { 13282- store = &memoize.Store{} 13283- } 13284- 13285- c := &Cache{ 13286- id: strconv.FormatInt(index, 10), 13287- store: store, 13288- memoizedFS: &memoizedFS{filesByID: map[robustio.FileID][]*DiskFile{}}, 13289- } 13290- return c 13291-} 13292- 13293-// A Cache holds caching stores that are bundled together for consistency. 13294-// 13295-// TODO(rfindley): once fset and store need not be bundled together, the Cache 13296-// type can be eliminated. 13297-type Cache struct { 13298- id string 13299- 13300- store *memoize.Store 13301- 13302- *memoizedFS // implements source.FileSource 13303-} 13304- 13305-// NewSession creates a new gopls session with the given cache and options overrides. 13306-// 13307-// The provided optionsOverrides may be nil. 13308-// 13309-// TODO(rfindley): move this to session.go. 13310-func NewSession(ctx context.Context, c *Cache, optionsOverrides func(*source.Options)) *Session { 13311- index := atomic.AddInt64(&sessionIndex, 1) 13312- options := source.DefaultOptions().Clone() 13313- if optionsOverrides != nil { 13314- optionsOverrides(options) 13315- } 13316- s := &Session{ 13317- id: strconv.FormatInt(index, 10), 13318- cache: c, 13319- gocmdRunner: &gocommand.Runner{}, 13320- options: options, 13321- overlayFS: newOverlayFS(c), 13322- } 13323- event.Log(ctx, "New session", KeyCreateSession.Of(s)) 13324- return s 13325-} 13326- 13327-var cacheIndex, sessionIndex, viewIndex int64 13328- 13329-func (c *Cache) ID() string { return c.id } 13330-func (c *Cache) MemStats() map[reflect.Type]int { return c.store.Stats() } 13331diff -urN a/gopls/internal/lsp/cache/check.go b/gopls/internal/lsp/cache/check.go 13332--- a/gopls/internal/lsp/cache/check.go 2000-01-01 00:00:00.000000000 -0000 13333+++ b/gopls/internal/lsp/cache/check.go 1970-01-01 00:00:00.000000000 +0000 13334@@ -1,1227 +0,0 @@ 13335-// Copyright 2019 The Go Authors. All rights reserved. 13336-// Use of this source code is governed by a BSD-style 13337-// license that can be found in the LICENSE file. 13338- 13339-package cache 13340- 13341-import ( 13342- "context" 13343- "crypto/sha256" 13344- "fmt" 13345- "go/ast" 13346- "go/token" 13347- "go/types" 13348- "log" 13349- "regexp" 13350- "sort" 13351- "strings" 13352- "sync" 13353- 13354- "golang.org/x/mod/module" 13355- "golang.org/x/sync/errgroup" 13356- "golang.org/x/tools/go/ast/astutil" 13357- "golang.org/x/tools/gopls/internal/lsp/filecache" 13358- "golang.org/x/tools/gopls/internal/lsp/protocol" 13359- "golang.org/x/tools/gopls/internal/lsp/source" 13360- "golang.org/x/tools/gopls/internal/lsp/source/methodsets" 13361- "golang.org/x/tools/gopls/internal/lsp/source/xrefs" 13362- "golang.org/x/tools/gopls/internal/span" 13363- "golang.org/x/tools/internal/bug" 13364- "golang.org/x/tools/internal/event" 13365- "golang.org/x/tools/internal/event/tag" 13366- "golang.org/x/tools/internal/gcimporter" 13367- "golang.org/x/tools/internal/memoize" 13368- "golang.org/x/tools/internal/packagesinternal" 13369- "golang.org/x/tools/internal/typeparams" 13370- "golang.org/x/tools/internal/typesinternal" 13371-) 13372- 13373-// A typeCheckBatch holds data for a logical type-checking operation, which may 13374-// type-check many unrelated packages. 13375-// 13376-// It shares state such as parsed files and imports, to optimize type-checking 13377-// for packages with overlapping dependency graphs. 13378-type typeCheckBatch struct { 13379- meta *metadataGraph 13380- 13381- parsedFiles map[span.URI]*source.ParsedGoFile // parsed files necessary for type-checking 13382- fset *token.FileSet // FileSet describing all parsed files 13383- 13384- // Promises holds promises to either read export data for the package, or 13385- // parse and type-check its syntax. 13386- // 13387- // The return value of these promises is not used: after promises are 13388- // awaited, they must write an entry into the imports map. 13389- promises map[PackageID]*memoize.Promise 13390- 13391- mu sync.Mutex 13392- needFiles map[span.URI]source.FileHandle // de-duplicated file handles required for type-checking 13393- imports map[PackageID]pkgOrErr // types.Packages to use for importing 13394- exportData map[PackageID][]byte 13395- packages map[PackageID]*Package 13396-} 13397- 13398-type pkgOrErr struct { 13399- pkg *types.Package 13400- err error 13401-} 13402- 13403-// TypeCheck type-checks the specified packages. 13404-// 13405-// The resulting packages slice always contains len(ids) entries, though some 13406-// of them may be nil if (and only if) the resulting error is non-nil. 13407-// 13408-// An error is returned if any of the requested packages fail to type-check. 13409-// This is different from having type-checking errors: a failure to type-check 13410-// indicates context cancellation or otherwise significant failure to perform 13411-// the type-checking operation. 13412-func (s *snapshot) TypeCheck(ctx context.Context, ids ...PackageID) ([]source.Package, error) { 13413- // Check for existing active packages. 13414- // 13415- // Since gopls can't depend on package identity, any instance of the 13416- // requested package must be ok to return. 13417- // 13418- // This is an optimization to avoid redundant type-checking: following 13419- // changes to an open package many LSP clients send several successive 13420- // requests for package information for the modified package (semantic 13421- // tokens, code lens, inlay hints, etc.) 13422- pkgs := make([]source.Package, len(ids)) 13423- needSyntax := make(map[PackageID]bool) 13424- for i, id := range ids { 13425- if pkg := s.getActivePackage(id); pkg != nil { 13426- pkgs[i] = pkg 13427- } else { 13428- needSyntax[id] = true 13429- } 13430- } 13431- 13432- if len(needSyntax) == 0 { 13433- return pkgs, nil 13434- } 13435- 13436- // Build up shared state for efficient type-checking. 13437- b := &typeCheckBatch{ 13438- parsedFiles: make(map[span.URI]*source.ParsedGoFile), 13439- // fset is built during the parsing pass. 13440- needFiles: make(map[span.URI]source.FileHandle), 13441- 13442- promises: make(map[PackageID]*memoize.Promise), 13443- imports: make(map[PackageID]pkgOrErr), 13444- exportData: make(map[PackageID][]byte), 13445- packages: make(map[PackageID]*Package), 13446- } 13447- 13448- // Capture metadata once to ensure a consistent view. 13449- s.mu.Lock() 13450- b.meta = s.meta 13451- s.mu.Unlock() 13452- 13453- // -- Step 1: assemble the promises graph -- 13454- 13455- var ( 13456- needExportData = make(map[PackageID]packageHandleKey) 13457- packageHandles = make(map[PackageID]*packageHandle) 13458- ) 13459- 13460- // collectPromises collects promises to load packages from export data or 13461- // type-check. 13462- var collectPromises func(PackageID) error 13463- collectPromises = func(id PackageID) error { 13464- if _, ok := b.promises[id]; ok { 13465- return nil 13466- } 13467- b.promises[id] = nil // break cycles 13468- 13469- m := b.meta.metadata[id] 13470- if m == nil { 13471- return bug.Errorf("missing metadata for %v", id) 13472- } 13473- for _, id := range m.DepsByPkgPath { 13474- if err := collectPromises(id); err != nil { 13475- return err 13476- } 13477- } 13478- 13479- // Note that we can't reuse active packages here, as they will have the 13480- // wrong FileSet. Any active packages that exist as dependencies of other 13481- // packages will need to be loaded from export data. 13482- ph, err := s.buildPackageHandle(ctx, id) 13483- if err != nil { 13484- return err 13485- } 13486- packageHandles[id] = ph 13487- 13488- if needSyntax[id] { 13489- // We will need to parse and type-check this package. 13490- // 13491- // We may also need to parse and type-check if export data is missing, 13492- // but that is handled after fetching export data below. 13493- b.addNeededFiles(ph) 13494- } else if id != "unsafe" { // we can't load export data for unsafe 13495- needExportData[id] = ph.key 13496- } 13497- 13498- debugName := fmt.Sprintf("check(%s)", id) 13499- b.promises[id] = memoize.NewPromise(debugName, func(ctx context.Context, _ interface{}) interface{} { 13500- var res pkgOrErr 13501- if err := b.awaitPredecessors(ctx, ph.m); err != nil { 13502- res.err = err 13503- } else { 13504- b.mu.Lock() 13505- data, ok := b.exportData[id] 13506- b.mu.Unlock() 13507- 13508- if ok { 13509- // We need export data, and have it. 13510- res.pkg, res.err = b.importPackage(ctx, m, data) 13511- } else if !needSyntax[id] { 13512- // We need only a types.Package, but don't have export data. 13513- // Type-check as fast as possible (skipping function bodies). 13514- res.pkg, res.err = b.checkPackageForImport(ctx, ph) 13515- } else { 13516- // We need a syntax package. 13517- var pkg *Package 13518- pkg, res.err = b.checkPackage(ctx, ph) 13519- if res.err == nil { 13520- res.pkg = pkg.pkg.types 13521- b.mu.Lock() 13522- b.packages[id] = pkg 13523- b.mu.Unlock() 13524- } 13525- } 13526- } 13527- 13528- b.mu.Lock() 13529- b.imports[m.ID] = res 13530- b.mu.Unlock() 13531- return nil 13532- }) 13533- return nil 13534- } 13535- for id := range needSyntax { 13536- collectPromises(id) 13537- } 13538- 13539- // -- Step 2: collect export data -- 13540- // 13541- // This must be done before parsing in order to determine which files must be 13542- // parsed. 13543- { 13544- var g errgroup.Group 13545- for id, key := range needExportData { 13546- id := id 13547- key := key 13548- g.Go(func() error { 13549- data, err := filecache.Get(exportDataKind, key) 13550- if err != nil { 13551- if err == filecache.ErrNotFound { 13552- ph := packageHandles[id] 13553- b.addNeededFiles(ph) // we will need to parse and type check 13554- return nil // ok: we will type check later 13555- } 13556- return err 13557- } 13558- b.mu.Lock() 13559- b.exportData[id] = data 13560- b.mu.Unlock() 13561- return nil 13562- }) 13563- } 13564- if err := g.Wait(); err != nil { 13565- return pkgs, err 13566- } 13567- } 13568- 13569- // -- Step 3: parse files required for type checking. -- 13570- // 13571- // Parse all necessary files in parallel. Unfortunately we can't start 13572- // parsing each package's file as soon as we discover that it is a syntax 13573- // package, because the parseCache cannot add files to an existing FileSet. 13574- { 13575- var fhs []source.FileHandle 13576- for _, fh := range b.needFiles { 13577- fhs = append(fhs, fh) 13578- } 13579- pgfs, fset, err := s.parseCache.parseFiles(ctx, source.ParseFull, fhs...) 13580- if err != nil { 13581- return pkgs, err 13582- } 13583- for _, pgf := range pgfs { 13584- b.parsedFiles[pgf.URI] = pgf 13585- } 13586- b.fset = fset 13587- } 13588- 13589- // -- Step 4: await type-checking. -- 13590- // 13591- // Start a single goroutine for each promise. 13592- { 13593- var g errgroup.Group 13594- // TODO(rfindley): find a good way to limit concurrency of type-checking, 13595- // which is CPU bound at this point. 13596- // 13597- // (calling g.SetLimit here is mostly ineffective, as promises are 13598- // recursively concurrent.) 13599- for _, promise := range b.promises { 13600- promise := promise 13601- g.Go(func() error { 13602- _, err := promise.Get(ctx, nil) 13603- return err 13604- }) 13605- } 13606- if err := g.Wait(); err != nil { 13607- return pkgs, err 13608- } 13609- } 13610- 13611- // Fill in the gaps of the results slice. 13612- var firstErr error 13613- for i, id := range ids { 13614- if pkgs[i] != nil { 13615- continue 13616- } 13617- if err := b.imports[id].err; err != nil { 13618- if firstErr == nil { 13619- firstErr = err 13620- } 13621- continue 13622- } 13623- pkg := b.packages[id] 13624- if pkg == nil { 13625- panic("nil package") 13626- } 13627- if alt := s.memoizeActivePackage(id, pkg); alt != nil && alt != pkg { 13628- // pkg is an open package, but we've lost a race and an existing package 13629- // has already been memoized. 13630- pkg = alt 13631- } 13632- pkgs[i] = pkg 13633- } 13634- 13635- return pkgs, firstErr 13636-} 13637- 13638-// addNeededFiles records the files necessary for type-checking ph, for later 13639-// parsing. 13640-func (b *typeCheckBatch) addNeededFiles(ph *packageHandle) { 13641- b.mu.Lock() 13642- defer b.mu.Unlock() 13643- 13644- // Technically for export-only packages we only need compiledGoFiles, but 13645- // these slices are usually redundant. 13646- for _, fh := range ph.inputs.goFiles { 13647- b.needFiles[fh.URI()] = fh 13648- } 13649- for _, fh := range ph.inputs.compiledGoFiles { 13650- b.needFiles[fh.URI()] = fh 13651- } 13652-} 13653- 13654-// importPackage loads the given package from its export data in p.exportData 13655-// (which must already be populated). 13656-func (b *typeCheckBatch) importPackage(ctx context.Context, m *source.Metadata, data []byte) (*types.Package, error) { 13657- impMap, errMap := b.importMap(m.ID) 13658- // Any failure to populate an import will cause confusing errors from 13659- // IImportShallow below. 13660- for path, err := range errMap { 13661- return nil, fmt.Errorf("error importing %q for %q: %v", path, m.ID, err) 13662- } 13663- 13664- // TODO(rfindley): collect "deep" hashes here using the provided 13665- // callback, for precise pruning. 13666- imported, err := gcimporter.IImportShallow(b.fset, impMap, data, string(m.PkgPath), func(*types.Package, string) {}) 13667- if err != nil { 13668- return nil, bug.Errorf("invalid export data for %q: %v", m.ID, err) 13669- } 13670- return imported, nil 13671-} 13672- 13673-// checkPackageForImport type checks, but skips function bodies and does not 13674-// record syntax information. 13675-func (b *typeCheckBatch) checkPackageForImport(ctx context.Context, ph *packageHandle) (*types.Package, error) { 13676- if ph.m.ID == "unsafe" { 13677- return types.Unsafe, nil 13678- } 13679- impMap, errMap := b.importMap(ph.inputs.id) 13680- onError := func(e error) { 13681- // Ignore errors for exporting. 13682- } 13683- cfg := b.typesConfig(ph.inputs, onError, impMap, errMap) 13684- var files []*ast.File 13685- for _, fh := range ph.inputs.compiledGoFiles { 13686- pgf := b.parsedFiles[fh.URI()] 13687- if pgf == nil { 13688- return nil, fmt.Errorf("compiled go file %q failed to parse", fh.URI().Filename()) 13689- } 13690- files = append(files, pgf.File) 13691- } 13692- cfg.IgnoreFuncBodies = true 13693- pkg := types.NewPackage(string(ph.inputs.pkgPath), string(ph.inputs.name)) 13694- check := types.NewChecker(cfg, b.fset, pkg, nil) 13695- 13696- _ = check.Files(files) // ignore errors 13697- 13698- // If the context was cancelled, we may have returned a ton of transient 13699- // errors to the type checker. Swallow them. 13700- if ctx.Err() != nil { 13701- return nil, ctx.Err() 13702- } 13703- 13704- // Asynchronously record export data. 13705- go func() { 13706- exportData, err := gcimporter.IExportShallow(b.fset, pkg) 13707- if err != nil { 13708- bug.Reportf("exporting package %v: %v", ph.m.ID, err) 13709- return 13710- } 13711- if err := filecache.Set(exportDataKind, ph.key, exportData); err != nil { 13712- event.Error(ctx, fmt.Sprintf("storing export data for %s", ph.m.ID), err) 13713- } 13714- }() 13715- return pkg, nil 13716-} 13717- 13718-// checkPackage "fully type checks" to produce a syntax package. 13719-func (b *typeCheckBatch) checkPackage(ctx context.Context, ph *packageHandle) (*Package, error) { 13720- // TODO(rfindley): refactor to inline typeCheckImpl here. There is no need 13721- // for so many layers to build up the package 13722- // (checkPackage->typeCheckImpl->doTypeCheck). 13723- pkg, err := typeCheckImpl(ctx, b, ph.inputs) 13724- 13725- if err == nil { 13726- // Write package data to disk asynchronously. 13727- go func() { 13728- toCache := map[string][]byte{ 13729- xrefsKind: pkg.xrefs, 13730- methodSetsKind: pkg.methodsets.Encode(), 13731- diagnosticsKind: encodeDiagnostics(pkg.diagnostics), 13732- } 13733- 13734- if ph.m.ID != "unsafe" { // unsafe cannot be exported 13735- exportData, err := gcimporter.IExportShallow(pkg.fset, pkg.types) 13736- if err != nil { 13737- bug.Reportf("exporting package %v: %v", ph.m.ID, err) 13738- } else { 13739- toCache[exportDataKind] = exportData 13740- } 13741- } 13742- 13743- for kind, data := range toCache { 13744- if err := filecache.Set(kind, ph.key, data); err != nil { 13745- event.Error(ctx, fmt.Sprintf("storing %s data for %s", kind, ph.m.ID), err) 13746- } 13747- } 13748- }() 13749- } 13750- 13751- return &Package{ph.m, pkg}, err 13752-} 13753- 13754-// awaitPredecessors awaits all promises for m.DepsByPkgPath, returning an 13755-// error if awaiting failed due to context cancellation or if there was an 13756-// unrecoverable error loading export data. 13757-func (b *typeCheckBatch) awaitPredecessors(ctx context.Context, m *source.Metadata) error { 13758- for _, depID := range m.DepsByPkgPath { 13759- depID := depID 13760- if p, ok := b.promises[depID]; ok { 13761- if _, err := p.Get(ctx, nil); err != nil { 13762- return err 13763- } 13764- } 13765- } 13766- return nil 13767-} 13768- 13769-// importMap returns an import map for the given package ID, populated with 13770-// type-checked packages for its dependencies. It is intended for compatibility 13771-// with gcimporter.IImportShallow, so the first result uses the map signature 13772-// of that API, where keys are package path strings. 13773-// 13774-// importMap must only be used once all promises for dependencies of id have 13775-// been awaited. 13776-// 13777-// For any missing packages, importMap returns an entry in the resulting errMap 13778-// reporting the error for that package. 13779-// 13780-// Invariant: for all recursive dependencies, either impMap[path] or 13781-// errMap[path] is set. 13782-func (b *typeCheckBatch) importMap(id PackageID) (impMap map[string]*types.Package, errMap map[PackagePath]error) { 13783- impMap = make(map[string]*types.Package) 13784- outerID := id 13785- var populateDepsOf func(m *source.Metadata) 13786- populateDepsOf = func(parent *source.Metadata) { 13787- for _, id := range parent.DepsByPkgPath { 13788- m := b.meta.metadata[id] 13789- if _, ok := impMap[string(m.PkgPath)]; ok { 13790- continue 13791- } 13792- if _, ok := errMap[m.PkgPath]; ok { 13793- continue 13794- } 13795- b.mu.Lock() 13796- result, ok := b.imports[m.ID] 13797- b.mu.Unlock() 13798- if !ok { 13799- panic(fmt.Sprintf("import map for %q missing package data for %q", outerID, m.ID)) 13800- } 13801- // We may fail to produce a package due to e.g. context cancellation 13802- // (handled elsewhere), or some catastrophic failure such as a package with 13803- // no files. 13804- switch { 13805- case result.err != nil: 13806- if errMap == nil { 13807- errMap = make(map[PackagePath]error) 13808- } 13809- errMap[m.PkgPath] = result.err 13810- case result.pkg != nil: 13811- impMap[string(m.PkgPath)] = result.pkg 13812- default: 13813- panic("invalid import for " + id) 13814- } 13815- populateDepsOf(m) 13816- } 13817- } 13818- m := b.meta.metadata[id] 13819- populateDepsOf(m) 13820- return impMap, errMap 13821-} 13822- 13823-// packageData holds binary data (e.g. types, xrefs) extracted from a syntax 13824-// package. 13825-type packageData struct { 13826- m *source.Metadata 13827- data []byte 13828-} 13829- 13830-// getPackageData gets package data (e.g. types, xrefs) for the requested ids, 13831-// either loading from the file-based cache or type-checking and extracting 13832-// data using the provided get function. 13833-func (s *snapshot) getPackageData(ctx context.Context, kind string, ids []PackageID, get func(*syntaxPackage) []byte) ([]*packageData, error) { 13834- var needIDs []PackageID 13835- keys := make([]packageHandleKey, len(ids)) 13836- pkgData := make([]*packageData, len(ids)) 13837- var firstErr error 13838- // Compute package keys and query file cache. 13839- for i, id := range ids { 13840- ph, err := s.buildPackageHandle(ctx, id) 13841- if err != nil { 13842- if firstErr == nil { 13843- firstErr = err 13844- } 13845- if ctx.Err() != nil { 13846- return pkgData, firstErr 13847- } 13848- continue 13849- } 13850- keys[i] = ph.key 13851- data, err := filecache.Get(kind, ph.key) 13852- switch err { 13853- case nil: 13854- pkgData[i] = &packageData{m: ph.m, data: data} 13855- case filecache.ErrNotFound: 13856- needIDs = append(needIDs, id) 13857- default: 13858- if firstErr == nil { 13859- firstErr = err 13860- } 13861- if ctx.Err() != nil { 13862- return pkgData, firstErr 13863- } 13864- } 13865- } 13866- 13867- // Type-check the packages for which we got file-cache misses. 13868- pkgs, err := s.TypeCheck(ctx, needIDs...) 13869- if err != nil { 13870- return nil, err 13871- } 13872- 13873- pkgMap := make(map[PackageID]source.Package) 13874- for i, id := range needIDs { 13875- pkgMap[id] = pkgs[i] 13876- } 13877- 13878- // Fill in the gaps using data derived from type checking. 13879- for i, id := range ids { 13880- if pkgData[i] != nil { 13881- continue 13882- } 13883- result := pkgMap[id] 13884- if result == nil { 13885- panic(fmt.Sprintf("missing type-check result for %s", id)) 13886- } 13887- data := get(result.(*Package).pkg) 13888- pkgData[i] = &packageData{m: result.Metadata(), data: data} 13889- } 13890- 13891- return pkgData, firstErr 13892-} 13893- 13894-type packageHandleKey source.Hash 13895- 13896-// A packageHandle holds package information, some of which may not be fully 13897-// evaluated. 13898-// 13899-// The only methods on packageHandle that are safe to call before calling await 13900-// are Metadata and await itself. 13901-type packageHandle struct { 13902- m *source.Metadata 13903- 13904- inputs typeCheckInputs 13905- 13906- // key is the hashed key for the package. 13907- // 13908- // It includes the all bits of the transitive closure of 13909- // dependencies's sources. This is more than type checking 13910- // really depends on: export data of direct deps should be 13911- // enough. (The key for analysis actions could similarly 13912- // hash only Facts of direct dependencies.) 13913- key packageHandleKey 13914- 13915- // Note: as an optimization, we could join in-flight type-checking by 13916- // recording a transient ref-counted promise here. 13917- // (This was done previously, but proved to be a premature optimization). 13918-} 13919- 13920-// buildPackageHandle returns a handle for the future results of 13921-// type-checking the package identified by id in the given mode. 13922-// It assumes that the given ID already has metadata available, so it does not 13923-// attempt to reload missing or invalid metadata. The caller must reload 13924-// metadata if needed. 13925-func (s *snapshot) buildPackageHandle(ctx context.Context, id PackageID) (*packageHandle, error) { 13926- s.mu.Lock() 13927- entry, hit := s.packages.Get(id) 13928- m := s.meta.metadata[id] 13929- s.mu.Unlock() 13930- 13931- if m == nil { 13932- return nil, fmt.Errorf("no metadata for %s", id) 13933- } 13934- 13935- if hit { 13936- return entry.(*packageHandle), nil 13937- } 13938- 13939- inputs, err := s.typeCheckInputs(ctx, m) 13940- if err != nil { 13941- return nil, err 13942- } 13943- // All the file reading has now been done. 13944- // Create a handle for the result of type checking. 13945- phKey := computePackageKey(s, inputs) 13946- ph := &packageHandle{ 13947- m: m, 13948- inputs: inputs, 13949- key: phKey, 13950- } 13951- 13952- s.mu.Lock() 13953- defer s.mu.Unlock() 13954- 13955- // Check that the metadata has not changed 13956- // (which should invalidate this handle). 13957- // 13958- // (In future, handles should form a graph with edges from a 13959- // packageHandle to the handles for parsing its files and the 13960- // handles for type-checking its immediate deps, at which 13961- // point there will be no need to even access s.meta.) 13962- if s.meta.metadata[ph.m.ID] != ph.m { 13963- // TODO(rfindley): this should be bug.Errorf. 13964- return nil, fmt.Errorf("stale metadata for %s", ph.m.ID) 13965- } 13966- 13967- // Check cache again in case another goroutine got there first. 13968- if prev, ok := s.packages.Get(id); ok { 13969- prevPH := prev.(*packageHandle) 13970- if prevPH.m != ph.m { 13971- return nil, bug.Errorf("existing package handle does not match for %s", ph.m.ID) 13972- } 13973- return prevPH, nil 13974- } 13975- 13976- s.packages.Set(id, ph, nil) 13977- return ph, nil 13978-} 13979- 13980-// typeCheckInputs contains the inputs of a call to typeCheckImpl, which 13981-// type-checks a package. 13982-// 13983-// Part of the purpose of this type is to keep type checking in-sync with the 13984-// package handle key, by explicitly identifying the inputs to type checking. 13985-type typeCheckInputs struct { 13986- id PackageID 13987- 13988- // Used for type checking: 13989- pkgPath PackagePath 13990- name PackageName 13991- goFiles, compiledGoFiles []source.FileHandle 13992- sizes types.Sizes 13993- deps map[PackageID]*packageHandle 13994- depsByImpPath map[ImportPath]PackageID 13995- goVersion string // packages.Module.GoVersion, e.g. "1.18" 13996- 13997- // Used for type check diagnostics: 13998- relatedInformation bool 13999- linkTarget string 14000- moduleMode bool 14001-} 14002- 14003-func (s *snapshot) typeCheckInputs(ctx context.Context, m *source.Metadata) (typeCheckInputs, error) { 14004- deps := make(map[PackageID]*packageHandle) 14005- for _, depID := range m.DepsByPkgPath { 14006- depHandle, err := s.buildPackageHandle(ctx, depID) 14007- if err != nil { 14008- // If err is non-nil, we either have an invalid dependency, or a 14009- // catastrophic failure to read a file (context cancellation or 14010- // permission issues). 14011- // 14012- // We don't want one bad dependency to prevent us from type-checking the 14013- // package -- we should instead get an import error. So we only abort 14014- // this operation if the context is cancelled. 14015- // 14016- // We could do a better job of handling permission errors on files, but 14017- // this is rare, and it is reasonable to treat the same an invalid 14018- // dependency. 14019- event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", m.ID, depID), err, source.SnapshotLabels(s)...) 14020- if ctx.Err() != nil { 14021- return typeCheckInputs{}, ctx.Err() // cancelled 14022- } 14023- continue 14024- } 14025- deps[depID] = depHandle 14026- } 14027- 14028- // Read both lists of files of this package, in parallel. 14029- // 14030- // goFiles aren't presented to the type checker--nor 14031- // are they included in the key, unsoundly--but their 14032- // syntax trees are available from (*pkg).File(URI). 14033- // TODO(adonovan): consider parsing them on demand? 14034- // The need should be rare. 14035- goFiles, compiledGoFiles, err := readGoFiles(ctx, s, m) 14036- if err != nil { 14037- return typeCheckInputs{}, err 14038- } 14039- 14040- goVersion := "" 14041- if m.Module != nil && m.Module.GoVersion != "" { 14042- goVersion = m.Module.GoVersion 14043- } 14044- 14045- return typeCheckInputs{ 14046- id: m.ID, 14047- pkgPath: m.PkgPath, 14048- name: m.Name, 14049- goFiles: goFiles, 14050- compiledGoFiles: compiledGoFiles, 14051- sizes: m.TypesSizes, 14052- deps: deps, 14053- depsByImpPath: m.DepsByImpPath, 14054- goVersion: goVersion, 14055- 14056- relatedInformation: s.view.Options().RelatedInformationSupported, 14057- linkTarget: s.view.Options().LinkTarget, 14058- moduleMode: s.moduleMode(), 14059- }, nil 14060-} 14061- 14062-// readGoFiles reads the content of Metadata.GoFiles and 14063-// Metadata.CompiledGoFiles, in parallel. 14064-func readGoFiles(ctx context.Context, s *snapshot, m *source.Metadata) (goFiles, compiledGoFiles []source.FileHandle, err error) { 14065- var group errgroup.Group 14066- getFileHandles := func(files []span.URI) []source.FileHandle { 14067- fhs := make([]source.FileHandle, len(files)) 14068- for i, uri := range files { 14069- i, uri := i, uri 14070- group.Go(func() (err error) { 14071- fhs[i], err = s.GetFile(ctx, uri) // ~25us 14072- return 14073- }) 14074- } 14075- return fhs 14076- } 14077- return getFileHandles(m.GoFiles), 14078- getFileHandles(m.CompiledGoFiles), 14079- group.Wait() 14080-} 14081- 14082-// computePackageKey returns a key representing the act of type checking 14083-// a package named id containing the specified files, metadata, and 14084-// combined dependency hash. 14085-func computePackageKey(s *snapshot, inputs typeCheckInputs) packageHandleKey { 14086- hasher := sha256.New() 14087- 14088- // In principle, a key must be the hash of an 14089- // unambiguous encoding of all the relevant data. 14090- // If it's ambiguous, we risk collisions. 14091- 14092- // package identifiers 14093- fmt.Fprintf(hasher, "package: %s %s %s\n", inputs.id, inputs.name, inputs.pkgPath) 14094- 14095- // module Go version 14096- fmt.Fprintf(hasher, "go %s\n", inputs.goVersion) 14097- 14098- // import map 14099- importPaths := make([]string, 0, len(inputs.depsByImpPath)) 14100- for impPath := range inputs.depsByImpPath { 14101- importPaths = append(importPaths, string(impPath)) 14102- } 14103- sort.Strings(importPaths) 14104- for _, impPath := range importPaths { 14105- fmt.Fprintf(hasher, "import %s %s", impPath, string(inputs.depsByImpPath[ImportPath(impPath)])) 14106- } 14107- 14108- // deps, in PackageID order 14109- depIDs := make([]string, 0, len(inputs.deps)) 14110- for depID := range inputs.deps { 14111- depIDs = append(depIDs, string(depID)) 14112- } 14113- sort.Strings(depIDs) 14114- for _, depID := range depIDs { 14115- dep := inputs.deps[PackageID(depID)] 14116- fmt.Fprintf(hasher, "dep: %s key:%s\n", dep.m.PkgPath, dep.key) 14117- } 14118- 14119- // file names and contents 14120- fmt.Fprintf(hasher, "compiledGoFiles: %d\n", len(inputs.compiledGoFiles)) 14121- for _, fh := range inputs.compiledGoFiles { 14122- fmt.Fprintln(hasher, fh.FileIdentity()) 14123- } 14124- fmt.Fprintf(hasher, "goFiles: %d\n", len(inputs.goFiles)) 14125- for _, fh := range inputs.goFiles { 14126- fmt.Fprintln(hasher, fh.FileIdentity()) 14127- } 14128- 14129- // types sizes 14130- sz := inputs.sizes.(*types.StdSizes) 14131- fmt.Fprintf(hasher, "sizes: %d %d\n", sz.WordSize, sz.MaxAlign) 14132- 14133- fmt.Fprintf(hasher, "relatedInformation: %t\n", inputs.relatedInformation) 14134- fmt.Fprintf(hasher, "linkTarget: %s\n", inputs.linkTarget) 14135- fmt.Fprintf(hasher, "moduleMode: %t\n", inputs.moduleMode) 14136- 14137- var hash [sha256.Size]byte 14138- hasher.Sum(hash[:0]) 14139- return packageHandleKey(hash) 14140-} 14141- 14142-// typeCheckImpl type checks the parsed source files in compiledGoFiles. 14143-// (The resulting pkg also holds the parsed but not type-checked goFiles.) 14144-// deps holds the future results of type-checking the direct dependencies. 14145-func typeCheckImpl(ctx context.Context, b *typeCheckBatch, inputs typeCheckInputs) (*syntaxPackage, error) { 14146- ctx, done := event.Start(ctx, "cache.typeCheck", tag.Package.Of(string(inputs.id))) 14147- defer done() 14148- 14149- pkg, err := doTypeCheck(ctx, b, inputs) 14150- if err != nil { 14151- return nil, err 14152- } 14153- pkg.methodsets = methodsets.NewIndex(pkg.fset, pkg.types) 14154- pkg.xrefs = xrefs.Index(pkg.compiledGoFiles, pkg.types, pkg.typesInfo) 14155- 14156- // Our heuristic for whether to show type checking errors is: 14157- // + If any file was 'fixed', don't show type checking errors as we 14158- // can't guarantee that they reference accurate locations in the source. 14159- // + If there is a parse error _in the current file_, suppress type 14160- // errors in that file. 14161- // + Otherwise, show type errors even in the presence of parse errors in 14162- // other package files. go/types attempts to suppress follow-on errors 14163- // due to bad syntax, so on balance type checking errors still provide 14164- // a decent signal/noise ratio as long as the file in question parses. 14165- 14166- // Track URIs with parse errors so that we can suppress type errors for these 14167- // files. 14168- unparseable := map[span.URI]bool{} 14169- for _, e := range pkg.parseErrors { 14170- diags, err := parseErrorDiagnostics(pkg, e) 14171- if err != nil { 14172- event.Error(ctx, "unable to compute positions for parse errors", err, tag.Package.Of(string(inputs.id))) 14173- continue 14174- } 14175- for _, diag := range diags { 14176- unparseable[diag.URI] = true 14177- pkg.diagnostics = append(pkg.diagnostics, diag) 14178- } 14179- } 14180- 14181- if pkg.hasFixedFiles { 14182- return pkg, nil 14183- } 14184- 14185- unexpanded := pkg.typeErrors 14186- pkg.typeErrors = nil 14187- for _, e := range expandErrors(unexpanded, inputs.relatedInformation) { 14188- diags, err := typeErrorDiagnostics(inputs.moduleMode, inputs.linkTarget, pkg, e) 14189- if err != nil { 14190- event.Error(ctx, "unable to compute positions for type errors", err, tag.Package.Of(string(inputs.id))) 14191- continue 14192- } 14193- pkg.typeErrors = append(pkg.typeErrors, e.primary) 14194- for _, diag := range diags { 14195- // If the file didn't parse cleanly, it is highly likely that type 14196- // checking errors will be confusing or redundant. But otherwise, type 14197- // checking usually provides a good enough signal to include. 14198- if !unparseable[diag.URI] { 14199- pkg.diagnostics = append(pkg.diagnostics, diag) 14200- } 14201- } 14202- } 14203- 14204- return pkg, nil 14205-} 14206- 14207-var goVersionRx = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) 14208- 14209-func doTypeCheck(ctx context.Context, b *typeCheckBatch, inputs typeCheckInputs) (*syntaxPackage, error) { 14210- impMap, errMap := b.importMap(inputs.id) 14211- pkg := &syntaxPackage{ 14212- id: inputs.id, 14213- fset: b.fset, // must match parse call below 14214- types: types.NewPackage(string(inputs.pkgPath), string(inputs.name)), 14215- typesInfo: &types.Info{ 14216- Types: make(map[ast.Expr]types.TypeAndValue), 14217- Defs: make(map[*ast.Ident]types.Object), 14218- Uses: make(map[*ast.Ident]types.Object), 14219- Implicits: make(map[ast.Node]types.Object), 14220- Selections: make(map[*ast.SelectorExpr]*types.Selection), 14221- Scopes: make(map[ast.Node]*types.Scope), 14222- }, 14223- importMap: impMap, 14224- } 14225- typeparams.InitInstanceInfo(pkg.typesInfo) 14226- 14227- // Collect parsed files from the type check pass, capturing parse errors from 14228- // compiled files. 14229- for _, fh := range inputs.goFiles { 14230- pgf := b.parsedFiles[fh.URI()] 14231- if pgf == nil { 14232- // If go/packages told us that a file is in a package, it should be 14233- // parseable (after all, it was parsed by go list). 14234- return nil, bug.Errorf("go file %q failed to parse", fh.URI().Filename()) 14235- } 14236- pkg.goFiles = append(pkg.goFiles, pgf) 14237- } 14238- for _, fh := range inputs.compiledGoFiles { 14239- pgf := b.parsedFiles[fh.URI()] 14240- if pgf == nil { 14241- return nil, fmt.Errorf("compiled go file %q failed to parse", fh.URI().Filename()) 14242- } 14243- if pgf.ParseErr != nil { 14244- pkg.parseErrors = append(pkg.parseErrors, pgf.ParseErr) 14245- } 14246- pkg.compiledGoFiles = append(pkg.compiledGoFiles, pgf) 14247- } 14248- 14249- // Use the default type information for the unsafe package. 14250- if inputs.pkgPath == "unsafe" { 14251- // Don't type check Unsafe: it's unnecessary, and doing so exposes a data 14252- // race to Unsafe.completed. 14253- pkg.types = types.Unsafe 14254- return pkg, nil 14255- } 14256- 14257- if len(pkg.compiledGoFiles) == 0 { 14258- // No files most likely means go/packages failed. 14259- // 14260- // TODO(rfindley): in the past, we would capture go list errors in this 14261- // case, to present go list errors to the user. However we had no tests for 14262- // this behavior. It is unclear if anything better can be done here. 14263- return nil, fmt.Errorf("no parsed files for package %s", inputs.pkgPath) 14264- } 14265- 14266- onError := func(e error) { 14267- pkg.typeErrors = append(pkg.typeErrors, e.(types.Error)) 14268- } 14269- cfg := b.typesConfig(inputs, onError, impMap, errMap) 14270- 14271- check := types.NewChecker(cfg, pkg.fset, pkg.types, pkg.typesInfo) 14272- 14273- var files []*ast.File 14274- for _, cgf := range pkg.compiledGoFiles { 14275- files = append(files, cgf.File) 14276- } 14277- 14278- // Type checking errors are handled via the config, so ignore them here. 14279- _ = check.Files(files) // 50us-15ms, depending on size of package 14280- 14281- // If the context was cancelled, we may have returned a ton of transient 14282- // errors to the type checker. Swallow them. 14283- if ctx.Err() != nil { 14284- return nil, ctx.Err() 14285- } 14286- return pkg, nil 14287-} 14288- 14289-func (b *typeCheckBatch) typesConfig(inputs typeCheckInputs, onError func(e error), impMap map[string]*types.Package, errMap map[PackagePath]error) *types.Config { 14290- cfg := &types.Config{ 14291- Sizes: inputs.sizes, 14292- Error: onError, 14293- Importer: importerFunc(func(path string) (*types.Package, error) { 14294- // While all of the import errors could be reported 14295- // based on the metadata before we start type checking, 14296- // reporting them via types.Importer places the errors 14297- // at the correct source location. 14298- id, ok := inputs.depsByImpPath[ImportPath(path)] 14299- if !ok { 14300- // If the import declaration is broken, 14301- // go list may fail to report metadata about it. 14302- // See TestFixImportDecl for an example. 14303- return nil, fmt.Errorf("missing metadata for import of %q", path) 14304- } 14305- depPH := inputs.deps[id] 14306- if depPH == nil { 14307- // e.g. missing metadata for dependencies in buildPackageHandle 14308- return nil, missingPkgError(path, inputs.moduleMode) 14309- } 14310- if !source.IsValidImport(inputs.pkgPath, depPH.m.PkgPath) { 14311- return nil, fmt.Errorf("invalid use of internal package %q", path) 14312- } 14313- pkg, ok := impMap[string(depPH.m.PkgPath)] 14314- if !ok { 14315- err := errMap[depPH.m.PkgPath] 14316- if err == nil { 14317- log.Fatalf("neither pkg nor error is set") 14318- } 14319- return nil, err 14320- } 14321- return pkg, nil 14322- }), 14323- } 14324- 14325- if inputs.goVersion != "" { 14326- goVersion := "go" + inputs.goVersion 14327- // types.NewChecker panics if GoVersion is invalid. An unparsable mod 14328- // file should probably stop us before we get here, but double check 14329- // just in case. 14330- if goVersionRx.MatchString(goVersion) { 14331- typesinternal.SetGoVersion(cfg, goVersion) 14332- } 14333- } 14334- 14335- // We want to type check cgo code if go/types supports it. 14336- // We passed typecheckCgo to go/packages when we Loaded. 14337- typesinternal.SetUsesCgo(cfg) 14338- return cfg 14339-} 14340- 14341-// depsErrors creates diagnostics for each metadata error (e.g. import cycle). 14342-// These may be attached to import declarations in the transitive source files 14343-// of pkg, or to 'requires' declarations in the package's go.mod file. 14344-// 14345-// TODO(rfindley): move this to load.go 14346-func depsErrors(ctx context.Context, m *source.Metadata, meta *metadataGraph, fs source.FileSource, workspacePackages map[PackageID]PackagePath) ([]*source.Diagnostic, error) { 14347- // Select packages that can't be found, and were imported in non-workspace packages. 14348- // Workspace packages already show their own errors. 14349- var relevantErrors []*packagesinternal.PackageError 14350- for _, depsError := range m.DepsErrors { 14351- // Up to Go 1.15, the missing package was included in the stack, which 14352- // was presumably a bug. We want the next one up. 14353- directImporterIdx := len(depsError.ImportStack) - 1 14354- if directImporterIdx < 0 { 14355- continue 14356- } 14357- 14358- directImporter := depsError.ImportStack[directImporterIdx] 14359- if _, ok := workspacePackages[PackageID(directImporter)]; ok { 14360- continue 14361- } 14362- relevantErrors = append(relevantErrors, depsError) 14363- } 14364- 14365- // Don't build the import index for nothing. 14366- if len(relevantErrors) == 0 { 14367- return nil, nil 14368- } 14369- 14370- // Subsequent checks require Go files. 14371- if len(m.CompiledGoFiles) == 0 { 14372- return nil, nil 14373- } 14374- 14375- // Build an index of all imports in the package. 14376- type fileImport struct { 14377- cgf *source.ParsedGoFile 14378- imp *ast.ImportSpec 14379- } 14380- allImports := map[string][]fileImport{} 14381- for _, uri := range m.CompiledGoFiles { 14382- pgf, err := parseGoURI(ctx, fs, uri, source.ParseHeader) 14383- if err != nil { 14384- return nil, err 14385- } 14386- fset := source.FileSetFor(pgf.Tok) 14387- // TODO(adonovan): modify Imports() to accept a single token.File (cgf.Tok). 14388- for _, group := range astutil.Imports(fset, pgf.File) { 14389- for _, imp := range group { 14390- if imp.Path == nil { 14391- continue 14392- } 14393- path := strings.Trim(imp.Path.Value, `"`) 14394- allImports[path] = append(allImports[path], fileImport{pgf, imp}) 14395- } 14396- } 14397- } 14398- 14399- // Apply a diagnostic to any import involved in the error, stopping once 14400- // we reach the workspace. 14401- var errors []*source.Diagnostic 14402- for _, depErr := range relevantErrors { 14403- for i := len(depErr.ImportStack) - 1; i >= 0; i-- { 14404- item := depErr.ImportStack[i] 14405- if _, ok := workspacePackages[PackageID(item)]; ok { 14406- break 14407- } 14408- 14409- for _, imp := range allImports[item] { 14410- rng, err := imp.cgf.NodeRange(imp.imp) 14411- if err != nil { 14412- return nil, err 14413- } 14414- fixes, err := goGetQuickFixes(m.Module != nil, imp.cgf.URI, item) 14415- if err != nil { 14416- return nil, err 14417- } 14418- errors = append(errors, &source.Diagnostic{ 14419- URI: imp.cgf.URI, 14420- Range: rng, 14421- Severity: protocol.SeverityError, 14422- Source: source.TypeError, 14423- Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err), 14424- SuggestedFixes: fixes, 14425- }) 14426- } 14427- } 14428- } 14429- 14430- modFile, err := nearestModFile(ctx, m.CompiledGoFiles[0], fs) 14431- if err != nil { 14432- return nil, err 14433- } 14434- pm, err := parseModURI(ctx, fs, modFile) 14435- if err != nil { 14436- return nil, err 14437- } 14438- 14439- // Add a diagnostic to the module that contained the lowest-level import of 14440- // the missing package. 14441- for _, depErr := range relevantErrors { 14442- for i := len(depErr.ImportStack) - 1; i >= 0; i-- { 14443- item := depErr.ImportStack[i] 14444- m := meta.metadata[PackageID(item)] 14445- if m == nil || m.Module == nil { 14446- continue 14447- } 14448- modVer := module.Version{Path: m.Module.Path, Version: m.Module.Version} 14449- reference := findModuleReference(pm.File, modVer) 14450- if reference == nil { 14451- continue 14452- } 14453- rng, err := pm.Mapper.OffsetRange(reference.Start.Byte, reference.End.Byte) 14454- if err != nil { 14455- return nil, err 14456- } 14457- fixes, err := goGetQuickFixes(true, pm.URI, item) 14458- if err != nil { 14459- return nil, err 14460- } 14461- errors = append(errors, &source.Diagnostic{ 14462- URI: pm.URI, 14463- Range: rng, 14464- Severity: protocol.SeverityError, 14465- Source: source.TypeError, 14466- Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err), 14467- SuggestedFixes: fixes, 14468- }) 14469- break 14470- } 14471- } 14472- return errors, nil 14473-} 14474- 14475-// missingPkgError returns an error message for a missing package that varies 14476-// based on the user's workspace mode. 14477-func missingPkgError(pkgPath string, moduleMode bool) error { 14478- // TODO(rfindley): improve this error. Previous versions of this error had 14479- // access to the full snapshot, and could provide more information (such as 14480- // the initialization error). 14481- if moduleMode { 14482- // Previously, we would present the initialization error here. 14483- return fmt.Errorf("no required module provides package %q", pkgPath) 14484- } else { 14485- // Previously, we would list the directories in GOROOT and GOPATH here. 14486- return fmt.Errorf("cannot find package %q in GOROOT or GOPATH", pkgPath) 14487- } 14488-} 14489- 14490-type extendedError struct { 14491- primary types.Error 14492- secondaries []types.Error 14493-} 14494- 14495-func (e extendedError) Error() string { 14496- return e.primary.Error() 14497-} 14498- 14499-// expandErrors duplicates "secondary" errors by mapping them to their main 14500-// error. Some errors returned by the type checker are followed by secondary 14501-// errors which give more information about the error. These are errors in 14502-// their own right, and they are marked by starting with \t. For instance, when 14503-// there is a multiply-defined function, the secondary error points back to the 14504-// definition first noticed. 14505-// 14506-// This function associates the secondary error with its primary error, which can 14507-// then be used as RelatedInformation when the error becomes a diagnostic. 14508-// 14509-// If supportsRelatedInformation is false, the secondary is instead embedded as 14510-// additional context in the primary error. 14511-func expandErrors(errs []types.Error, supportsRelatedInformation bool) []extendedError { 14512- var result []extendedError 14513- for i := 0; i < len(errs); { 14514- original := extendedError{ 14515- primary: errs[i], 14516- } 14517- for i++; i < len(errs); i++ { 14518- spl := errs[i] 14519- if len(spl.Msg) == 0 || spl.Msg[0] != '\t' { 14520- break 14521- } 14522- spl.Msg = spl.Msg[1:] 14523- original.secondaries = append(original.secondaries, spl) 14524- } 14525- 14526- // Clone the error to all its related locations -- VS Code, at least, 14527- // doesn't do it for us. 14528- result = append(result, original) 14529- for i, mainSecondary := range original.secondaries { 14530- // Create the new primary error, with a tweaked message, in the 14531- // secondary's location. We need to start from the secondary to 14532- // capture its unexported location fields. 14533- relocatedSecondary := mainSecondary 14534- if supportsRelatedInformation { 14535- relocatedSecondary.Msg = fmt.Sprintf("%v (see details)", original.primary.Msg) 14536- } else { 14537- relocatedSecondary.Msg = fmt.Sprintf("%v (this error: %v)", original.primary.Msg, mainSecondary.Msg) 14538- } 14539- relocatedSecondary.Soft = original.primary.Soft 14540- 14541- // Copy over the secondary errors, noting the location of the 14542- // current error we're cloning. 14543- clonedError := extendedError{primary: relocatedSecondary, secondaries: []types.Error{original.primary}} 14544- for j, secondary := range original.secondaries { 14545- if i == j { 14546- secondary.Msg += " (this error)" 14547- } 14548- clonedError.secondaries = append(clonedError.secondaries, secondary) 14549- } 14550- result = append(result, clonedError) 14551- } 14552- 14553- } 14554- return result 14555-} 14556- 14557-// An importFunc is an implementation of the single-method 14558-// types.Importer interface based on a function value. 14559-type importerFunc func(path string) (*types.Package, error) 14560- 14561-func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } 14562diff -urN a/gopls/internal/lsp/cache/debug.go b/gopls/internal/lsp/cache/debug.go 14563--- a/gopls/internal/lsp/cache/debug.go 2000-01-01 00:00:00.000000000 -0000 14564+++ b/gopls/internal/lsp/cache/debug.go 1970-01-01 00:00:00.000000000 +0000 14565@@ -1,55 +0,0 @@ 14566-// Copyright 2022 The Go Authors. All rights reserved. 14567-// Use of this source code is governed by a BSD-style 14568-// license that can be found in the LICENSE file. 14569- 14570-package cache 14571- 14572-import ( 14573- "fmt" 14574- "os" 14575- "sort" 14576-) 14577- 14578-// This file contains helpers that can be used to instrument code while 14579-// debugging. 14580- 14581-// debugEnabled toggles the helpers below. 14582-const debugEnabled = false 14583- 14584-// If debugEnabled is true, debugf formats its arguments and prints to stderr. 14585-// If debugEnabled is false, it is a no-op. 14586-func debugf(format string, args ...interface{}) { 14587- if !debugEnabled { 14588- return 14589- } 14590- if false { 14591- _ = fmt.Sprintf(format, args...) // encourage vet to validate format strings 14592- } 14593- fmt.Fprintf(os.Stderr, ">>> "+format+"\n", args...) 14594-} 14595- 14596-// If debugEnabled is true, dumpWorkspace prints a summary of workspace 14597-// packages to stderr. If debugEnabled is false, it is a no-op. 14598-// 14599-// TODO(rfindley): this has served its purpose. Delete. 14600-func (s *snapshot) dumpWorkspace(context string) { 14601- if !debugEnabled { 14602- return 14603- } 14604- 14605- debugf("workspace (after %s):", context) 14606- var ids []PackageID 14607- for id := range s.workspacePackages { 14608- ids = append(ids, id) 14609- } 14610- 14611- sort.Slice(ids, func(i, j int) bool { 14612- return ids[i] < ids[j] 14613- }) 14614- 14615- for _, id := range ids { 14616- pkgPath := s.workspacePackages[id] 14617- _, ok := s.meta.metadata[id] 14618- debugf(" %s:%s (metadata: %t)", id, pkgPath, ok) 14619- } 14620-} 14621diff -urN a/gopls/internal/lsp/cache/errors.go b/gopls/internal/lsp/cache/errors.go 14622--- a/gopls/internal/lsp/cache/errors.go 2000-01-01 00:00:00.000000000 -0000 14623+++ b/gopls/internal/lsp/cache/errors.go 1970-01-01 00:00:00.000000000 +0000 14624@@ -1,528 +0,0 @@ 14625-// Copyright 2019 The Go Authors. All rights reserved. 14626-// Use of this source code is governed by a BSD-style 14627-// license that can be found in the LICENSE file. 14628- 14629-package cache 14630- 14631-// This file defines routines to convert diagnostics from go list, go 14632-// get, go/packages, parsing, type checking, and analysis into 14633-// source.Diagnostic form, and suggesting quick fixes. 14634- 14635-import ( 14636- "context" 14637- "fmt" 14638- "go/scanner" 14639- "go/token" 14640- "go/types" 14641- "log" 14642- "regexp" 14643- "strconv" 14644- "strings" 14645- 14646- "golang.org/x/tools/go/packages" 14647- "golang.org/x/tools/gopls/internal/lsp/command" 14648- "golang.org/x/tools/gopls/internal/lsp/protocol" 14649- "golang.org/x/tools/gopls/internal/lsp/safetoken" 14650- "golang.org/x/tools/gopls/internal/lsp/source" 14651- "golang.org/x/tools/gopls/internal/span" 14652- "golang.org/x/tools/internal/analysisinternal" 14653- "golang.org/x/tools/internal/bug" 14654- "golang.org/x/tools/internal/typesinternal" 14655-) 14656- 14657-// goPackagesErrorDiagnostics translates the given go/packages Error into a 14658-// diagnostic, using the provided metadata and filesource. 14659-// 14660-// The slice of diagnostics may be empty. 14661-func goPackagesErrorDiagnostics(ctx context.Context, e packages.Error, m *source.Metadata, fs source.FileSource) ([]*source.Diagnostic, error) { 14662- if diag, err := parseGoListImportCycleError(ctx, e, m, fs); err != nil { 14663- return nil, err 14664- } else if diag != nil { 14665- return []*source.Diagnostic{diag}, nil 14666- } 14667- 14668- var spn span.Span 14669- if e.Pos == "" { 14670- spn = parseGoListError(e.Msg, m.LoadDir) 14671- // We may not have been able to parse a valid span. Apply the errors to all files. 14672- if _, err := spanToRange(ctx, fs, spn); err != nil { 14673- var diags []*source.Diagnostic 14674- for _, uri := range m.CompiledGoFiles { 14675- diags = append(diags, &source.Diagnostic{ 14676- URI: uri, 14677- Severity: protocol.SeverityError, 14678- Source: source.ListError, 14679- Message: e.Msg, 14680- }) 14681- } 14682- return diags, nil 14683- } 14684- } else { 14685- spn = span.ParseInDir(e.Pos, m.LoadDir) 14686- } 14687- 14688- // TODO(rfindley): in some cases the go command outputs invalid spans, for 14689- // example (from TestGoListErrors): 14690- // 14691- // package a 14692- // import 14693- // 14694- // In this case, the go command will complain about a.go:2:8, which is after 14695- // the trailing newline but still considered to be on the second line, most 14696- // likely because *token.File lacks information about newline termination. 14697- // 14698- // We could do better here by handling that case. 14699- rng, err := spanToRange(ctx, fs, spn) 14700- if err != nil { 14701- return nil, err 14702- } 14703- return []*source.Diagnostic{{ 14704- URI: spn.URI(), 14705- Range: rng, 14706- Severity: protocol.SeverityError, 14707- Source: source.ListError, 14708- Message: e.Msg, 14709- }}, nil 14710-} 14711- 14712-func parseErrorDiagnostics(pkg *syntaxPackage, errList scanner.ErrorList) ([]*source.Diagnostic, error) { 14713- // The first parser error is likely the root cause of the problem. 14714- if errList.Len() <= 0 { 14715- return nil, fmt.Errorf("no errors in %v", errList) 14716- } 14717- e := errList[0] 14718- pgf, err := pkg.File(span.URIFromPath(e.Pos.Filename)) 14719- if err != nil { 14720- return nil, err 14721- } 14722- rng, err := pgf.Mapper.OffsetRange(e.Pos.Offset, e.Pos.Offset) 14723- if err != nil { 14724- return nil, err 14725- } 14726- return []*source.Diagnostic{{ 14727- URI: pgf.URI, 14728- Range: rng, 14729- Severity: protocol.SeverityError, 14730- Source: source.ParseError, 14731- Message: e.Msg, 14732- }}, nil 14733-} 14734- 14735-var importErrorRe = regexp.MustCompile(`could not import ([^\s]+)`) 14736-var unsupportedFeatureRe = regexp.MustCompile(`.*require.* go(\d+\.\d+) or later`) 14737- 14738-func typeErrorDiagnostics(moduleMode bool, linkTarget string, pkg *syntaxPackage, e extendedError) ([]*source.Diagnostic, error) { 14739- code, loc, err := typeErrorData(pkg, e.primary) 14740- if err != nil { 14741- return nil, err 14742- } 14743- diag := &source.Diagnostic{ 14744- URI: loc.URI.SpanURI(), 14745- Range: loc.Range, 14746- Severity: protocol.SeverityError, 14747- Source: source.TypeError, 14748- Message: e.primary.Msg, 14749- } 14750- if code != 0 { 14751- diag.Code = code.String() 14752- diag.CodeHref = typesCodeHref(linkTarget, code) 14753- } 14754- switch code { 14755- case typesinternal.UnusedVar, typesinternal.UnusedImport: 14756- diag.Tags = append(diag.Tags, protocol.Unnecessary) 14757- } 14758- 14759- for _, secondary := range e.secondaries { 14760- _, secondaryLoc, err := typeErrorData(pkg, secondary) 14761- if err != nil { 14762- return nil, err 14763- } 14764- diag.Related = append(diag.Related, protocol.DiagnosticRelatedInformation{ 14765- Location: secondaryLoc, 14766- Message: secondary.Msg, 14767- }) 14768- } 14769- 14770- if match := importErrorRe.FindStringSubmatch(e.primary.Msg); match != nil { 14771- diag.SuggestedFixes, err = goGetQuickFixes(moduleMode, loc.URI.SpanURI(), match[1]) 14772- if err != nil { 14773- return nil, err 14774- } 14775- } 14776- if match := unsupportedFeatureRe.FindStringSubmatch(e.primary.Msg); match != nil { 14777- diag.SuggestedFixes, err = editGoDirectiveQuickFix(moduleMode, loc.URI.SpanURI(), match[1]) 14778- if err != nil { 14779- return nil, err 14780- } 14781- } 14782- return []*source.Diagnostic{diag}, nil 14783-} 14784- 14785-func goGetQuickFixes(moduleMode bool, uri span.URI, pkg string) ([]source.SuggestedFix, error) { 14786- // Go get only supports module mode for now. 14787- if !moduleMode { 14788- return nil, nil 14789- } 14790- title := fmt.Sprintf("go get package %v", pkg) 14791- cmd, err := command.NewGoGetPackageCommand(title, command.GoGetPackageArgs{ 14792- URI: protocol.URIFromSpanURI(uri), 14793- AddRequire: true, 14794- Pkg: pkg, 14795- }) 14796- if err != nil { 14797- return nil, err 14798- } 14799- return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, nil 14800-} 14801- 14802-func editGoDirectiveQuickFix(moduleMode bool, uri span.URI, version string) ([]source.SuggestedFix, error) { 14803- // Go mod edit only supports module mode. 14804- if !moduleMode { 14805- return nil, nil 14806- } 14807- title := fmt.Sprintf("go mod edit -go=%s", version) 14808- cmd, err := command.NewEditGoDirectiveCommand(title, command.EditGoDirectiveArgs{ 14809- URI: protocol.URIFromSpanURI(uri), 14810- Version: version, 14811- }) 14812- if err != nil { 14813- return nil, err 14814- } 14815- return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, nil 14816-} 14817- 14818-// encodeDiagnostics gob-encodes the given diagnostics. 14819-func encodeDiagnostics(srcDiags []*source.Diagnostic) []byte { 14820- var gobDiags []gobDiagnostic 14821- for _, srcDiag := range srcDiags { 14822- var gobFixes []gobSuggestedFix 14823- for _, srcFix := range srcDiag.SuggestedFixes { 14824- gobFix := gobSuggestedFix{ 14825- Message: srcFix.Title, 14826- ActionKind: srcFix.ActionKind, 14827- } 14828- for uri, srcEdits := range srcFix.Edits { 14829- for _, srcEdit := range srcEdits { 14830- gobFix.TextEdits = append(gobFix.TextEdits, gobTextEdit{ 14831- Location: protocol.Location{ 14832- URI: protocol.URIFromSpanURI(uri), 14833- Range: srcEdit.Range, 14834- }, 14835- NewText: []byte(srcEdit.NewText), 14836- }) 14837- } 14838- } 14839- if srcCmd := srcFix.Command; srcCmd != nil { 14840- gobFix.Command = &gobCommand{ 14841- Title: srcCmd.Title, 14842- Command: srcCmd.Command, 14843- Arguments: srcCmd.Arguments, 14844- } 14845- } 14846- gobFixes = append(gobFixes, gobFix) 14847- } 14848- var gobRelated []gobRelatedInformation 14849- for _, srcRel := range srcDiag.Related { 14850- gobRel := gobRelatedInformation(srcRel) 14851- gobRelated = append(gobRelated, gobRel) 14852- } 14853- gobDiag := gobDiagnostic{ 14854- Location: protocol.Location{ 14855- URI: protocol.URIFromSpanURI(srcDiag.URI), 14856- Range: srcDiag.Range, 14857- }, 14858- Severity: srcDiag.Severity, 14859- Code: srcDiag.Code, 14860- CodeHref: srcDiag.CodeHref, 14861- Source: string(srcDiag.Source), 14862- Message: srcDiag.Message, 14863- SuggestedFixes: gobFixes, 14864- Related: gobRelated, 14865- Tags: srcDiag.Tags, 14866- } 14867- gobDiags = append(gobDiags, gobDiag) 14868- } 14869- return mustEncode(gobDiags) 14870-} 14871- 14872-// decodeDiagnostics decodes the given gob-encoded diagnostics. 14873-func decodeDiagnostics(data []byte) []*source.Diagnostic { 14874- var gobDiags []gobDiagnostic 14875- mustDecode(data, &gobDiags) 14876- var srcDiags []*source.Diagnostic 14877- for _, gobDiag := range gobDiags { 14878- var srcFixes []source.SuggestedFix 14879- for _, gobFix := range gobDiag.SuggestedFixes { 14880- srcFix := source.SuggestedFix{ 14881- Title: gobFix.Message, 14882- ActionKind: gobFix.ActionKind, 14883- } 14884- for _, gobEdit := range gobFix.TextEdits { 14885- if srcFix.Edits == nil { 14886- srcFix.Edits = make(map[span.URI][]protocol.TextEdit) 14887- } 14888- srcEdit := protocol.TextEdit{ 14889- Range: gobEdit.Location.Range, 14890- NewText: string(gobEdit.NewText), 14891- } 14892- uri := gobEdit.Location.URI.SpanURI() 14893- srcFix.Edits[uri] = append(srcFix.Edits[uri], srcEdit) 14894- } 14895- if gobCmd := gobFix.Command; gobCmd != nil { 14896- gobFix.Command = &gobCommand{ 14897- Title: gobCmd.Title, 14898- Command: gobCmd.Command, 14899- Arguments: gobCmd.Arguments, 14900- } 14901- } 14902- srcFixes = append(srcFixes, srcFix) 14903- } 14904- var srcRelated []protocol.DiagnosticRelatedInformation 14905- for _, gobRel := range gobDiag.Related { 14906- srcRel := protocol.DiagnosticRelatedInformation(gobRel) 14907- srcRelated = append(srcRelated, srcRel) 14908- } 14909- srcDiag := &source.Diagnostic{ 14910- URI: gobDiag.Location.URI.SpanURI(), 14911- Range: gobDiag.Location.Range, 14912- Severity: gobDiag.Severity, 14913- Source: source.AnalyzerErrorKind(gobDiag.Source), 14914- Message: gobDiag.Message, 14915- Tags: gobDiag.Tags, 14916- Related: srcRelated, 14917- SuggestedFixes: srcFixes, 14918- } 14919- srcDiags = append(srcDiags, srcDiag) 14920- } 14921- return srcDiags 14922-} 14923- 14924-// toSourceDiagnostic converts a gobDiagnostic to "source" form. 14925-func toSourceDiagnostic(srcAnalyzer *source.Analyzer, gobDiag *gobDiagnostic) *source.Diagnostic { 14926- var related []protocol.DiagnosticRelatedInformation 14927- for _, gobRelated := range gobDiag.Related { 14928- related = append(related, protocol.DiagnosticRelatedInformation(gobRelated)) 14929- } 14930- 14931- kinds := srcAnalyzer.ActionKind 14932- if len(srcAnalyzer.ActionKind) == 0 { 14933- kinds = append(kinds, protocol.QuickFix) 14934- } 14935- fixes := suggestedAnalysisFixes(gobDiag, kinds) 14936- if srcAnalyzer.Fix != "" { 14937- cmd, err := command.NewApplyFixCommand(gobDiag.Message, command.ApplyFixArgs{ 14938- URI: gobDiag.Location.URI, 14939- Range: gobDiag.Location.Range, 14940- Fix: srcAnalyzer.Fix, 14941- }) 14942- if err != nil { 14943- // JSON marshalling of these argument values cannot fail. 14944- log.Fatalf("internal error in NewApplyFixCommand: %v", err) 14945- } 14946- for _, kind := range kinds { 14947- fixes = append(fixes, source.SuggestedFixFromCommand(cmd, kind)) 14948- } 14949- } 14950- 14951- severity := srcAnalyzer.Severity 14952- if severity == 0 { 14953- severity = protocol.SeverityWarning 14954- } 14955- 14956- diag := &source.Diagnostic{ 14957- URI: gobDiag.Location.URI.SpanURI(), 14958- Range: gobDiag.Location.Range, 14959- Severity: severity, 14960- Source: source.AnalyzerErrorKind(gobDiag.Source), 14961- Message: gobDiag.Message, 14962- Related: related, 14963- SuggestedFixes: fixes, 14964- } 14965- // If the fixes only delete code, assume that the diagnostic is reporting dead code. 14966- if onlyDeletions(fixes) { 14967- diag.Tags = []protocol.DiagnosticTag{protocol.Unnecessary} 14968- } 14969- return diag 14970-} 14971- 14972-// onlyDeletions returns true if all of the suggested fixes are deletions. 14973-func onlyDeletions(fixes []source.SuggestedFix) bool { 14974- for _, fix := range fixes { 14975- if fix.Command != nil { 14976- return false 14977- } 14978- for _, edits := range fix.Edits { 14979- for _, edit := range edits { 14980- if edit.NewText != "" { 14981- return false 14982- } 14983- if protocol.ComparePosition(edit.Range.Start, edit.Range.End) == 0 { 14984- return false 14985- } 14986- } 14987- } 14988- } 14989- return len(fixes) > 0 14990-} 14991- 14992-func typesCodeHref(linkTarget string, code typesinternal.ErrorCode) string { 14993- return source.BuildLink(linkTarget, "golang.org/x/tools/internal/typesinternal", code.String()) 14994-} 14995- 14996-func suggestedAnalysisFixes(diag *gobDiagnostic, kinds []protocol.CodeActionKind) []source.SuggestedFix { 14997- var fixes []source.SuggestedFix 14998- for _, fix := range diag.SuggestedFixes { 14999- edits := make(map[span.URI][]protocol.TextEdit) 15000- for _, e := range fix.TextEdits { 15001- uri := span.URI(e.Location.URI) 15002- edits[uri] = append(edits[uri], protocol.TextEdit{ 15003- Range: e.Location.Range, 15004- NewText: string(e.NewText), 15005- }) 15006- } 15007- for _, kind := range kinds { 15008- fixes = append(fixes, source.SuggestedFix{ 15009- Title: fix.Message, 15010- Edits: edits, 15011- ActionKind: kind, 15012- }) 15013- } 15014- 15015- } 15016- return fixes 15017-} 15018- 15019-func typeErrorData(pkg *syntaxPackage, terr types.Error) (typesinternal.ErrorCode, protocol.Location, error) { 15020- ecode, start, end, ok := typesinternal.ReadGo116ErrorData(terr) 15021- if !ok { 15022- start, end = terr.Pos, terr.Pos 15023- ecode = 0 15024- } 15025- // go/types may return invalid positions in some cases, such as 15026- // in errors on tokens missing from the syntax tree. 15027- if !start.IsValid() { 15028- return 0, protocol.Location{}, fmt.Errorf("type error (%q, code %d, go116=%t) without position", terr.Msg, ecode, ok) 15029- } 15030- // go/types errors retain their FileSet. 15031- // Sanity-check that we're using the right one. 15032- fset := pkg.fset 15033- if fset != terr.Fset { 15034- return 0, protocol.Location{}, bug.Errorf("wrong FileSet for type error") 15035- } 15036- posn := safetoken.StartPosition(fset, start) 15037- if !posn.IsValid() { 15038- return 0, protocol.Location{}, fmt.Errorf("position %d of type error %q (code %q) not found in FileSet", start, start, terr) 15039- } 15040- pgf, err := pkg.File(span.URIFromPath(posn.Filename)) 15041- if err != nil { 15042- return 0, protocol.Location{}, err 15043- } 15044- if !end.IsValid() || end == start { 15045- end = analysisinternal.TypeErrorEndPos(fset, pgf.Src, start) 15046- } 15047- loc, err := pgf.Mapper.PosLocation(pgf.Tok, start, end) 15048- return ecode, loc, err 15049-} 15050- 15051-// spanToRange converts a span.Span to a protocol.Range, by mapping content 15052-// contained in the provided FileSource. 15053-func spanToRange(ctx context.Context, fs source.FileSource, spn span.Span) (protocol.Range, error) { 15054- uri := spn.URI() 15055- fh, err := fs.GetFile(ctx, uri) 15056- if err != nil { 15057- return protocol.Range{}, err 15058- } 15059- content, err := fh.Read() 15060- if err != nil { 15061- return protocol.Range{}, err 15062- } 15063- mapper := protocol.NewMapper(uri, content) 15064- return mapper.SpanRange(spn) 15065-} 15066- 15067-// parseGoListError attempts to parse a standard `go list` error message 15068-// by stripping off the trailing error message. 15069-// 15070-// It works only on errors whose message is prefixed by colon, 15071-// followed by a space (": "). For example: 15072-// 15073-// attributes.go:13:1: expected 'package', found 'type' 15074-func parseGoListError(input, wd string) span.Span { 15075- input = strings.TrimSpace(input) 15076- msgIndex := strings.Index(input, ": ") 15077- if msgIndex < 0 { 15078- return span.Parse(input) 15079- } 15080- return span.ParseInDir(input[:msgIndex], wd) 15081-} 15082- 15083-// parseGoListImportCycleError attempts to parse the given go/packages error as 15084-// an import cycle, returning a diagnostic if successful. 15085-// 15086-// If the error is not detected as an import cycle error, it returns nil, nil. 15087-func parseGoListImportCycleError(ctx context.Context, e packages.Error, m *source.Metadata, fs source.FileSource) (*source.Diagnostic, error) { 15088- re := regexp.MustCompile(`(.*): import stack: \[(.+)\]`) 15089- matches := re.FindStringSubmatch(strings.TrimSpace(e.Msg)) 15090- if len(matches) < 3 { 15091- return nil, nil 15092- } 15093- msg := matches[1] 15094- importList := strings.Split(matches[2], " ") 15095- // Since the error is relative to the current package. The import that is causing 15096- // the import cycle error is the second one in the list. 15097- if len(importList) < 2 { 15098- return nil, nil 15099- } 15100- // Imports have quotation marks around them. 15101- circImp := strconv.Quote(importList[1]) 15102- for _, uri := range m.CompiledGoFiles { 15103- pgf, err := parseGoURI(ctx, fs, uri, source.ParseHeader) 15104- if err != nil { 15105- return nil, err 15106- } 15107- // Search file imports for the import that is causing the import cycle. 15108- for _, imp := range pgf.File.Imports { 15109- if imp.Path.Value == circImp { 15110- rng, err := pgf.NodeMappedRange(imp) 15111- if err != nil { 15112- return nil, nil 15113- } 15114- 15115- return &source.Diagnostic{ 15116- URI: pgf.URI, 15117- Range: rng.Range(), 15118- Severity: protocol.SeverityError, 15119- Source: source.ListError, 15120- Message: msg, 15121- }, nil 15122- } 15123- } 15124- } 15125- return nil, nil 15126-} 15127- 15128-// parseGoURI is a helper to parse the Go file at the given URI from the file 15129-// source fs. The resulting syntax and token.File belong to an ephemeral, 15130-// encapsulated FileSet, so this file stands only on its own: it's not suitable 15131-// to use in a list of file of a package, for example. 15132-// 15133-// It returns an error if the file could not be read. 15134-func parseGoURI(ctx context.Context, fs source.FileSource, uri span.URI, mode source.ParseMode) (*source.ParsedGoFile, error) { 15135- fh, err := fs.GetFile(ctx, uri) 15136- if err != nil { 15137- return nil, err 15138- } 15139- return parseGoImpl(ctx, token.NewFileSet(), fh, source.ParseHeader) 15140-} 15141- 15142-// parseModURI is a helper to parse the Mod file at the given URI from the file 15143-// source fs. 15144-// 15145-// It returns an error if the file could not be read. 15146-func parseModURI(ctx context.Context, fs source.FileSource, uri span.URI) (*source.ParsedModule, error) { 15147- fh, err := fs.GetFile(ctx, uri) 15148- if err != nil { 15149- return nil, err 15150- } 15151- return parseModImpl(ctx, fh) 15152-} 15153diff -urN a/gopls/internal/lsp/cache/errors_test.go b/gopls/internal/lsp/cache/errors_test.go 15154--- a/gopls/internal/lsp/cache/errors_test.go 2000-01-01 00:00:00.000000000 -0000 15155+++ b/gopls/internal/lsp/cache/errors_test.go 1970-01-01 00:00:00.000000000 +0000 15156@@ -1,52 +0,0 @@ 15157-// Copyright 2019 The Go Authors. All rights reserved. 15158-// Use of this source code is governed by a BSD-style 15159-// license that can be found in the LICENSE file. 15160- 15161-package cache 15162- 15163-import ( 15164- "strings" 15165- "testing" 15166-) 15167- 15168-func TestParseErrorMessage(t *testing.T) { 15169- tests := []struct { 15170- name string 15171- in string 15172- expectedFileName string 15173- expectedLine int 15174- expectedColumn int 15175- }{ 15176- { 15177- name: "from go list output", 15178- in: "\nattributes.go:13:1: expected 'package', found 'type'", 15179- expectedFileName: "attributes.go", 15180- expectedLine: 13, 15181- expectedColumn: 1, 15182- }, 15183- } 15184- 15185- for _, tt := range tests { 15186- t.Run(tt.name, func(t *testing.T) { 15187- spn := parseGoListError(tt.in, ".") 15188- fn := spn.URI().Filename() 15189- 15190- if !strings.HasSuffix(fn, tt.expectedFileName) { 15191- t.Errorf("expected filename with suffix %v but got %v", tt.expectedFileName, fn) 15192- } 15193- 15194- if !spn.HasPosition() { 15195- t.Fatalf("expected span to have position") 15196- } 15197- 15198- pos := spn.Start() 15199- if pos.Line() != tt.expectedLine { 15200- t.Errorf("expected line %v but got %v", tt.expectedLine, pos.Line()) 15201- } 15202- 15203- if pos.Column() != tt.expectedColumn { 15204- t.Errorf("expected line %v but got %v", tt.expectedLine, pos.Line()) 15205- } 15206- }) 15207- } 15208-} 15209diff -urN a/gopls/internal/lsp/cache/fs_memoized.go b/gopls/internal/lsp/cache/fs_memoized.go 15210--- a/gopls/internal/lsp/cache/fs_memoized.go 2000-01-01 00:00:00.000000000 -0000 15211+++ b/gopls/internal/lsp/cache/fs_memoized.go 1970-01-01 00:00:00.000000000 +0000 15212@@ -1,149 +0,0 @@ 15213-// Copyright 2023 The Go Authors. All rights reserved. 15214-// Use of this source code is governed by a BSD-style 15215-// license that can be found in the LICENSE file. 15216- 15217-package cache 15218- 15219-import ( 15220- "context" 15221- "os" 15222- "sync" 15223- "time" 15224- 15225- "golang.org/x/tools/gopls/internal/lsp/source" 15226- "golang.org/x/tools/gopls/internal/span" 15227- "golang.org/x/tools/internal/event" 15228- "golang.org/x/tools/internal/event/tag" 15229- "golang.org/x/tools/internal/robustio" 15230-) 15231- 15232-// A memoizedFS is a file source that memoizes reads, to reduce IO. 15233-type memoizedFS struct { 15234- mu sync.Mutex 15235- 15236- // filesByID maps existing file inodes to the result of a read. 15237- // (The read may have failed, e.g. due to EACCES or a delete between stat+read.) 15238- // Each slice is a non-empty list of aliases: different URIs. 15239- filesByID map[robustio.FileID][]*DiskFile 15240-} 15241- 15242-func newMemoizedFS() *memoizedFS { 15243- return &memoizedFS{filesByID: make(map[robustio.FileID][]*DiskFile)} 15244-} 15245- 15246-// A DiskFile is a file on the filesystem, or a failure to read one. 15247-// It implements the source.FileHandle interface. 15248-type DiskFile struct { 15249- uri span.URI 15250- modTime time.Time 15251- content []byte 15252- hash source.Hash 15253- err error 15254-} 15255- 15256-func (h *DiskFile) URI() span.URI { return h.uri } 15257- 15258-func (h *DiskFile) FileIdentity() source.FileIdentity { 15259- return source.FileIdentity{ 15260- URI: h.uri, 15261- Hash: h.hash, 15262- } 15263-} 15264- 15265-func (h *DiskFile) Saved() bool { return true } 15266-func (h *DiskFile) Version() int32 { return 0 } 15267-func (h *DiskFile) Read() ([]byte, error) { return h.content, h.err } 15268- 15269-// GetFile stats and (maybe) reads the file, updates the cache, and returns it. 15270-func (fs *memoizedFS) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) { 15271- id, mtime, err := robustio.GetFileID(uri.Filename()) 15272- if err != nil { 15273- // file does not exist 15274- return &DiskFile{ 15275- err: err, 15276- uri: uri, 15277- }, nil 15278- } 15279- 15280- // We check if the file has changed by comparing modification times. Notably, 15281- // this is an imperfect heuristic as various systems have low resolution 15282- // mtimes (as much as 1s on WSL or s390x builders), so we only cache 15283- // filehandles if mtime is old enough to be reliable, meaning that we don't 15284- // expect a subsequent write to have the same mtime. 15285- // 15286- // The coarsest mtime precision we've seen in practice is 1s, so consider 15287- // mtime to be unreliable if it is less than 2s old. Capture this before 15288- // doing anything else. 15289- recentlyModified := time.Since(mtime) < 2*time.Second 15290- 15291- fs.mu.Lock() 15292- fhs, ok := fs.filesByID[id] 15293- if ok && fhs[0].modTime.Equal(mtime) { 15294- var fh *DiskFile 15295- // We have already seen this file and it has not changed. 15296- for _, h := range fhs { 15297- if h.uri == uri { 15298- fh = h 15299- break 15300- } 15301- } 15302- // No file handle for this exact URI. Create an alias, but share content. 15303- if fh == nil { 15304- newFH := *fhs[0] 15305- newFH.uri = uri 15306- fh = &newFH 15307- fhs = append(fhs, fh) 15308- fs.filesByID[id] = fhs 15309- } 15310- fs.mu.Unlock() 15311- return fh, nil 15312- } 15313- fs.mu.Unlock() 15314- 15315- // Unknown file, or file has changed. Read (or re-read) it. 15316- fh, err := readFile(ctx, uri, mtime) // ~25us 15317- if err != nil { 15318- return nil, err // e.g. cancelled (not: read failed) 15319- } 15320- 15321- fs.mu.Lock() 15322- if !recentlyModified { 15323- fs.filesByID[id] = []*DiskFile{fh} 15324- } else { 15325- delete(fs.filesByID, id) 15326- } 15327- fs.mu.Unlock() 15328- return fh, nil 15329-} 15330- 15331-// ioLimit limits the number of parallel file reads per process. 15332-var ioLimit = make(chan struct{}, 128) 15333- 15334-func readFile(ctx context.Context, uri span.URI, mtime time.Time) (*DiskFile, error) { 15335- select { 15336- case ioLimit <- struct{}{}: 15337- case <-ctx.Done(): 15338- return nil, ctx.Err() 15339- } 15340- defer func() { <-ioLimit }() 15341- 15342- ctx, done := event.Start(ctx, "cache.readFile", tag.File.Of(uri.Filename())) 15343- _ = ctx 15344- defer done() 15345- 15346- // It is possible that a race causes us to read a file with different file 15347- // ID, or whose mtime differs from the given mtime. However, in these cases 15348- // we expect the client to notify of a subsequent file change, and the file 15349- // content should be eventually consistent. 15350- content, err := os.ReadFile(uri.Filename()) // ~20us 15351- if err != nil { 15352- content = nil // just in case 15353- } 15354- return &DiskFile{ 15355- modTime: mtime, 15356- uri: uri, 15357- content: content, 15358- hash: source.HashOf(content), 15359- err: err, 15360- }, nil 15361-} 15362diff -urN a/gopls/internal/lsp/cache/fs_overlay.go b/gopls/internal/lsp/cache/fs_overlay.go 15363--- a/gopls/internal/lsp/cache/fs_overlay.go 2000-01-01 00:00:00.000000000 -0000 15364+++ b/gopls/internal/lsp/cache/fs_overlay.go 1970-01-01 00:00:00.000000000 +0000 15365@@ -1,78 +0,0 @@ 15366-// Copyright 2023 The Go Authors. All rights reserved. 15367-// Use of this source code is governed by a BSD-style 15368-// license that can be found in the LICENSE file. 15369- 15370-package cache 15371- 15372-import ( 15373- "context" 15374- "sync" 15375- 15376- "golang.org/x/tools/gopls/internal/lsp/source" 15377- "golang.org/x/tools/gopls/internal/span" 15378-) 15379- 15380-// An overlayFS is a source.FileSource that keeps track of overlays on top of a 15381-// delegate FileSource. 15382-type overlayFS struct { 15383- delegate source.FileSource 15384- 15385- mu sync.Mutex 15386- overlays map[span.URI]*Overlay 15387-} 15388- 15389-func newOverlayFS(delegate source.FileSource) *overlayFS { 15390- return &overlayFS{ 15391- delegate: delegate, 15392- overlays: make(map[span.URI]*Overlay), 15393- } 15394-} 15395- 15396-// Overlays returns a new unordered array of overlays. 15397-func (fs *overlayFS) Overlays() []*Overlay { 15398- fs.mu.Lock() 15399- defer fs.mu.Unlock() 15400- overlays := make([]*Overlay, 0, len(fs.overlays)) 15401- for _, overlay := range fs.overlays { 15402- overlays = append(overlays, overlay) 15403- } 15404- return overlays 15405-} 15406- 15407-func (fs *overlayFS) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) { 15408- fs.mu.Lock() 15409- overlay, ok := fs.overlays[uri] 15410- fs.mu.Unlock() 15411- if ok { 15412- return overlay, nil 15413- } 15414- return fs.delegate.GetFile(ctx, uri) 15415-} 15416- 15417-// An Overlay is a file open in the editor. It may have unsaved edits. 15418-// It implements the source.FileHandle interface. 15419-type Overlay struct { 15420- uri span.URI 15421- content []byte 15422- hash source.Hash 15423- version int32 15424- kind source.FileKind 15425- 15426- // saved is true if a file matches the state on disk, 15427- // and therefore does not need to be part of the overlay sent to go/packages. 15428- saved bool 15429-} 15430- 15431-func (o *Overlay) URI() span.URI { return o.uri } 15432- 15433-func (o *Overlay) FileIdentity() source.FileIdentity { 15434- return source.FileIdentity{ 15435- URI: o.uri, 15436- Hash: o.hash, 15437- } 15438-} 15439- 15440-func (o *Overlay) Read() ([]byte, error) { return o.content, nil } 15441-func (o *Overlay) Version() int32 { return o.version } 15442-func (o *Overlay) Saved() bool { return o.saved } 15443-func (o *Overlay) Kind() source.FileKind { return o.kind } 15444diff -urN a/gopls/internal/lsp/cache/graph.go b/gopls/internal/lsp/cache/graph.go 15445--- a/gopls/internal/lsp/cache/graph.go 2000-01-01 00:00:00.000000000 -0000 15446+++ b/gopls/internal/lsp/cache/graph.go 1970-01-01 00:00:00.000000000 +0000 15447@@ -1,131 +0,0 @@ 15448-// Copyright 2022 The Go Authors. All rights reserved. 15449-// Use of this source code is governed by a BSD-style 15450-// license that can be found in the LICENSE file. 15451- 15452-package cache 15453- 15454-import ( 15455- "sort" 15456- 15457- "golang.org/x/tools/gopls/internal/lsp/source" 15458- "golang.org/x/tools/gopls/internal/span" 15459-) 15460- 15461-// A metadataGraph is an immutable and transitively closed import 15462-// graph of Go packages, as obtained from go/packages. 15463-type metadataGraph struct { 15464- // metadata maps package IDs to their associated metadata. 15465- metadata map[PackageID]*source.Metadata 15466- 15467- // importedBy maps package IDs to the list of packages that import them. 15468- importedBy map[PackageID][]PackageID 15469- 15470- // ids maps file URIs to package IDs, sorted by (!valid, cli, packageID). 15471- // A single file may belong to multiple packages due to tests packages. 15472- ids map[span.URI][]PackageID 15473-} 15474- 15475-// Metadata implements the source.MetadataSource interface. 15476-func (g *metadataGraph) Metadata(id PackageID) *source.Metadata { 15477- return g.metadata[id] 15478-} 15479- 15480-// Clone creates a new metadataGraph, applying the given updates to the 15481-// receiver. 15482-func (g *metadataGraph) Clone(updates map[PackageID]*source.Metadata) *metadataGraph { 15483- if len(updates) == 0 { 15484- // Optimization: since the graph is immutable, we can return the receiver. 15485- return g 15486- } 15487- result := &metadataGraph{metadata: make(map[PackageID]*source.Metadata, len(g.metadata))} 15488- // Copy metadata. 15489- for id, m := range g.metadata { 15490- result.metadata[id] = m 15491- } 15492- for id, m := range updates { 15493- if m == nil { 15494- delete(result.metadata, id) 15495- } else { 15496- result.metadata[id] = m 15497- } 15498- } 15499- result.build() 15500- return result 15501-} 15502- 15503-// build constructs g.importedBy and g.uris from g.metadata. 15504-// 15505-// TODO(rfindley): we should enforce that the graph is acyclic here. 15506-func (g *metadataGraph) build() { 15507- // Build the import graph. 15508- g.importedBy = make(map[PackageID][]PackageID) 15509- for id, m := range g.metadata { 15510- for _, depID := range m.DepsByPkgPath { 15511- g.importedBy[depID] = append(g.importedBy[depID], id) 15512- } 15513- } 15514- 15515- // Collect file associations. 15516- g.ids = make(map[span.URI][]PackageID) 15517- for id, m := range g.metadata { 15518- uris := map[span.URI]struct{}{} 15519- for _, uri := range m.CompiledGoFiles { 15520- uris[uri] = struct{}{} 15521- } 15522- for _, uri := range m.GoFiles { 15523- uris[uri] = struct{}{} 15524- } 15525- for uri := range uris { 15526- g.ids[uri] = append(g.ids[uri], id) 15527- } 15528- } 15529- 15530- // Sort and filter file associations. 15531- for uri, ids := range g.ids { 15532- sort.Slice(ids, func(i, j int) bool { 15533- cli := source.IsCommandLineArguments(ids[i]) 15534- clj := source.IsCommandLineArguments(ids[j]) 15535- if cli != clj { 15536- return clj 15537- } 15538- 15539- // 2. packages appear in name order. 15540- return ids[i] < ids[j] 15541- }) 15542- 15543- // Choose the best IDs for each URI, according to the following rules: 15544- // - If there are any valid real packages, choose them. 15545- // - Else, choose the first valid command-line-argument package, if it exists. 15546- // 15547- // TODO(rfindley): it might be better to track all IDs here, and exclude 15548- // them later when type checking, but this is the existing behavior. 15549- for i, id := range ids { 15550- // If we've seen *anything* prior to command-line arguments package, take 15551- // it. Note that ids[0] may itself be command-line-arguments. 15552- if i > 0 && source.IsCommandLineArguments(id) { 15553- g.ids[uri] = ids[:i] 15554- break 15555- } 15556- } 15557- } 15558-} 15559- 15560-// reverseReflexiveTransitiveClosure returns a new mapping containing the 15561-// metadata for the specified packages along with any package that 15562-// transitively imports one of them, keyed by ID, including all the initial packages. 15563-func (g *metadataGraph) reverseReflexiveTransitiveClosure(ids ...PackageID) map[PackageID]*source.Metadata { 15564- seen := make(map[PackageID]*source.Metadata) 15565- var visitAll func([]PackageID) 15566- visitAll = func(ids []PackageID) { 15567- for _, id := range ids { 15568- if seen[id] == nil { 15569- if m := g.metadata[id]; m != nil { 15570- seen[id] = m 15571- visitAll(g.importedBy[id]) 15572- } 15573- } 15574- } 15575- } 15576- visitAll(ids) 15577- return seen 15578-} 15579diff -urN a/gopls/internal/lsp/cache/imports.go b/gopls/internal/lsp/cache/imports.go 15580--- a/gopls/internal/lsp/cache/imports.go 2000-01-01 00:00:00.000000000 -0000 15581+++ b/gopls/internal/lsp/cache/imports.go 1970-01-01 00:00:00.000000000 +0000 15582@@ -1,188 +0,0 @@ 15583-// Copyright 2020 The Go Authors. All rights reserved. 15584-// Use of this source code is governed by a BSD-style 15585-// license that can be found in the LICENSE file. 15586- 15587-package cache 15588- 15589-import ( 15590- "context" 15591- "fmt" 15592- "reflect" 15593- "strings" 15594- "sync" 15595- "time" 15596- 15597- "golang.org/x/tools/gopls/internal/lsp/source" 15598- "golang.org/x/tools/internal/event" 15599- "golang.org/x/tools/internal/event/keys" 15600- "golang.org/x/tools/internal/gocommand" 15601- "golang.org/x/tools/internal/imports" 15602-) 15603- 15604-type importsState struct { 15605- ctx context.Context 15606- 15607- mu sync.Mutex 15608- processEnv *imports.ProcessEnv 15609- cacheRefreshDuration time.Duration 15610- cacheRefreshTimer *time.Timer 15611- cachedModFileHash source.Hash 15612- cachedBuildFlags []string 15613- cachedDirectoryFilters []string 15614- 15615- // runOnce records whether runProcessEnvFunc has been called at least once. 15616- // This is necessary to avoid resetting state before the process env is 15617- // populated. 15618- // 15619- // TODO(rfindley): this shouldn't be necessary. 15620- runOnce bool 15621-} 15622- 15623-func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot, fn func(*imports.Options) error) error { 15624- s.mu.Lock() 15625- defer s.mu.Unlock() 15626- 15627- // Find the hash of active mod files, if any. Using the unsaved content 15628- // is slightly wasteful, since we'll drop caches a little too often, but 15629- // the mod file shouldn't be changing while people are autocompleting. 15630- // 15631- // TODO(rfindley): consider instead hashing on-disk modfiles here. 15632- var modFileHash source.Hash 15633- for m := range snapshot.workspaceModFiles { 15634- fh, err := snapshot.GetFile(ctx, m) 15635- if err != nil { 15636- return err 15637- } 15638- modFileHash.XORWith(fh.FileIdentity().Hash) 15639- } 15640- 15641- // view.goEnv is immutable -- changes make a new view. Options can change. 15642- // We can't compare build flags directly because we may add -modfile. 15643- snapshot.view.optionsMu.Lock() 15644- localPrefix := snapshot.view.options.Local 15645- currentBuildFlags := snapshot.view.options.BuildFlags 15646- currentDirectoryFilters := snapshot.view.options.DirectoryFilters 15647- changed := !reflect.DeepEqual(currentBuildFlags, s.cachedBuildFlags) || 15648- snapshot.view.options.VerboseOutput != (s.processEnv.Logf != nil) || 15649- modFileHash != s.cachedModFileHash || 15650- !reflect.DeepEqual(snapshot.view.options.DirectoryFilters, s.cachedDirectoryFilters) 15651- snapshot.view.optionsMu.Unlock() 15652- 15653- // If anything relevant to imports has changed, clear caches and 15654- // update the processEnv. Clearing caches blocks on any background 15655- // scans. 15656- if changed { 15657- // As a special case, skip cleanup the first time -- we haven't fully 15658- // initialized the environment yet and calling GetResolver will do 15659- // unnecessary work and potentially mess up the go.mod file. 15660- if s.runOnce { 15661- if resolver, err := s.processEnv.GetResolver(); err == nil { 15662- if modResolver, ok := resolver.(*imports.ModuleResolver); ok { 15663- modResolver.ClearForNewMod() 15664- } 15665- } 15666- } 15667- 15668- s.cachedModFileHash = modFileHash 15669- s.cachedBuildFlags = currentBuildFlags 15670- s.cachedDirectoryFilters = currentDirectoryFilters 15671- if err := s.populateProcessEnv(ctx, snapshot); err != nil { 15672- return err 15673- } 15674- s.runOnce = true 15675- } 15676- 15677- // Run the user function. 15678- opts := &imports.Options{ 15679- // Defaults. 15680- AllErrors: true, 15681- Comments: true, 15682- Fragment: true, 15683- FormatOnly: false, 15684- TabIndent: true, 15685- TabWidth: 8, 15686- Env: s.processEnv, 15687- LocalPrefix: localPrefix, 15688- } 15689- 15690- if err := fn(opts); err != nil { 15691- return err 15692- } 15693- 15694- if s.cacheRefreshTimer == nil { 15695- // Don't refresh more than twice per minute. 15696- delay := 30 * time.Second 15697- // Don't spend more than a couple percent of the time refreshing. 15698- if adaptive := 50 * s.cacheRefreshDuration; adaptive > delay { 15699- delay = adaptive 15700- } 15701- s.cacheRefreshTimer = time.AfterFunc(delay, s.refreshProcessEnv) 15702- } 15703- 15704- return nil 15705-} 15706- 15707-// populateProcessEnv sets the dynamically configurable fields for the view's 15708-// process environment. Assumes that the caller is holding the s.view.importsMu. 15709-func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapshot) error { 15710- pe := s.processEnv 15711- 15712- if snapshot.view.Options().VerboseOutput { 15713- pe.Logf = func(format string, args ...interface{}) { 15714- event.Log(ctx, fmt.Sprintf(format, args...)) 15715- } 15716- } else { 15717- pe.Logf = nil 15718- } 15719- 15720- // Extract invocation details from the snapshot to use with goimports. 15721- // 15722- // TODO(rfindley): refactor to extract the necessary invocation logic into 15723- // separate functions. Using goCommandInvocation is unnecessarily indirect, 15724- // and has led to memory leaks in the past, when the snapshot was 15725- // unintentionally held past its lifetime. 15726- _, inv, cleanupInvocation, err := snapshot.goCommandInvocation(ctx, source.LoadWorkspace, &gocommand.Invocation{ 15727- WorkingDir: snapshot.view.workingDir().Filename(), 15728- }) 15729- if err != nil { 15730- return err 15731- } 15732- 15733- pe.BuildFlags = inv.BuildFlags 15734- pe.ModFlag = "readonly" // processEnv operations should not mutate the modfile 15735- pe.Env = map[string]string{} 15736- for _, kv := range inv.Env { 15737- split := strings.SplitN(kv, "=", 2) 15738- if len(split) != 2 { 15739- continue 15740- } 15741- pe.Env[split[0]] = split[1] 15742- } 15743- // We don't actually use the invocation, so clean it up now. 15744- cleanupInvocation() 15745- // TODO(rfindley): should this simply be inv.WorkingDir? 15746- pe.WorkingDir = snapshot.view.workingDir().Filename() 15747- return nil 15748-} 15749- 15750-func (s *importsState) refreshProcessEnv() { 15751- start := time.Now() 15752- 15753- s.mu.Lock() 15754- env := s.processEnv 15755- if resolver, err := s.processEnv.GetResolver(); err == nil { 15756- resolver.ClearForNewScan() 15757- } 15758- s.mu.Unlock() 15759- 15760- event.Log(s.ctx, "background imports cache refresh starting") 15761- if err := imports.PrimeCache(context.Background(), env); err == nil { 15762- event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start))) 15763- } else { 15764- event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)), keys.Err.Of(err)) 15765- } 15766- s.mu.Lock() 15767- s.cacheRefreshDuration = time.Since(start) 15768- s.cacheRefreshTimer = nil 15769- s.mu.Unlock() 15770-} 15771diff -urN a/gopls/internal/lsp/cache/keys.go b/gopls/internal/lsp/cache/keys.go 15772--- a/gopls/internal/lsp/cache/keys.go 2000-01-01 00:00:00.000000000 -0000 15773+++ b/gopls/internal/lsp/cache/keys.go 1970-01-01 00:00:00.000000000 +0000 15774@@ -1,52 +0,0 @@ 15775-// Copyright 2020 The Go Authors. All rights reserved. 15776-// Use of this source code is governed by a BSD-style 15777-// license that can be found in the LICENSE file. 15778- 15779-package cache 15780- 15781-import ( 15782- "io" 15783- 15784- "golang.org/x/tools/internal/event/label" 15785-) 15786- 15787-var ( 15788- KeyCreateSession = NewSessionKey("create_session", "A new session was added") 15789- KeyUpdateSession = NewSessionKey("update_session", "Updated information about a session") 15790- KeyShutdownSession = NewSessionKey("shutdown_session", "A session was shut down") 15791-) 15792- 15793-// SessionKey represents an event label key that has a *Session value. 15794-type SessionKey struct { 15795- name string 15796- description string 15797-} 15798- 15799-// NewSessionKey creates a new Key for *Session values. 15800-func NewSessionKey(name, description string) *SessionKey { 15801- return &SessionKey{name: name, description: description} 15802-} 15803- 15804-func (k *SessionKey) Name() string { return k.name } 15805-func (k *SessionKey) Description() string { return k.description } 15806- 15807-func (k *SessionKey) Format(w io.Writer, buf []byte, l label.Label) { 15808- io.WriteString(w, k.From(l).ID()) 15809-} 15810- 15811-// Of creates a new Label with this key and the supplied session. 15812-func (k *SessionKey) Of(v *Session) label.Label { return label.OfValue(k, v) } 15813- 15814-// Get can be used to get the session for the key from a label.Map. 15815-func (k *SessionKey) Get(lm label.Map) *Session { 15816- if t := lm.Find(k); t.Valid() { 15817- return k.From(t) 15818- } 15819- return nil 15820-} 15821- 15822-// From can be used to get the session value from a Label. 15823-func (k *SessionKey) From(t label.Label) *Session { 15824- err, _ := t.UnpackValue().(*Session) 15825- return err 15826-} 15827diff -urN a/gopls/internal/lsp/cache/load.go b/gopls/internal/lsp/cache/load.go 15828--- a/gopls/internal/lsp/cache/load.go 2000-01-01 00:00:00.000000000 -0000 15829+++ b/gopls/internal/lsp/cache/load.go 1970-01-01 00:00:00.000000000 +0000 15830@@ -1,782 +0,0 @@ 15831-// Copyright 2019 The Go Authors. All rights reserved. 15832-// Use of this source code is governed by a BSD-style 15833-// license that can be found in the LICENSE file. 15834- 15835-package cache 15836- 15837-import ( 15838- "bytes" 15839- "context" 15840- "errors" 15841- "fmt" 15842- "path/filepath" 15843- "sort" 15844- "strings" 15845- "sync/atomic" 15846- "time" 15847- 15848- "golang.org/x/tools/go/packages" 15849- "golang.org/x/tools/gopls/internal/lsp/protocol" 15850- "golang.org/x/tools/gopls/internal/lsp/source" 15851- "golang.org/x/tools/gopls/internal/span" 15852- "golang.org/x/tools/internal/bug" 15853- "golang.org/x/tools/internal/event" 15854- "golang.org/x/tools/internal/event/tag" 15855- "golang.org/x/tools/internal/gocommand" 15856- "golang.org/x/tools/internal/packagesinternal" 15857-) 15858- 15859-var loadID uint64 // atomic identifier for loads 15860- 15861-// errNoPackages indicates that a load query matched no packages. 15862-var errNoPackages = errors.New("no packages returned") 15863- 15864-// load calls packages.Load for the given scopes, updating package metadata, 15865-// import graph, and mapped files with the result. 15866-// 15867-// The resulting error may wrap the moduleErrorMap error type, representing 15868-// errors associated with specific modules. 15869-func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...loadScope) (err error) { 15870- id := atomic.AddUint64(&loadID, 1) 15871- eventName := fmt.Sprintf("go/packages.Load #%d", id) // unique name for logging 15872- 15873- var query []string 15874- var containsDir bool // for logging 15875- 15876- // Keep track of module query -> module path so that we can later correlate query 15877- // errors with errors. 15878- moduleQueries := make(map[string]string) 15879- for _, scope := range scopes { 15880- switch scope := scope.(type) { 15881- case packageLoadScope: 15882- // The only time we pass package paths is when we're doing a 15883- // partial workspace load. In those cases, the paths came back from 15884- // go list and should already be GOPATH-vendorized when appropriate. 15885- query = append(query, string(scope)) 15886- 15887- case fileLoadScope: 15888- uri := span.URI(scope) 15889- fh := s.FindFile(uri) 15890- if fh == nil || s.View().FileKind(fh) != source.Go { 15891- // Don't try to load a file that doesn't exist, or isn't a go file. 15892- continue 15893- } 15894- contents, err := fh.Read() 15895- if err != nil { 15896- continue 15897- } 15898- if isStandaloneFile(contents, s.view.Options().StandaloneTags) { 15899- query = append(query, uri.Filename()) 15900- } else { 15901- query = append(query, fmt.Sprintf("file=%s", uri.Filename())) 15902- } 15903- 15904- case moduleLoadScope: 15905- switch scope { 15906- case "std", "cmd": 15907- query = append(query, string(scope)) 15908- default: 15909- modQuery := fmt.Sprintf("%s/...", scope) 15910- query = append(query, modQuery) 15911- moduleQueries[modQuery] = string(scope) 15912- } 15913- 15914- case viewLoadScope: 15915- // If we are outside of GOPATH, a module, or some other known 15916- // build system, don't load subdirectories. 15917- if !s.ValidBuildConfiguration() { 15918- query = append(query, "./") 15919- } else { 15920- query = append(query, "./...") 15921- } 15922- 15923- default: 15924- panic(fmt.Sprintf("unknown scope type %T", scope)) 15925- } 15926- switch scope.(type) { 15927- case viewLoadScope, moduleLoadScope: 15928- containsDir = true 15929- } 15930- } 15931- if len(query) == 0 { 15932- return nil 15933- } 15934- sort.Strings(query) // for determinism 15935- 15936- ctx, done := event.Start(ctx, "cache.view.load", tag.Query.Of(query)) 15937- defer done() 15938- 15939- flags := source.LoadWorkspace 15940- if allowNetwork { 15941- flags |= source.AllowNetwork 15942- } 15943- _, inv, cleanup, err := s.goCommandInvocation(ctx, flags, &gocommand.Invocation{ 15944- WorkingDir: s.view.workingDir().Filename(), 15945- }) 15946- if err != nil { 15947- return err 15948- } 15949- 15950- // Set a last resort deadline on packages.Load since it calls the go 15951- // command, which may hang indefinitely if it has a bug. golang/go#42132 15952- // and golang/go#42255 have more context. 15953- ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) 15954- defer cancel() 15955- 15956- cfg := s.config(ctx, inv) 15957- pkgs, err := packages.Load(cfg, query...) 15958- cleanup() 15959- 15960- // If the context was canceled, return early. Otherwise, we might be 15961- // type-checking an incomplete result. Check the context directly, 15962- // because go/packages adds extra information to the error. 15963- if ctx.Err() != nil { 15964- return ctx.Err() 15965- } 15966- 15967- // This log message is sought for by TestReloadOnlyOnce. 15968- labels := append(source.SnapshotLabels(s), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs))) 15969- if err != nil { 15970- event.Error(ctx, eventName, err, labels...) 15971- } else { 15972- event.Log(ctx, eventName, labels...) 15973- } 15974- 15975- if len(pkgs) == 0 { 15976- if err == nil { 15977- err = errNoPackages 15978- } 15979- return fmt.Errorf("packages.Load error: %w", err) 15980- } 15981- 15982- moduleErrs := make(map[string][]packages.Error) // module path -> errors 15983- filterFunc := s.view.filterFunc() 15984- newMetadata := make(map[PackageID]*source.Metadata) 15985- for _, pkg := range pkgs { 15986- // The Go command returns synthetic list results for module queries that 15987- // encountered module errors. 15988- // 15989- // For example, given a module path a.mod, we'll query for "a.mod/..." and 15990- // the go command will return a package named "a.mod/..." holding this 15991- // error. Save it for later interpretation. 15992- // 15993- // See golang/go#50862 for more details. 15994- if mod := moduleQueries[pkg.PkgPath]; mod != "" { // a synthetic result for the unloadable module 15995- if len(pkg.Errors) > 0 { 15996- moduleErrs[mod] = pkg.Errors 15997- } 15998- continue 15999- } 16000- 16001- if !containsDir || s.view.Options().VerboseOutput { 16002- event.Log(ctx, eventName, append( 16003- source.SnapshotLabels(s), 16004- tag.Package.Of(pkg.ID), 16005- tag.Files.Of(pkg.CompiledGoFiles))...) 16006- } 16007- 16008- // Ignore packages with no sources, since we will never be able to 16009- // correctly invalidate that metadata. 16010- if len(pkg.GoFiles) == 0 && len(pkg.CompiledGoFiles) == 0 { 16011- continue 16012- } 16013- // Special case for the builtin package, as it has no dependencies. 16014- if pkg.PkgPath == "builtin" { 16015- if len(pkg.GoFiles) != 1 { 16016- return fmt.Errorf("only expected 1 file for builtin, got %v", len(pkg.GoFiles)) 16017- } 16018- s.setBuiltin(pkg.GoFiles[0]) 16019- continue 16020- } 16021- // Skip test main packages. 16022- if isTestMain(pkg, s.view.gocache) { 16023- continue 16024- } 16025- // Skip filtered packages. They may be added anyway if they're 16026- // dependencies of non-filtered packages. 16027- // 16028- // TODO(rfindley): why exclude metadata arbitrarily here? It should be safe 16029- // to capture all metadata. 16030- // TODO(rfindley): what about compiled go files? 16031- if allFilesExcluded(pkg.GoFiles, filterFunc) { 16032- continue 16033- } 16034- if err := buildMetadata(ctx, pkg, cfg, query, newMetadata, nil); err != nil { 16035- return err 16036- } 16037- } 16038- 16039- s.mu.Lock() 16040- 16041- // Compute the minimal metadata updates (for Clone) 16042- // required to preserve this invariant: 16043- // for all id, s.packages.Get(id).m == s.meta.metadata[id]. 16044- updates := make(map[PackageID]*source.Metadata) 16045- for _, m := range newMetadata { 16046- if existing := s.meta.metadata[m.ID]; existing == nil { 16047- updates[m.ID] = m 16048- delete(s.shouldLoad, m.ID) 16049- } 16050- } 16051- // Assert the invariant. 16052- s.packages.Range(func(k, v interface{}) { 16053- id, ph := k.(PackageID), v.(*packageHandle) 16054- if s.meta.metadata[id] != ph.m { 16055- // TODO(adonovan): upgrade to unconditional panic after Jan 2023. 16056- bug.Reportf("inconsistent metadata") 16057- } 16058- }) 16059- 16060- event.Log(ctx, fmt.Sprintf("%s: updating metadata for %d packages", eventName, len(updates))) 16061- 16062- // Before mutating the snapshot, ensure that we compute load diagnostics 16063- // successfully. This could fail if the context is cancelled, and we don't 16064- // want to leave the snapshot metadata in a partial state. 16065- meta := s.meta.Clone(updates) 16066- workspacePackages := computeWorkspacePackagesLocked(s, meta) 16067- for _, update := range updates { 16068- if err := computeLoadDiagnostics(ctx, update, meta, lockedSnapshot{s}, workspacePackages); err != nil { 16069- return err 16070- } 16071- } 16072- s.meta = meta 16073- s.workspacePackages = workspacePackages 16074- s.resetActivePackagesLocked() 16075- 16076- s.dumpWorkspace("load") 16077- s.mu.Unlock() 16078- 16079- // Recompute the workspace package handle for any packages we invalidated. 16080- // 16081- // This is (putatively) an optimization since handle construction prefetches 16082- // the content of all Go source files. 16083- // 16084- // However, one necessary side effect of this operation is that we are 16085- // guaranteed to visit all package files during load. This is required for 16086- // e.g. determining the set of directories to watch. 16087- // 16088- // TODO(rfindley, golang/go#57558): determine the set of directories based on 16089- // loaded packages, and skip this precomputation. 16090- for _, m := range updates { 16091- s.buildPackageHandle(ctx, m.ID) // ignore error 16092- } 16093- 16094- if len(moduleErrs) > 0 { 16095- return &moduleErrorMap{moduleErrs} 16096- } 16097- 16098- return nil 16099-} 16100- 16101-type moduleErrorMap struct { 16102- errs map[string][]packages.Error // module path -> errors 16103-} 16104- 16105-func (m *moduleErrorMap) Error() string { 16106- var paths []string // sort for stability 16107- for path, errs := range m.errs { 16108- if len(errs) > 0 { // should always be true, but be cautious 16109- paths = append(paths, path) 16110- } 16111- } 16112- sort.Strings(paths) 16113- 16114- var buf bytes.Buffer 16115- fmt.Fprintf(&buf, "%d modules have errors:\n", len(paths)) 16116- for _, path := range paths { 16117- fmt.Fprintf(&buf, "\t%s:%s\n", path, m.errs[path][0].Msg) 16118- } 16119- 16120- return buf.String() 16121-} 16122- 16123-// workspaceLayoutError returns an error describing a misconfiguration of the 16124-// workspace, along with related diagnostic. 16125-// 16126-// The unusual argument ordering of results is intentional: if the resulting 16127-// error is nil, so must be the resulting diagnostics. 16128-// 16129-// If ctx is cancelled, it may return ctx.Err(), nil. 16130-// 16131-// TODO(rfindley): separate workspace diagnostics from critical workspace 16132-// errors. 16133-func (s *snapshot) workspaceLayoutError(ctx context.Context) (error, []*source.Diagnostic) { 16134- // TODO(rfindley): both of the checks below should be delegated to the workspace. 16135- 16136- if s.view.effectiveGO111MODULE() == off { 16137- return nil, nil 16138- } 16139- 16140- // If the user is using a go.work file, we assume that they know what they 16141- // are doing. 16142- // 16143- // TODO(golang/go#53880): improve orphaned file diagnostics when using go.work. 16144- if s.view.gowork != "" { 16145- return nil, nil 16146- } 16147- 16148- // Apply diagnostics about the workspace configuration to relevant open 16149- // files. 16150- openFiles := s.openFiles() 16151- 16152- // If the snapshot does not have a valid build configuration, it may be 16153- // that the user has opened a directory that contains multiple modules. 16154- // Check for that an warn about it. 16155- if !s.ValidBuildConfiguration() { 16156- var msg string 16157- if s.view.goversion >= 18 { 16158- msg = `gopls was not able to find modules in your workspace. 16159-When outside of GOPATH, gopls needs to know which modules you are working on. 16160-You can fix this by opening your workspace to a folder inside a Go module, or 16161-by using a go.work file to specify multiple modules. 16162-See the documentation for more information on setting up your workspace: 16163-https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.` 16164- } else { 16165- msg = `gopls requires a module at the root of your workspace. 16166-You can work with multiple modules by upgrading to Go 1.18 or later, and using 16167-go workspaces (go.work files). 16168-See the documentation for more information on setting up your workspace: 16169-https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.` 16170- } 16171- return fmt.Errorf(msg), s.applyCriticalErrorToFiles(ctx, msg, openFiles) 16172- } 16173- 16174- // If the user has one active go.mod file, they may still be editing files 16175- // in nested modules. Check the module of each open file and add warnings 16176- // that the nested module must be opened as a workspace folder. 16177- if len(s.workspaceModFiles) == 1 { 16178- // Get the active root go.mod file to compare against. 16179- var rootMod string 16180- for uri := range s.workspaceModFiles { 16181- rootMod = uri.Filename() 16182- } 16183- rootDir := filepath.Dir(rootMod) 16184- nestedModules := make(map[string][]source.FileHandle) 16185- for _, fh := range openFiles { 16186- mod, err := findRootPattern(ctx, filepath.Dir(fh.URI().Filename()), "go.mod", s) 16187- if err != nil { 16188- if ctx.Err() != nil { 16189- return ctx.Err(), nil 16190- } 16191- continue 16192- } 16193- if mod == "" { 16194- continue 16195- } 16196- if mod != rootMod && source.InDir(rootDir, mod) { 16197- modDir := filepath.Dir(mod) 16198- nestedModules[modDir] = append(nestedModules[modDir], fh) 16199- } 16200- } 16201- var multiModuleMsg string 16202- if s.view.goversion >= 18 { 16203- multiModuleMsg = `To work on multiple modules at once, please use a go.work file. 16204-See https://github.com/golang/tools/blob/master/gopls/doc/workspace.md for more information on using workspaces.` 16205- } else { 16206- multiModuleMsg = `To work on multiple modules at once, please upgrade to Go 1.18 and use a go.work file. 16207-See https://github.com/golang/tools/blob/master/gopls/doc/workspace.md for more information on using workspaces.` 16208- } 16209- // Add a diagnostic to each file in a nested module to mark it as 16210- // "orphaned". Don't show a general diagnostic in the progress bar, 16211- // because the user may still want to edit a file in a nested module. 16212- var srcDiags []*source.Diagnostic 16213- for modDir, uris := range nestedModules { 16214- msg := fmt.Sprintf("This file is in %s, which is a nested module in the %s module.\n%s", modDir, rootMod, multiModuleMsg) 16215- srcDiags = append(srcDiags, s.applyCriticalErrorToFiles(ctx, msg, uris)...) 16216- } 16217- if len(srcDiags) != 0 { 16218- return fmt.Errorf("You have opened a nested module.\n%s", multiModuleMsg), srcDiags 16219- } 16220- } 16221- return nil, nil 16222-} 16223- 16224-func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, files []source.FileHandle) []*source.Diagnostic { 16225- var srcDiags []*source.Diagnostic 16226- for _, fh := range files { 16227- // Place the diagnostics on the package or module declarations. 16228- var rng protocol.Range 16229- switch s.view.FileKind(fh) { 16230- case source.Go: 16231- if pgf, err := s.ParseGo(ctx, fh, source.ParseHeader); err == nil { 16232- // Check that we have a valid `package foo` range to use for positioning the error. 16233- if pgf.File.Package.IsValid() && pgf.File.Name != nil && pgf.File.Name.End().IsValid() { 16234- rng, _ = pgf.PosRange(pgf.File.Package, pgf.File.Name.End()) 16235- } 16236- } 16237- case source.Mod: 16238- if pmf, err := s.ParseMod(ctx, fh); err == nil { 16239- if mod := pmf.File.Module; mod != nil && mod.Syntax != nil { 16240- rng, _ = pmf.Mapper.OffsetRange(mod.Syntax.Start.Byte, mod.Syntax.End.Byte) 16241- } 16242- } 16243- } 16244- srcDiags = append(srcDiags, &source.Diagnostic{ 16245- URI: fh.URI(), 16246- Range: rng, 16247- Severity: protocol.SeverityError, 16248- Source: source.ListError, 16249- Message: msg, 16250- }) 16251- } 16252- return srcDiags 16253-} 16254- 16255-// buildMetadata populates the updates map with metadata updates to 16256-// apply, based on the given pkg. It recurs through pkg.Imports to ensure that 16257-// metadata exists for all dependencies. 16258-func buildMetadata(ctx context.Context, pkg *packages.Package, cfg *packages.Config, query []string, updates map[PackageID]*source.Metadata, path []PackageID) error { 16259- // Allow for multiple ad-hoc packages in the workspace (see #47584). 16260- pkgPath := PackagePath(pkg.PkgPath) 16261- id := PackageID(pkg.ID) 16262- if source.IsCommandLineArguments(id) { 16263- suffix := ":" + strings.Join(query, ",") 16264- id = PackageID(pkg.ID + suffix) 16265- pkgPath = PackagePath(pkg.PkgPath + suffix) 16266- } 16267- 16268- if _, ok := updates[id]; ok { 16269- // If we've already seen this dependency, there may be an import cycle, or 16270- // we may have reached the same package transitively via distinct paths. 16271- // Check the path to confirm. 16272- 16273- // TODO(rfindley): this doesn't look sufficient. Any single piece of new 16274- // metadata could theoretically introduce import cycles in the metadata 16275- // graph. What's the point of this limited check here (and is it even 16276- // possible to get an import cycle in data from go/packages)? Consider 16277- // simply returning, so that this function need not return an error. 16278- // 16279- // We should consider doing a more complete guard against import cycles 16280- // elsewhere. 16281- for _, prev := range path { 16282- if prev == id { 16283- return fmt.Errorf("import cycle detected: %q", id) 16284- } 16285- } 16286- return nil 16287- } 16288- 16289- // Recreate the metadata rather than reusing it to avoid locking. 16290- m := &source.Metadata{ 16291- ID: id, 16292- PkgPath: pkgPath, 16293- Name: PackageName(pkg.Name), 16294- ForTest: PackagePath(packagesinternal.GetForTest(pkg)), 16295- TypesSizes: pkg.TypesSizes, 16296- LoadDir: cfg.Dir, 16297- Module: pkg.Module, 16298- Errors: pkg.Errors, 16299- DepsErrors: packagesinternal.GetDepsErrors(pkg), 16300- } 16301- 16302- updates[id] = m 16303- 16304- for _, filename := range pkg.CompiledGoFiles { 16305- uri := span.URIFromPath(filename) 16306- m.CompiledGoFiles = append(m.CompiledGoFiles, uri) 16307- } 16308- for _, filename := range pkg.GoFiles { 16309- uri := span.URIFromPath(filename) 16310- m.GoFiles = append(m.GoFiles, uri) 16311- } 16312- 16313- depsByImpPath := make(map[ImportPath]PackageID) 16314- depsByPkgPath := make(map[PackagePath]PackageID) 16315- for importPath, imported := range pkg.Imports { 16316- importPath := ImportPath(importPath) 16317- 16318- // It is not an invariant that importPath == imported.PkgPath. 16319- // For example, package "net" imports "golang.org/x/net/dns/dnsmessage" 16320- // which refers to the package whose ID and PkgPath are both 16321- // "vendor/golang.org/x/net/dns/dnsmessage". Notice the ImportMap, 16322- // which maps ImportPaths to PackagePaths: 16323- // 16324- // $ go list -json net vendor/golang.org/x/net/dns/dnsmessage 16325- // { 16326- // "ImportPath": "net", 16327- // "Name": "net", 16328- // "Imports": [ 16329- // "C", 16330- // "vendor/golang.org/x/net/dns/dnsmessage", 16331- // "vendor/golang.org/x/net/route", 16332- // ... 16333- // ], 16334- // "ImportMap": { 16335- // "golang.org/x/net/dns/dnsmessage": "vendor/golang.org/x/net/dns/dnsmessage", 16336- // "golang.org/x/net/route": "vendor/golang.org/x/net/route" 16337- // }, 16338- // ... 16339- // } 16340- // { 16341- // "ImportPath": "vendor/golang.org/x/net/dns/dnsmessage", 16342- // "Name": "dnsmessage", 16343- // ... 16344- // } 16345- // 16346- // (Beware that, for historical reasons, go list uses 16347- // the JSON field "ImportPath" for the package's 16348- // path--effectively the linker symbol prefix.) 16349- // 16350- // The example above is slightly special to go list 16351- // because it's in the std module. Otherwise, 16352- // vendored modules are simply modules whose directory 16353- // is vendor/ instead of GOMODCACHE, and the 16354- // import path equals the package path. 16355- // 16356- // But in GOPATH (non-module) mode, it's possible for 16357- // package vendoring to cause a non-identity ImportMap, 16358- // as in this example: 16359- // 16360- // $ cd $HOME/src 16361- // $ find . -type f 16362- // ./b/b.go 16363- // ./vendor/example.com/a/a.go 16364- // $ cat ./b/b.go 16365- // package b 16366- // import _ "example.com/a" 16367- // $ cat ./vendor/example.com/a/a.go 16368- // package a 16369- // $ GOPATH=$HOME GO111MODULE=off go list -json ./b | grep -A2 ImportMap 16370- // "ImportMap": { 16371- // "example.com/a": "vendor/example.com/a" 16372- // }, 16373- 16374- // Don't remember any imports with significant errors. 16375- // 16376- // The len=0 condition is a heuristic check for imports of 16377- // non-existent packages (for which go/packages will create 16378- // an edge to a synthesized node). The heuristic is unsound 16379- // because some valid packages have zero files, for example, 16380- // a directory containing only the file p_test.go defines an 16381- // empty package p. 16382- // TODO(adonovan): clarify this. Perhaps go/packages should 16383- // report which nodes were synthesized. 16384- if importPath != "unsafe" && len(imported.CompiledGoFiles) == 0 { 16385- depsByImpPath[importPath] = "" // missing 16386- continue 16387- } 16388- 16389- depsByImpPath[importPath] = PackageID(imported.ID) 16390- depsByPkgPath[PackagePath(imported.PkgPath)] = PackageID(imported.ID) 16391- if err := buildMetadata(ctx, imported, cfg, query, updates, append(path, id)); err != nil { 16392- event.Error(ctx, "error in dependency", err) 16393- } 16394- } 16395- m.DepsByImpPath = depsByImpPath 16396- m.DepsByPkgPath = depsByPkgPath 16397- 16398- // m.Diagnostics is set later in the loading pass, using 16399- // computeLoadDiagnostics. 16400- 16401- return nil 16402-} 16403- 16404-// computeLoadDiagnostics computes and sets m.Diagnostics for the given metadata m. 16405-// 16406-// It should only be called during metadata construction in snapshot.load. 16407-func computeLoadDiagnostics(ctx context.Context, m *source.Metadata, meta *metadataGraph, fs source.FileSource, workspacePackages map[PackageID]PackagePath) error { 16408- for _, packagesErr := range m.Errors { 16409- // Filter out parse errors from go list. We'll get them when we 16410- // actually parse, and buggy overlay support may generate spurious 16411- // errors. (See TestNewModule_Issue38207.) 16412- if strings.Contains(packagesErr.Msg, "expected '") { 16413- continue 16414- } 16415- pkgDiags, err := goPackagesErrorDiagnostics(ctx, packagesErr, m, fs) 16416- if err != nil { 16417- // There are certain cases where the go command returns invalid 16418- // positions, so we cannot panic or even bug.Reportf here. 16419- event.Error(ctx, "unable to compute positions for list errors", err, tag.Package.Of(string(m.ID))) 16420- continue 16421- } 16422- m.Diagnostics = append(m.Diagnostics, pkgDiags...) 16423- } 16424- 16425- // TODO(rfindley): this is buggy: an insignificant change to a modfile 16426- // (or an unsaved modfile) could affect the position of deps errors, 16427- // without invalidating the package. 16428- depsDiags, err := depsErrors(ctx, m, meta, fs, workspacePackages) 16429- if err != nil { 16430- if ctx.Err() == nil { 16431- // TODO(rfindley): consider making this a bug.Reportf. depsErrors should 16432- // not normally fail. 16433- event.Error(ctx, "unable to compute deps errors", err, tag.Package.Of(string(m.ID))) 16434- } 16435- return nil 16436- } 16437- m.Diagnostics = append(m.Diagnostics, depsDiags...) 16438- return nil 16439-} 16440- 16441-// containsPackageLocked reports whether p is a workspace package for the 16442-// snapshot s. 16443-// 16444-// s.mu must be held while calling this function. 16445-func containsPackageLocked(s *snapshot, m *source.Metadata) bool { 16446- // In legacy workspace mode, or if a package does not have an associated 16447- // module, a package is considered inside the workspace if any of its files 16448- // are under the workspace root (and not excluded). 16449- // 16450- // Otherwise if the package has a module it must be an active module (as 16451- // defined by the module root or go.work file) and at least one file must not 16452- // be filtered out by directoryFilters. 16453- // 16454- // TODO(rfindley): revisit this function. We should not need to predicate on 16455- // gowork != "". It should suffice to consider workspace mod files (also, we 16456- // will hopefully eliminate the concept of a workspace package soon). 16457- if m.Module != nil && s.view.gowork != "" { 16458- modURI := span.URIFromPath(m.Module.GoMod) 16459- _, ok := s.workspaceModFiles[modURI] 16460- if !ok { 16461- return false 16462- } 16463- 16464- uris := map[span.URI]struct{}{} 16465- for _, uri := range m.CompiledGoFiles { 16466- uris[uri] = struct{}{} 16467- } 16468- for _, uri := range m.GoFiles { 16469- uris[uri] = struct{}{} 16470- } 16471- 16472- filterFunc := s.view.filterFunc() 16473- for uri := range uris { 16474- // Don't use view.contains here. go.work files may include modules 16475- // outside of the workspace folder. 16476- if !strings.Contains(string(uri), "/vendor/") && !filterFunc(uri) { 16477- return true 16478- } 16479- } 16480- return false 16481- } 16482- 16483- return containsFileInWorkspaceLocked(s, m) 16484-} 16485- 16486-// containsOpenFileLocked reports whether any file referenced by m is open in 16487-// the snapshot s. 16488-// 16489-// s.mu must be held while calling this function. 16490-func containsOpenFileLocked(s *snapshot, m *source.Metadata) bool { 16491- uris := map[span.URI]struct{}{} 16492- for _, uri := range m.CompiledGoFiles { 16493- uris[uri] = struct{}{} 16494- } 16495- for _, uri := range m.GoFiles { 16496- uris[uri] = struct{}{} 16497- } 16498- 16499- for uri := range uris { 16500- if s.isOpenLocked(uri) { 16501- return true 16502- } 16503- } 16504- return false 16505-} 16506- 16507-// containsFileInWorkspaceLocked reports whether m contains any file inside the 16508-// workspace of the snapshot s. 16509-// 16510-// s.mu must be held while calling this function. 16511-func containsFileInWorkspaceLocked(s *snapshot, m *source.Metadata) bool { 16512- uris := map[span.URI]struct{}{} 16513- for _, uri := range m.CompiledGoFiles { 16514- uris[uri] = struct{}{} 16515- } 16516- for _, uri := range m.GoFiles { 16517- uris[uri] = struct{}{} 16518- } 16519- 16520- for uri := range uris { 16521- // In order for a package to be considered for the workspace, at least one 16522- // file must be contained in the workspace and not vendored. 16523- 16524- // The package's files are in this view. It may be a workspace package. 16525- // Vendored packages are not likely to be interesting to the user. 16526- if !strings.Contains(string(uri), "/vendor/") && s.view.contains(uri) { 16527- return true 16528- } 16529- } 16530- return false 16531-} 16532- 16533-// computeWorkspacePackagesLocked computes workspace packages in the snapshot s 16534-// for the given metadata graph. 16535-// 16536-// s.mu must be held while calling this function. 16537-func computeWorkspacePackagesLocked(s *snapshot, meta *metadataGraph) map[PackageID]PackagePath { 16538- workspacePackages := make(map[PackageID]PackagePath) 16539- for _, m := range meta.metadata { 16540- if !containsPackageLocked(s, m) { 16541- continue 16542- } 16543- 16544- if source.IsCommandLineArguments(m.ID) { 16545- // If all the files contained in m have a real package, we don't need to 16546- // keep m as a workspace package. 16547- if allFilesHaveRealPackages(meta, m) { 16548- continue 16549- } 16550- 16551- // We only care about command-line-arguments packages if they are still 16552- // open. 16553- if !containsOpenFileLocked(s, m) { 16554- continue 16555- } 16556- } 16557- 16558- switch { 16559- case m.ForTest == "": 16560- // A normal package. 16561- workspacePackages[m.ID] = m.PkgPath 16562- case m.ForTest == m.PkgPath, m.ForTest+"_test" == m.PkgPath: 16563- // The test variant of some workspace package or its x_test. 16564- // To load it, we need to load the non-test variant with -test. 16565- // 16566- // Notably, this excludes intermediate test variants from workspace 16567- // packages. 16568- workspacePackages[m.ID] = m.ForTest 16569- } 16570- } 16571- return workspacePackages 16572-} 16573- 16574-// allFilesHaveRealPackages reports whether all files referenced by m are 16575-// contained in a "real" package (not command-line-arguments). 16576-// 16577-// If m is valid but all "real" packages containing any file are invalid, this 16578-// function returns false. 16579-// 16580-// If m is not a command-line-arguments package, this is trivially true. 16581-func allFilesHaveRealPackages(g *metadataGraph, m *source.Metadata) bool { 16582- n := len(m.CompiledGoFiles) 16583-checkURIs: 16584- for _, uri := range append(m.CompiledGoFiles[0:n:n], m.GoFiles...) { 16585- for _, id := range g.ids[uri] { 16586- if !source.IsCommandLineArguments(id) { 16587- continue checkURIs 16588- } 16589- } 16590- return false 16591- } 16592- return true 16593-} 16594- 16595-func isTestMain(pkg *packages.Package, gocache string) bool { 16596- // Test mains must have an import path that ends with ".test". 16597- if !strings.HasSuffix(pkg.PkgPath, ".test") { 16598- return false 16599- } 16600- // Test main packages are always named "main". 16601- if pkg.Name != "main" { 16602- return false 16603- } 16604- // Test mains always have exactly one GoFile that is in the build cache. 16605- if len(pkg.GoFiles) > 1 { 16606- return false 16607- } 16608- if !source.InDir(gocache, pkg.GoFiles[0]) { 16609- return false 16610- } 16611- return true 16612-} 16613diff -urN a/gopls/internal/lsp/cache/maps.go b/gopls/internal/lsp/cache/maps.go 16614--- a/gopls/internal/lsp/cache/maps.go 2000-01-01 00:00:00.000000000 -0000 16615+++ b/gopls/internal/lsp/cache/maps.go 1970-01-01 00:00:00.000000000 +0000 16616@@ -1,121 +0,0 @@ 16617-// Copyright 2022 The Go Authors. All rights reserved. 16618-// Use of this source code is governed by a BSD-style 16619-// license that can be found in the LICENSE file. 16620- 16621-package cache 16622- 16623-import ( 16624- "strings" 16625- 16626- "golang.org/x/tools/gopls/internal/lsp/source" 16627- "golang.org/x/tools/gopls/internal/span" 16628- "golang.org/x/tools/internal/persistent" 16629-) 16630- 16631-// TODO(euroelessar): Use generics once support for go1.17 is dropped. 16632- 16633-type filesMap struct { 16634- impl *persistent.Map 16635-} 16636- 16637-// uriLessInterface is the < relation for "any" values containing span.URIs. 16638-func uriLessInterface(a, b interface{}) bool { 16639- return a.(span.URI) < b.(span.URI) 16640-} 16641- 16642-func newFilesMap() filesMap { 16643- return filesMap{ 16644- impl: persistent.NewMap(uriLessInterface), 16645- } 16646-} 16647- 16648-func (m filesMap) Clone() filesMap { 16649- return filesMap{ 16650- impl: m.impl.Clone(), 16651- } 16652-} 16653- 16654-func (m filesMap) Destroy() { 16655- m.impl.Destroy() 16656-} 16657- 16658-func (m filesMap) Get(key span.URI) (source.FileHandle, bool) { 16659- value, ok := m.impl.Get(key) 16660- if !ok { 16661- return nil, false 16662- } 16663- return value.(source.FileHandle), true 16664-} 16665- 16666-func (m filesMap) Range(do func(key span.URI, value source.FileHandle)) { 16667- m.impl.Range(func(key, value interface{}) { 16668- do(key.(span.URI), value.(source.FileHandle)) 16669- }) 16670-} 16671- 16672-func (m filesMap) Set(key span.URI, value source.FileHandle) { 16673- m.impl.Set(key, value, nil) 16674-} 16675- 16676-func (m filesMap) Delete(key span.URI) { 16677- m.impl.Delete(key) 16678-} 16679- 16680-func packageIDLessInterface(x, y interface{}) bool { 16681- return x.(PackageID) < y.(PackageID) 16682-} 16683- 16684-type knownDirsSet struct { 16685- impl *persistent.Map 16686-} 16687- 16688-func newKnownDirsSet() knownDirsSet { 16689- return knownDirsSet{ 16690- impl: persistent.NewMap(func(a, b interface{}) bool { 16691- return a.(span.URI) < b.(span.URI) 16692- }), 16693- } 16694-} 16695- 16696-func (s knownDirsSet) Clone() knownDirsSet { 16697- return knownDirsSet{ 16698- impl: s.impl.Clone(), 16699- } 16700-} 16701- 16702-func (s knownDirsSet) Destroy() { 16703- s.impl.Destroy() 16704-} 16705- 16706-func (s knownDirsSet) Contains(key span.URI) bool { 16707- _, ok := s.impl.Get(key) 16708- return ok 16709-} 16710- 16711-func (s knownDirsSet) Range(do func(key span.URI)) { 16712- s.impl.Range(func(key, value interface{}) { 16713- do(key.(span.URI)) 16714- }) 16715-} 16716- 16717-func (s knownDirsSet) SetAll(other knownDirsSet) { 16718- s.impl.SetAll(other.impl) 16719-} 16720- 16721-func (s knownDirsSet) Insert(key span.URI) { 16722- s.impl.Set(key, nil, nil) 16723-} 16724- 16725-func (s knownDirsSet) Remove(key span.URI) { 16726- s.impl.Delete(key) 16727-} 16728- 16729-// analysisKeyLessInterface is the less-than relation for analysisKey 16730-// values wrapped in an interface. 16731-func analysisKeyLessInterface(a, b interface{}) bool { 16732- x, y := a.(analysisKey), b.(analysisKey) 16733- if cmp := strings.Compare(x.analyzerNames, y.analyzerNames); cmp != 0 { 16734- return cmp < 0 16735- } 16736- return x.pkgid < y.pkgid 16737-} 16738diff -urN a/gopls/internal/lsp/cache/mod.go b/gopls/internal/lsp/cache/mod.go 16739--- a/gopls/internal/lsp/cache/mod.go 2000-01-01 00:00:00.000000000 -0000 16740+++ b/gopls/internal/lsp/cache/mod.go 1970-01-01 00:00:00.000000000 +0000 16741@@ -1,522 +0,0 @@ 16742-// Copyright 2019 The Go Authors. All rights reserved. 16743-// Use of this source code is governed by a BSD-style 16744-// license that can be found in the LICENSE file. 16745- 16746-package cache 16747- 16748-import ( 16749- "context" 16750- "errors" 16751- "fmt" 16752- "path/filepath" 16753- "regexp" 16754- "strings" 16755- 16756- "golang.org/x/mod/modfile" 16757- "golang.org/x/mod/module" 16758- "golang.org/x/tools/gopls/internal/lsp/command" 16759- "golang.org/x/tools/gopls/internal/lsp/protocol" 16760- "golang.org/x/tools/gopls/internal/lsp/source" 16761- "golang.org/x/tools/gopls/internal/span" 16762- "golang.org/x/tools/internal/event" 16763- "golang.org/x/tools/internal/event/tag" 16764- "golang.org/x/tools/internal/gocommand" 16765- "golang.org/x/tools/internal/memoize" 16766-) 16767- 16768-// ParseMod parses a go.mod file, using a cache. It may return partial results and an error. 16769-func (s *snapshot) ParseMod(ctx context.Context, fh source.FileHandle) (*source.ParsedModule, error) { 16770- uri := fh.URI() 16771- 16772- s.mu.Lock() 16773- entry, hit := s.parseModHandles.Get(uri) 16774- s.mu.Unlock() 16775- 16776- type parseModKey source.FileIdentity 16777- type parseModResult struct { 16778- parsed *source.ParsedModule 16779- err error 16780- } 16781- 16782- // cache miss? 16783- if !hit { 16784- promise, release := s.store.Promise(parseModKey(fh.FileIdentity()), func(ctx context.Context, _ interface{}) interface{} { 16785- parsed, err := parseModImpl(ctx, fh) 16786- return parseModResult{parsed, err} 16787- }) 16788- 16789- entry = promise 16790- s.mu.Lock() 16791- s.parseModHandles.Set(uri, entry, func(_, _ interface{}) { release() }) 16792- s.mu.Unlock() 16793- } 16794- 16795- // Await result. 16796- v, err := s.awaitPromise(ctx, entry.(*memoize.Promise)) 16797- if err != nil { 16798- return nil, err 16799- } 16800- res := v.(parseModResult) 16801- return res.parsed, res.err 16802-} 16803- 16804-// parseModImpl parses the go.mod file whose name and contents are in fh. 16805-// It may return partial results and an error. 16806-func parseModImpl(ctx context.Context, fh source.FileHandle) (*source.ParsedModule, error) { 16807- _, done := event.Start(ctx, "cache.ParseMod", tag.URI.Of(fh.URI())) 16808- defer done() 16809- 16810- contents, err := fh.Read() 16811- if err != nil { 16812- return nil, err 16813- } 16814- m := protocol.NewMapper(fh.URI(), contents) 16815- file, parseErr := modfile.Parse(fh.URI().Filename(), contents, nil) 16816- // Attempt to convert the error to a standardized parse error. 16817- var parseErrors []*source.Diagnostic 16818- if parseErr != nil { 16819- mfErrList, ok := parseErr.(modfile.ErrorList) 16820- if !ok { 16821- return nil, fmt.Errorf("unexpected parse error type %v", parseErr) 16822- } 16823- for _, mfErr := range mfErrList { 16824- rng, err := m.OffsetRange(mfErr.Pos.Byte, mfErr.Pos.Byte) 16825- if err != nil { 16826- return nil, err 16827- } 16828- parseErrors = append(parseErrors, &source.Diagnostic{ 16829- URI: fh.URI(), 16830- Range: rng, 16831- Severity: protocol.SeverityError, 16832- Source: source.ParseError, 16833- Message: mfErr.Err.Error(), 16834- }) 16835- } 16836- } 16837- return &source.ParsedModule{ 16838- URI: fh.URI(), 16839- Mapper: m, 16840- File: file, 16841- ParseErrors: parseErrors, 16842- }, parseErr 16843-} 16844- 16845-// ParseWork parses a go.work file, using a cache. It may return partial results and an error. 16846-// TODO(adonovan): move to new work.go file. 16847-func (s *snapshot) ParseWork(ctx context.Context, fh source.FileHandle) (*source.ParsedWorkFile, error) { 16848- uri := fh.URI() 16849- 16850- s.mu.Lock() 16851- entry, hit := s.parseWorkHandles.Get(uri) 16852- s.mu.Unlock() 16853- 16854- type parseWorkKey source.FileIdentity 16855- type parseWorkResult struct { 16856- parsed *source.ParsedWorkFile 16857- err error 16858- } 16859- 16860- // cache miss? 16861- if !hit { 16862- handle, release := s.store.Promise(parseWorkKey(fh.FileIdentity()), func(ctx context.Context, _ interface{}) interface{} { 16863- parsed, err := parseWorkImpl(ctx, fh) 16864- return parseWorkResult{parsed, err} 16865- }) 16866- 16867- entry = handle 16868- s.mu.Lock() 16869- s.parseWorkHandles.Set(uri, entry, func(_, _ interface{}) { release() }) 16870- s.mu.Unlock() 16871- } 16872- 16873- // Await result. 16874- v, err := s.awaitPromise(ctx, entry.(*memoize.Promise)) 16875- if err != nil { 16876- return nil, err 16877- } 16878- res := v.(parseWorkResult) 16879- return res.parsed, res.err 16880-} 16881- 16882-// parseWorkImpl parses a go.work file. It may return partial results and an error. 16883-func parseWorkImpl(ctx context.Context, fh source.FileHandle) (*source.ParsedWorkFile, error) { 16884- _, done := event.Start(ctx, "cache.ParseWork", tag.URI.Of(fh.URI())) 16885- defer done() 16886- 16887- contents, err := fh.Read() 16888- if err != nil { 16889- return nil, err 16890- } 16891- m := protocol.NewMapper(fh.URI(), contents) 16892- file, parseErr := modfile.ParseWork(fh.URI().Filename(), contents, nil) 16893- // Attempt to convert the error to a standardized parse error. 16894- var parseErrors []*source.Diagnostic 16895- if parseErr != nil { 16896- mfErrList, ok := parseErr.(modfile.ErrorList) 16897- if !ok { 16898- return nil, fmt.Errorf("unexpected parse error type %v", parseErr) 16899- } 16900- for _, mfErr := range mfErrList { 16901- rng, err := m.OffsetRange(mfErr.Pos.Byte, mfErr.Pos.Byte) 16902- if err != nil { 16903- return nil, err 16904- } 16905- parseErrors = append(parseErrors, &source.Diagnostic{ 16906- URI: fh.URI(), 16907- Range: rng, 16908- Severity: protocol.SeverityError, 16909- Source: source.ParseError, 16910- Message: mfErr.Err.Error(), 16911- }) 16912- } 16913- } 16914- return &source.ParsedWorkFile{ 16915- URI: fh.URI(), 16916- Mapper: m, 16917- File: file, 16918- ParseErrors: parseErrors, 16919- }, parseErr 16920-} 16921- 16922-// goSum reads the go.sum file for the go.mod file at modURI, if it exists. If 16923-// it doesn't exist, it returns nil. 16924-func (s *snapshot) goSum(ctx context.Context, modURI span.URI) []byte { 16925- // Get the go.sum file, either from the snapshot or directly from the 16926- // cache. Avoid (*snapshot).GetFile here, as we don't want to add 16927- // nonexistent file handles to the snapshot if the file does not exist. 16928- // 16929- // TODO(rfindley): but that's not right. Changes to sum files should 16930- // invalidate content, even if it's nonexistent content. 16931- sumURI := span.URIFromPath(sumFilename(modURI)) 16932- var sumFH source.FileHandle = s.FindFile(sumURI) 16933- if sumFH == nil { 16934- var err error 16935- sumFH, err = s.view.fs.GetFile(ctx, sumURI) 16936- if err != nil { 16937- return nil 16938- } 16939- } 16940- content, err := sumFH.Read() 16941- if err != nil { 16942- return nil 16943- } 16944- return content 16945-} 16946- 16947-func sumFilename(modURI span.URI) string { 16948- return strings.TrimSuffix(modURI.Filename(), ".mod") + ".sum" 16949-} 16950- 16951-// ModWhy returns the "go mod why" result for each module named in a 16952-// require statement in the go.mod file. 16953-// TODO(adonovan): move to new mod_why.go file. 16954-func (s *snapshot) ModWhy(ctx context.Context, fh source.FileHandle) (map[string]string, error) { 16955- uri := fh.URI() 16956- 16957- if s.View().FileKind(fh) != source.Mod { 16958- return nil, fmt.Errorf("%s is not a go.mod file", uri) 16959- } 16960- 16961- s.mu.Lock() 16962- entry, hit := s.modWhyHandles.Get(uri) 16963- s.mu.Unlock() 16964- 16965- type modWhyResult struct { 16966- why map[string]string 16967- err error 16968- } 16969- 16970- // cache miss? 16971- if !hit { 16972- handle := memoize.NewPromise("modWhy", func(ctx context.Context, arg interface{}) interface{} { 16973- why, err := modWhyImpl(ctx, arg.(*snapshot), fh) 16974- return modWhyResult{why, err} 16975- }) 16976- 16977- entry = handle 16978- s.mu.Lock() 16979- s.modWhyHandles.Set(uri, entry, nil) 16980- s.mu.Unlock() 16981- } 16982- 16983- // Await result. 16984- v, err := s.awaitPromise(ctx, entry.(*memoize.Promise)) 16985- if err != nil { 16986- return nil, err 16987- } 16988- res := v.(modWhyResult) 16989- return res.why, res.err 16990-} 16991- 16992-// modWhyImpl returns the result of "go mod why -m" on the specified go.mod file. 16993-func modWhyImpl(ctx context.Context, snapshot *snapshot, fh source.FileHandle) (map[string]string, error) { 16994- ctx, done := event.Start(ctx, "cache.ModWhy", tag.URI.Of(fh.URI())) 16995- defer done() 16996- 16997- pm, err := snapshot.ParseMod(ctx, fh) 16998- if err != nil { 16999- return nil, err 17000- } 17001- // No requires to explain. 17002- if len(pm.File.Require) == 0 { 17003- return nil, nil // empty result 17004- } 17005- // Run `go mod why` on all the dependencies. 17006- inv := &gocommand.Invocation{ 17007- Verb: "mod", 17008- Args: []string{"why", "-m"}, 17009- WorkingDir: filepath.Dir(fh.URI().Filename()), 17010- } 17011- for _, req := range pm.File.Require { 17012- inv.Args = append(inv.Args, req.Mod.Path) 17013- } 17014- stdout, err := snapshot.RunGoCommandDirect(ctx, source.Normal, inv) 17015- if err != nil { 17016- return nil, err 17017- } 17018- whyList := strings.Split(stdout.String(), "\n\n") 17019- if len(whyList) != len(pm.File.Require) { 17020- return nil, fmt.Errorf("mismatched number of results: got %v, want %v", len(whyList), len(pm.File.Require)) 17021- } 17022- why := make(map[string]string, len(pm.File.Require)) 17023- for i, req := range pm.File.Require { 17024- why[req.Mod.Path] = whyList[i] 17025- } 17026- return why, nil 17027-} 17028- 17029-// extractGoCommandErrors tries to parse errors that come from the go command 17030-// and shape them into go.mod diagnostics. 17031-// TODO: rename this to 'load errors' 17032-func (s *snapshot) extractGoCommandErrors(ctx context.Context, goCmdError error) []*source.Diagnostic { 17033- if goCmdError == nil { 17034- return nil 17035- } 17036- 17037- type locatedErr struct { 17038- spn span.Span 17039- msg string 17040- } 17041- diagLocations := map[*source.ParsedModule]locatedErr{} 17042- backupDiagLocations := map[*source.ParsedModule]locatedErr{} 17043- 17044- // If moduleErrs is non-nil, go command errors are scoped to specific 17045- // modules. 17046- var moduleErrs *moduleErrorMap 17047- _ = errors.As(goCmdError, &moduleErrs) 17048- 17049- // Match the error against all the mod files in the workspace. 17050- for _, uri := range s.ModFiles() { 17051- fh, err := s.GetFile(ctx, uri) 17052- if err != nil { 17053- event.Error(ctx, "getting modfile for Go command error", err) 17054- continue 17055- } 17056- pm, err := s.ParseMod(ctx, fh) 17057- if err != nil { 17058- // Parsing errors are reported elsewhere 17059- return nil 17060- } 17061- var msgs []string // error messages to consider 17062- if moduleErrs != nil { 17063- if pm.File.Module != nil { 17064- for _, mes := range moduleErrs.errs[pm.File.Module.Mod.Path] { 17065- msgs = append(msgs, mes.Error()) 17066- } 17067- } 17068- } else { 17069- msgs = append(msgs, goCmdError.Error()) 17070- } 17071- for _, msg := range msgs { 17072- if strings.Contains(goCmdError.Error(), "errors parsing go.mod") { 17073- // The go command emits parse errors for completely invalid go.mod files. 17074- // Those are reported by our own diagnostics and can be ignored here. 17075- // As of writing, we are not aware of any other errors that include 17076- // file/position information, so don't even try to find it. 17077- continue 17078- } 17079- spn, found, err := s.matchErrorToModule(ctx, pm, msg) 17080- if err != nil { 17081- event.Error(ctx, "matching error to module", err) 17082- continue 17083- } 17084- le := locatedErr{ 17085- spn: spn, 17086- msg: msg, 17087- } 17088- if found { 17089- diagLocations[pm] = le 17090- } else { 17091- backupDiagLocations[pm] = le 17092- } 17093- } 17094- } 17095- 17096- // If we didn't find any good matches, assign diagnostics to all go.mod files. 17097- if len(diagLocations) == 0 { 17098- diagLocations = backupDiagLocations 17099- } 17100- 17101- var srcErrs []*source.Diagnostic 17102- for pm, le := range diagLocations { 17103- diag, err := s.goCommandDiagnostic(pm, le.spn, le.msg) 17104- if err != nil { 17105- event.Error(ctx, "building go command diagnostic", err) 17106- continue 17107- } 17108- srcErrs = append(srcErrs, diag) 17109- } 17110- return srcErrs 17111-} 17112- 17113-var moduleVersionInErrorRe = regexp.MustCompile(`[:\s]([+-._~0-9A-Za-z]+)@([+-._~0-9A-Za-z]+)[:\s]`) 17114- 17115-// matchErrorToModule matches a go command error message to a go.mod file. 17116-// Some examples: 17117-// 17118-// [email protected]: reading example.com/@v/v1.2.2.mod: no such file or directory 17119-// go: github.com/cockroachdb/apd/v2@v2.0.72: reading github.com/cockroachdb/apd/go.mod at revision v2.0.72: unknown revision v2.0.72 17120-// go: [email protected] requires\n\[email protected]: parsing go.mod:\n\tmodule declares its path as: bob.org\n\tbut was required as: random.org 17121-// 17122-// It returns the location of a reference to the one of the modules and true 17123-// if one exists. If none is found it returns a fallback location and false. 17124-func (s *snapshot) matchErrorToModule(ctx context.Context, pm *source.ParsedModule, goCmdError string) (span.Span, bool, error) { 17125- var reference *modfile.Line 17126- matches := moduleVersionInErrorRe.FindAllStringSubmatch(goCmdError, -1) 17127- 17128- for i := len(matches) - 1; i >= 0; i-- { 17129- ver := module.Version{Path: matches[i][1], Version: matches[i][2]} 17130- if err := module.Check(ver.Path, ver.Version); err != nil { 17131- continue 17132- } 17133- reference = findModuleReference(pm.File, ver) 17134- if reference != nil { 17135- break 17136- } 17137- } 17138- 17139- if reference == nil { 17140- // No match for the module path was found in the go.mod file. 17141- // Show the error on the module declaration, if one exists, or 17142- // just the first line of the file. 17143- if pm.File.Module == nil { 17144- return span.New(pm.URI, span.NewPoint(1, 1, 0), span.Point{}), false, nil 17145- } 17146- syntax := pm.File.Module.Syntax 17147- spn, err := pm.Mapper.OffsetSpan(syntax.Start.Byte, syntax.End.Byte) 17148- return spn, false, err 17149- } 17150- 17151- spn, err := pm.Mapper.OffsetSpan(reference.Start.Byte, reference.End.Byte) 17152- return spn, true, err 17153-} 17154- 17155-// goCommandDiagnostic creates a diagnostic for a given go command error. 17156-func (s *snapshot) goCommandDiagnostic(pm *source.ParsedModule, spn span.Span, goCmdError string) (*source.Diagnostic, error) { 17157- rng, err := pm.Mapper.SpanRange(spn) 17158- if err != nil { 17159- return nil, err 17160- } 17161- 17162- matches := moduleVersionInErrorRe.FindAllStringSubmatch(goCmdError, -1) 17163- var innermost *module.Version 17164- for i := len(matches) - 1; i >= 0; i-- { 17165- ver := module.Version{Path: matches[i][1], Version: matches[i][2]} 17166- if err := module.Check(ver.Path, ver.Version); err != nil { 17167- continue 17168- } 17169- innermost = &ver 17170- break 17171- } 17172- 17173- switch { 17174- case strings.Contains(goCmdError, "inconsistent vendoring"): 17175- cmd, err := command.NewVendorCommand("Run go mod vendor", command.URIArg{URI: protocol.URIFromSpanURI(pm.URI)}) 17176- if err != nil { 17177- return nil, err 17178- } 17179- return &source.Diagnostic{ 17180- URI: pm.URI, 17181- Range: rng, 17182- Severity: protocol.SeverityError, 17183- Source: source.ListError, 17184- Message: `Inconsistent vendoring detected. Please re-run "go mod vendor". 17185-See https://github.com/golang/go/issues/39164 for more detail on this issue.`, 17186- SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, 17187- }, nil 17188- 17189- case strings.Contains(goCmdError, "updates to go.sum needed"), strings.Contains(goCmdError, "missing go.sum entry"): 17190- var args []protocol.DocumentURI 17191- for _, uri := range s.ModFiles() { 17192- args = append(args, protocol.URIFromSpanURI(uri)) 17193- } 17194- tidyCmd, err := command.NewTidyCommand("Run go mod tidy", command.URIArgs{URIs: args}) 17195- if err != nil { 17196- return nil, err 17197- } 17198- updateCmd, err := command.NewUpdateGoSumCommand("Update go.sum", command.URIArgs{URIs: args}) 17199- if err != nil { 17200- return nil, err 17201- } 17202- msg := "go.sum is out of sync with go.mod. Please update it by applying the quick fix." 17203- if innermost != nil { 17204- msg = fmt.Sprintf("go.sum is out of sync with go.mod: entry for %v is missing. Please updating it by applying the quick fix.", innermost) 17205- } 17206- return &source.Diagnostic{ 17207- URI: pm.URI, 17208- Range: rng, 17209- Severity: protocol.SeverityError, 17210- Source: source.ListError, 17211- Message: msg, 17212- SuggestedFixes: []source.SuggestedFix{ 17213- source.SuggestedFixFromCommand(tidyCmd, protocol.QuickFix), 17214- source.SuggestedFixFromCommand(updateCmd, protocol.QuickFix), 17215- }, 17216- }, nil 17217- case strings.Contains(goCmdError, "disabled by GOPROXY=off") && innermost != nil: 17218- title := fmt.Sprintf("Download %v@%v", innermost.Path, innermost.Version) 17219- cmd, err := command.NewAddDependencyCommand(title, command.DependencyArgs{ 17220- URI: protocol.URIFromSpanURI(pm.URI), 17221- AddRequire: false, 17222- GoCmdArgs: []string{fmt.Sprintf("%v@%v", innermost.Path, innermost.Version)}, 17223- }) 17224- if err != nil { 17225- return nil, err 17226- } 17227- return &source.Diagnostic{ 17228- URI: pm.URI, 17229- Range: rng, 17230- Severity: protocol.SeverityError, 17231- Message: fmt.Sprintf("%v@%v has not been downloaded", innermost.Path, innermost.Version), 17232- Source: source.ListError, 17233- SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, 17234- }, nil 17235- default: 17236- return &source.Diagnostic{ 17237- URI: pm.URI, 17238- Range: rng, 17239- Severity: protocol.SeverityError, 17240- Source: source.ListError, 17241- Message: goCmdError, 17242- }, nil 17243- } 17244-} 17245- 17246-func findModuleReference(mf *modfile.File, ver module.Version) *modfile.Line { 17247- for _, req := range mf.Require { 17248- if req.Mod == ver { 17249- return req.Syntax 17250- } 17251- } 17252- for _, ex := range mf.Exclude { 17253- if ex.Mod == ver { 17254- return ex.Syntax 17255- } 17256- } 17257- for _, rep := range mf.Replace { 17258- if rep.New == ver || rep.Old == ver { 17259- return rep.Syntax 17260- } 17261- } 17262- return nil 17263-} 17264diff -urN a/gopls/internal/lsp/cache/mod_tidy.go b/gopls/internal/lsp/cache/mod_tidy.go 17265--- a/gopls/internal/lsp/cache/mod_tidy.go 2000-01-01 00:00:00.000000000 -0000 17266+++ b/gopls/internal/lsp/cache/mod_tidy.go 1970-01-01 00:00:00.000000000 +0000 17267@@ -1,469 +0,0 @@ 17268-// Copyright 2020 The Go Authors. All rights reserved. 17269-// Use of this source code is governed by a BSD-style 17270-// license that can be found in the LICENSE file. 17271- 17272-package cache 17273- 17274-import ( 17275- "context" 17276- "fmt" 17277- "go/ast" 17278- "io/ioutil" 17279- "os" 17280- "path/filepath" 17281- "strconv" 17282- "strings" 17283- 17284- "golang.org/x/mod/modfile" 17285- "golang.org/x/tools/gopls/internal/lsp/command" 17286- "golang.org/x/tools/gopls/internal/lsp/protocol" 17287- "golang.org/x/tools/gopls/internal/lsp/source" 17288- "golang.org/x/tools/gopls/internal/span" 17289- "golang.org/x/tools/internal/event" 17290- "golang.org/x/tools/internal/event/tag" 17291- "golang.org/x/tools/internal/gocommand" 17292- "golang.org/x/tools/internal/memoize" 17293-) 17294- 17295-// ModTidy returns the go.mod file that would be obtained by running 17296-// "go mod tidy". Concurrent requests are combined into a single command. 17297-func (s *snapshot) ModTidy(ctx context.Context, pm *source.ParsedModule) (*source.TidiedModule, error) { 17298- uri := pm.URI 17299- if pm.File == nil { 17300- return nil, fmt.Errorf("cannot tidy unparseable go.mod file: %v", uri) 17301- } 17302- 17303- s.mu.Lock() 17304- entry, hit := s.modTidyHandles.Get(uri) 17305- s.mu.Unlock() 17306- 17307- type modTidyResult struct { 17308- tidied *source.TidiedModule 17309- err error 17310- } 17311- 17312- // Cache miss? 17313- if !hit { 17314- // If the file handle is an overlay, it may not be written to disk. 17315- // The go.mod file has to be on disk for `go mod tidy` to work. 17316- // TODO(rfindley): is this still true with Go 1.16 overlay support? 17317- fh, err := s.GetFile(ctx, pm.URI) 17318- if err != nil { 17319- return nil, err 17320- } 17321- if _, ok := fh.(*Overlay); ok { 17322- if info, _ := os.Stat(uri.Filename()); info == nil { 17323- return nil, source.ErrNoModOnDisk 17324- } 17325- } 17326- 17327- if criticalErr := s.GetCriticalError(ctx); criticalErr != nil { 17328- return &source.TidiedModule{ 17329- Diagnostics: criticalErr.Diagnostics, 17330- }, nil 17331- } 17332- if ctx.Err() != nil { // must check ctx after GetCriticalError 17333- return nil, ctx.Err() 17334- } 17335- 17336- if err := s.awaitLoaded(ctx); err != nil { 17337- return nil, err 17338- } 17339- 17340- handle := memoize.NewPromise("modTidy", func(ctx context.Context, arg interface{}) interface{} { 17341- tidied, err := modTidyImpl(ctx, arg.(*snapshot), uri.Filename(), pm) 17342- return modTidyResult{tidied, err} 17343- }) 17344- 17345- entry = handle 17346- s.mu.Lock() 17347- s.modTidyHandles.Set(uri, entry, nil) 17348- s.mu.Unlock() 17349- } 17350- 17351- // Await result. 17352- v, err := s.awaitPromise(ctx, entry.(*memoize.Promise)) 17353- if err != nil { 17354- return nil, err 17355- } 17356- res := v.(modTidyResult) 17357- return res.tidied, res.err 17358-} 17359- 17360-// modTidyImpl runs "go mod tidy" on a go.mod file. 17361-func modTidyImpl(ctx context.Context, snapshot *snapshot, filename string, pm *source.ParsedModule) (*source.TidiedModule, error) { 17362- ctx, done := event.Start(ctx, "cache.ModTidy", tag.URI.Of(filename)) 17363- defer done() 17364- 17365- inv := &gocommand.Invocation{ 17366- Verb: "mod", 17367- Args: []string{"tidy"}, 17368- WorkingDir: filepath.Dir(filename), 17369- } 17370- // TODO(adonovan): ensure that unsaved overlays are passed through to 'go'. 17371- tmpURI, inv, cleanup, err := snapshot.goCommandInvocation(ctx, source.WriteTemporaryModFile, inv) 17372- if err != nil { 17373- return nil, err 17374- } 17375- // Keep the temporary go.mod file around long enough to parse it. 17376- defer cleanup() 17377- 17378- if _, err := snapshot.view.gocmdRunner.Run(ctx, *inv); err != nil { 17379- return nil, err 17380- } 17381- 17382- // Go directly to disk to get the temporary mod file, 17383- // since it is always on disk. 17384- tempContents, err := ioutil.ReadFile(tmpURI.Filename()) 17385- if err != nil { 17386- return nil, err 17387- } 17388- ideal, err := modfile.Parse(tmpURI.Filename(), tempContents, nil) 17389- if err != nil { 17390- // We do not need to worry about the temporary file's parse errors 17391- // since it has been "tidied". 17392- return nil, err 17393- } 17394- 17395- // Compare the original and tidied go.mod files to compute errors and 17396- // suggested fixes. 17397- diagnostics, err := modTidyDiagnostics(ctx, snapshot, pm, ideal) 17398- if err != nil { 17399- return nil, err 17400- } 17401- 17402- return &source.TidiedModule{ 17403- Diagnostics: diagnostics, 17404- TidiedContent: tempContents, 17405- }, nil 17406-} 17407- 17408-// modTidyDiagnostics computes the differences between the original and tidied 17409-// go.mod files to produce diagnostic and suggested fixes. Some diagnostics 17410-// may appear on the Go files that import packages from missing modules. 17411-func modTidyDiagnostics(ctx context.Context, snapshot *snapshot, pm *source.ParsedModule, ideal *modfile.File) (diagnostics []*source.Diagnostic, err error) { 17412- // First, determine which modules are unused and which are missing from the 17413- // original go.mod file. 17414- var ( 17415- unused = make(map[string]*modfile.Require, len(pm.File.Require)) 17416- missing = make(map[string]*modfile.Require, len(ideal.Require)) 17417- wrongDirectness = make(map[string]*modfile.Require, len(pm.File.Require)) 17418- ) 17419- for _, req := range pm.File.Require { 17420- unused[req.Mod.Path] = req 17421- } 17422- for _, req := range ideal.Require { 17423- origReq := unused[req.Mod.Path] 17424- if origReq == nil { 17425- missing[req.Mod.Path] = req 17426- continue 17427- } else if origReq.Indirect != req.Indirect { 17428- wrongDirectness[req.Mod.Path] = origReq 17429- } 17430- delete(unused, req.Mod.Path) 17431- } 17432- for _, req := range wrongDirectness { 17433- // Handle dependencies that are incorrectly labeled indirect and 17434- // vice versa. 17435- srcDiag, err := directnessDiagnostic(pm.Mapper, req, snapshot.View().Options().ComputeEdits) 17436- if err != nil { 17437- // We're probably in a bad state if we can't compute a 17438- // directnessDiagnostic, but try to keep going so as to not suppress 17439- // other, valid diagnostics. 17440- event.Error(ctx, "computing directness diagnostic", err) 17441- continue 17442- } 17443- diagnostics = append(diagnostics, srcDiag) 17444- } 17445- // Next, compute any diagnostics for modules that are missing from the 17446- // go.mod file. The fixes will be for the go.mod file, but the 17447- // diagnostics should also appear in both the go.mod file and the import 17448- // statements in the Go files in which the dependencies are used. 17449- missingModuleFixes := map[*modfile.Require][]source.SuggestedFix{} 17450- for _, req := range missing { 17451- srcDiag, err := missingModuleDiagnostic(pm, req) 17452- if err != nil { 17453- return nil, err 17454- } 17455- missingModuleFixes[req] = srcDiag.SuggestedFixes 17456- diagnostics = append(diagnostics, srcDiag) 17457- } 17458- // Add diagnostics for missing modules anywhere they are imported in the 17459- // workspace. 17460- // TODO(adonovan): opt: opportunities for parallelism abound. 17461- for _, m := range snapshot.workspaceMetadata() { 17462- // Read both lists of files of this package, in parallel. 17463- goFiles, compiledGoFiles, err := readGoFiles(ctx, snapshot, m) 17464- if err != nil { 17465- return nil, err 17466- } 17467- 17468- missingImports := map[string]*modfile.Require{} 17469- 17470- // If -mod=readonly is not set we may have successfully imported 17471- // packages from missing modules. Otherwise they'll be in 17472- // MissingDependencies. Combine both. 17473- imps, err := parseImports(ctx, snapshot, goFiles) 17474- if err != nil { 17475- return nil, err 17476- } 17477- for imp := range imps { 17478- if req, ok := missing[imp]; ok { 17479- missingImports[imp] = req 17480- break 17481- } 17482- // If the import is a package of the dependency, then add the 17483- // package to the map, this will eliminate the need to do this 17484- // prefix package search on each import for each file. 17485- // Example: 17486- // 17487- // import ( 17488- // "golang.org/x/tools/go/expect" 17489- // "golang.org/x/tools/go/packages" 17490- // ) 17491- // They both are related to the same module: "golang.org/x/tools". 17492- var match string 17493- for _, req := range ideal.Require { 17494- if strings.HasPrefix(imp, req.Mod.Path) && len(req.Mod.Path) > len(match) { 17495- match = req.Mod.Path 17496- } 17497- } 17498- if req, ok := missing[match]; ok { 17499- missingImports[imp] = req 17500- } 17501- } 17502- // None of this package's imports are from missing modules. 17503- if len(missingImports) == 0 { 17504- continue 17505- } 17506- for _, goFile := range compiledGoFiles { 17507- pgf, err := snapshot.ParseGo(ctx, goFile, source.ParseHeader) 17508- if err != nil { 17509- continue 17510- } 17511- file, m := pgf.File, pgf.Mapper 17512- if file == nil || m == nil { 17513- continue 17514- } 17515- imports := make(map[string]*ast.ImportSpec) 17516- for _, imp := range file.Imports { 17517- if imp.Path == nil { 17518- continue 17519- } 17520- if target, err := strconv.Unquote(imp.Path.Value); err == nil { 17521- imports[target] = imp 17522- } 17523- } 17524- if len(imports) == 0 { 17525- continue 17526- } 17527- for importPath, req := range missingImports { 17528- imp, ok := imports[importPath] 17529- if !ok { 17530- continue 17531- } 17532- fixes, ok := missingModuleFixes[req] 17533- if !ok { 17534- return nil, fmt.Errorf("no missing module fix for %q (%q)", importPath, req.Mod.Path) 17535- } 17536- srcErr, err := missingModuleForImport(pgf, imp, req, fixes) 17537- if err != nil { 17538- return nil, err 17539- } 17540- diagnostics = append(diagnostics, srcErr) 17541- } 17542- } 17543- } 17544- // Finally, add errors for any unused dependencies. 17545- onlyDiagnostic := len(diagnostics) == 0 && len(unused) == 1 17546- for _, req := range unused { 17547- srcErr, err := unusedDiagnostic(pm.Mapper, req, onlyDiagnostic) 17548- if err != nil { 17549- return nil, err 17550- } 17551- diagnostics = append(diagnostics, srcErr) 17552- } 17553- return diagnostics, nil 17554-} 17555- 17556-// unusedDiagnostic returns a source.Diagnostic for an unused require. 17557-func unusedDiagnostic(m *protocol.Mapper, req *modfile.Require, onlyDiagnostic bool) (*source.Diagnostic, error) { 17558- rng, err := m.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) 17559- if err != nil { 17560- return nil, err 17561- } 17562- title := fmt.Sprintf("Remove dependency: %s", req.Mod.Path) 17563- cmd, err := command.NewRemoveDependencyCommand(title, command.RemoveDependencyArgs{ 17564- URI: protocol.URIFromSpanURI(m.URI), 17565- OnlyDiagnostic: onlyDiagnostic, 17566- ModulePath: req.Mod.Path, 17567- }) 17568- if err != nil { 17569- return nil, err 17570- } 17571- return &source.Diagnostic{ 17572- URI: m.URI, 17573- Range: rng, 17574- Severity: protocol.SeverityWarning, 17575- Source: source.ModTidyError, 17576- Message: fmt.Sprintf("%s is not used in this module", req.Mod.Path), 17577- SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, 17578- }, nil 17579-} 17580- 17581-// directnessDiagnostic extracts errors when a dependency is labeled indirect when 17582-// it should be direct and vice versa. 17583-func directnessDiagnostic(m *protocol.Mapper, req *modfile.Require, computeEdits source.DiffFunction) (*source.Diagnostic, error) { 17584- rng, err := m.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) 17585- if err != nil { 17586- return nil, err 17587- } 17588- direction := "indirect" 17589- if req.Indirect { 17590- direction = "direct" 17591- 17592- // If the dependency should be direct, just highlight the // indirect. 17593- if comments := req.Syntax.Comment(); comments != nil && len(comments.Suffix) > 0 { 17594- end := comments.Suffix[0].Start 17595- end.LineRune += len(comments.Suffix[0].Token) 17596- end.Byte += len(comments.Suffix[0].Token) 17597- rng, err = m.OffsetRange(comments.Suffix[0].Start.Byte, end.Byte) 17598- if err != nil { 17599- return nil, err 17600- } 17601- } 17602- } 17603- // If the dependency should be indirect, add the // indirect. 17604- edits, err := switchDirectness(req, m, computeEdits) 17605- if err != nil { 17606- return nil, err 17607- } 17608- return &source.Diagnostic{ 17609- URI: m.URI, 17610- Range: rng, 17611- Severity: protocol.SeverityWarning, 17612- Source: source.ModTidyError, 17613- Message: fmt.Sprintf("%s should be %s", req.Mod.Path, direction), 17614- SuggestedFixes: []source.SuggestedFix{{ 17615- Title: fmt.Sprintf("Change %s to %s", req.Mod.Path, direction), 17616- Edits: map[span.URI][]protocol.TextEdit{ 17617- m.URI: edits, 17618- }, 17619- ActionKind: protocol.QuickFix, 17620- }}, 17621- }, nil 17622-} 17623- 17624-func missingModuleDiagnostic(pm *source.ParsedModule, req *modfile.Require) (*source.Diagnostic, error) { 17625- var rng protocol.Range 17626- // Default to the start of the file if there is no module declaration. 17627- if pm.File != nil && pm.File.Module != nil && pm.File.Module.Syntax != nil { 17628- start, end := pm.File.Module.Syntax.Span() 17629- var err error 17630- rng, err = pm.Mapper.OffsetRange(start.Byte, end.Byte) 17631- if err != nil { 17632- return nil, err 17633- } 17634- } 17635- title := fmt.Sprintf("Add %s to your go.mod file", req.Mod.Path) 17636- cmd, err := command.NewAddDependencyCommand(title, command.DependencyArgs{ 17637- URI: protocol.URIFromSpanURI(pm.Mapper.URI), 17638- AddRequire: !req.Indirect, 17639- GoCmdArgs: []string{req.Mod.Path + "@" + req.Mod.Version}, 17640- }) 17641- if err != nil { 17642- return nil, err 17643- } 17644- return &source.Diagnostic{ 17645- URI: pm.Mapper.URI, 17646- Range: rng, 17647- Severity: protocol.SeverityError, 17648- Source: source.ModTidyError, 17649- Message: fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path), 17650- SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, 17651- }, nil 17652-} 17653- 17654-// switchDirectness gets the edits needed to change an indirect dependency to 17655-// direct and vice versa. 17656-func switchDirectness(req *modfile.Require, m *protocol.Mapper, computeEdits source.DiffFunction) ([]protocol.TextEdit, error) { 17657- // We need a private copy of the parsed go.mod file, since we're going to 17658- // modify it. 17659- copied, err := modfile.Parse("", m.Content, nil) 17660- if err != nil { 17661- return nil, err 17662- } 17663- // Change the directness in the matching require statement. To avoid 17664- // reordering the require statements, rewrite all of them. 17665- var requires []*modfile.Require 17666- seenVersions := make(map[string]string) 17667- for _, r := range copied.Require { 17668- if seen := seenVersions[r.Mod.Path]; seen != "" && seen != r.Mod.Version { 17669- // Avoid a panic in SetRequire below, which panics on conflicting 17670- // versions. 17671- return nil, fmt.Errorf("%q has conflicting versions: %q and %q", r.Mod.Path, seen, r.Mod.Version) 17672- } 17673- seenVersions[r.Mod.Path] = r.Mod.Version 17674- if r.Mod.Path == req.Mod.Path { 17675- requires = append(requires, &modfile.Require{ 17676- Mod: r.Mod, 17677- Syntax: r.Syntax, 17678- Indirect: !r.Indirect, 17679- }) 17680- continue 17681- } 17682- requires = append(requires, r) 17683- } 17684- copied.SetRequire(requires) 17685- newContent, err := copied.Format() 17686- if err != nil { 17687- return nil, err 17688- } 17689- // Calculate the edits to be made due to the change. 17690- edits := computeEdits(string(m.Content), string(newContent)) 17691- return source.ToProtocolEdits(m, edits) 17692-} 17693- 17694-// missingModuleForImport creates an error for a given import path that comes 17695-// from a missing module. 17696-func missingModuleForImport(pgf *source.ParsedGoFile, imp *ast.ImportSpec, req *modfile.Require, fixes []source.SuggestedFix) (*source.Diagnostic, error) { 17697- if req.Syntax == nil { 17698- return nil, fmt.Errorf("no syntax for %v", req) 17699- } 17700- rng, err := pgf.NodeRange(imp.Path) 17701- if err != nil { 17702- return nil, err 17703- } 17704- return &source.Diagnostic{ 17705- URI: pgf.URI, 17706- Range: rng, 17707- Severity: protocol.SeverityError, 17708- Source: source.ModTidyError, 17709- Message: fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path), 17710- SuggestedFixes: fixes, 17711- }, nil 17712-} 17713- 17714-// parseImports parses the headers of the specified files and returns 17715-// the set of strings that appear in import declarations within 17716-// GoFiles. Errors are ignored. 17717-// 17718-// (We can't simply use Metadata.Imports because it is based on 17719-// CompiledGoFiles, after cgo processing.) 17720-// 17721-// TODO(rfindley): this should key off source.ImportPath. 17722-func parseImports(ctx context.Context, s *snapshot, files []source.FileHandle) (map[string]bool, error) { 17723- pgfs, _, err := s.parseCache.parseFiles(ctx, source.ParseHeader, files...) 17724- if err != nil { // e.g. context cancellation 17725- return nil, err 17726- } 17727- 17728- seen := make(map[string]bool) 17729- for _, pgf := range pgfs { 17730- for _, spec := range pgf.File.Imports { 17731- path, _ := strconv.Unquote(spec.Path.Value) 17732- seen[path] = true 17733- } 17734- } 17735- return seen, nil 17736-} 17737diff -urN a/gopls/internal/lsp/cache/mod_vuln.go b/gopls/internal/lsp/cache/mod_vuln.go 17738--- a/gopls/internal/lsp/cache/mod_vuln.go 2000-01-01 00:00:00.000000000 -0000 17739+++ b/gopls/internal/lsp/cache/mod_vuln.go 1970-01-01 00:00:00.000000000 +0000 17740@@ -1,75 +0,0 @@ 17741-// Copyright 2022 The Go Authors. All rights reserved. 17742-// Use of this source code is governed by a BSD-style 17743-// license that can be found in the LICENSE file. 17744- 17745-package cache 17746- 17747-import ( 17748- "context" 17749- "os" 17750- 17751- "golang.org/x/tools/gopls/internal/govulncheck" 17752- "golang.org/x/tools/gopls/internal/lsp/source" 17753- "golang.org/x/tools/gopls/internal/span" 17754- "golang.org/x/tools/gopls/internal/vulncheck" 17755- "golang.org/x/tools/internal/memoize" 17756-) 17757- 17758-// ModVuln returns import vulnerability analysis for the given go.mod URI. 17759-// Concurrent requests are combined into a single command. 17760-func (s *snapshot) ModVuln(ctx context.Context, modURI span.URI) (*govulncheck.Result, error) { 17761- s.mu.Lock() 17762- entry, hit := s.modVulnHandles.Get(modURI) 17763- s.mu.Unlock() 17764- 17765- type modVuln struct { 17766- result *govulncheck.Result 17767- err error 17768- } 17769- 17770- // Cache miss? 17771- if !hit { 17772- // If the file handle is an overlay, it may not be written to disk. 17773- // The go.mod file has to be on disk for vulncheck to work. 17774- // 17775- // TODO(hyangah): use overlays for vulncheck. 17776- fh, err := s.GetFile(ctx, modURI) 17777- if err != nil { 17778- return nil, err 17779- } 17780- if _, ok := fh.(*Overlay); ok { 17781- if info, _ := os.Stat(modURI.Filename()); info == nil { 17782- return nil, source.ErrNoModOnDisk 17783- } 17784- } 17785- 17786- handle := memoize.NewPromise("modVuln", func(ctx context.Context, arg interface{}) interface{} { 17787- result, err := modVulnImpl(ctx, arg.(*snapshot), modURI) 17788- return modVuln{result, err} 17789- }) 17790- 17791- entry = handle 17792- s.mu.Lock() 17793- s.modVulnHandles.Set(modURI, entry, nil) 17794- s.mu.Unlock() 17795- } 17796- 17797- // Await result. 17798- v, err := s.awaitPromise(ctx, entry.(*memoize.Promise)) 17799- if err != nil { 17800- return nil, err 17801- } 17802- res := v.(modVuln) 17803- return res.result, res.err 17804-} 17805- 17806-func modVulnImpl(ctx context.Context, s *snapshot, uri span.URI) (*govulncheck.Result, error) { 17807- if vulncheck.VulnerablePackages == nil { 17808- return &govulncheck.Result{}, nil 17809- } 17810- fh, err := s.GetFile(ctx, uri) 17811- if err != nil { 17812- return nil, err 17813- } 17814- return vulncheck.VulnerablePackages(ctx, s, fh) 17815-} 17816diff -urN a/gopls/internal/lsp/cache/os_darwin.go b/gopls/internal/lsp/cache/os_darwin.go 17817--- a/gopls/internal/lsp/cache/os_darwin.go 2000-01-01 00:00:00.000000000 -0000 17818+++ b/gopls/internal/lsp/cache/os_darwin.go 1970-01-01 00:00:00.000000000 +0000 17819@@ -1,59 +0,0 @@ 17820-// Copyright 2020 The Go Authors. All rights reserved. 17821-// Use of this source code is governed by a BSD-style 17822-// license that can be found in the LICENSE file. 17823- 17824-package cache 17825- 17826-import ( 17827- "bytes" 17828- "fmt" 17829- "os" 17830- "path/filepath" 17831- "strings" 17832- "syscall" 17833- "unsafe" 17834-) 17835- 17836-func init() { 17837- checkPathCase = darwinCheckPathCase 17838-} 17839- 17840-func darwinCheckPathCase(path string) error { 17841- // Darwin provides fcntl(F_GETPATH) to get a path for an arbitrary FD. 17842- // Conveniently for our purposes, it gives the canonical case back. But 17843- // there's no guarantee that it will follow the same route through the 17844- // filesystem that the original path did. 17845- 17846- path, err := filepath.Abs(path) 17847- if err != nil { 17848- return err 17849- } 17850- fd, err := syscall.Open(path, os.O_RDONLY, 0) 17851- if err != nil { 17852- return err 17853- } 17854- defer syscall.Close(fd) 17855- buf := make([]byte, 4096) // No MAXPATHLEN in syscall, I think it's 1024, this is bigger. 17856- 17857- // Wheeee! syscall doesn't expose a way to call Fcntl except FcntlFlock. 17858- // As of writing, it just passes the pointer through, so we can just lie. 17859- if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETPATH, (*syscall.Flock_t)(unsafe.Pointer(&buf[0]))); err != nil { 17860- return err 17861- } 17862- buf = buf[:bytes.IndexByte(buf, 0)] 17863- 17864- isRoot := func(p string) bool { 17865- return p[len(p)-1] == filepath.Separator 17866- } 17867- // Darwin seems to like having multiple names for the same folder. Match as much of the suffix as we can. 17868- for got, want := path, string(buf); !isRoot(got) && !isRoot(want); got, want = filepath.Dir(got), filepath.Dir(want) { 17869- g, w := filepath.Base(got), filepath.Base(want) 17870- if !strings.EqualFold(g, w) { 17871- break 17872- } 17873- if g != w { 17874- return fmt.Errorf("case mismatch in path %q: component %q is listed by macOS as %q", path, g, w) 17875- } 17876- } 17877- return nil 17878-} 17879diff -urN a/gopls/internal/lsp/cache/os_windows.go b/gopls/internal/lsp/cache/os_windows.go 17880--- a/gopls/internal/lsp/cache/os_windows.go 2000-01-01 00:00:00.000000000 -0000 17881+++ b/gopls/internal/lsp/cache/os_windows.go 1970-01-01 00:00:00.000000000 +0000 17882@@ -1,56 +0,0 @@ 17883-// Copyright 2020 The Go Authors. All rights reserved. 17884-// Use of this source code is governed by a BSD-style 17885-// license that can be found in the LICENSE file. 17886- 17887-package cache 17888- 17889-import ( 17890- "fmt" 17891- "path/filepath" 17892- "syscall" 17893-) 17894- 17895-func init() { 17896- checkPathCase = windowsCheckPathCase 17897-} 17898- 17899-func windowsCheckPathCase(path string) error { 17900- // Back in the day, Windows used to have short and long filenames, and 17901- // it still supports those APIs. GetLongPathName gets the real case for a 17902- // path, so we can use it here. Inspired by 17903- // http://stackoverflow.com/q/2113822. 17904- 17905- // Short paths can be longer than long paths, and unicode, so be generous. 17906- buflen := 4 * len(path) 17907- namep, err := syscall.UTF16PtrFromString(path) 17908- if err != nil { 17909- return err 17910- } 17911- short := make([]uint16, buflen) 17912- n, err := syscall.GetShortPathName(namep, &short[0], uint32(len(short)*2)) // buflen is in bytes. 17913- if err != nil { 17914- return err 17915- } 17916- if int(n) > len(short)*2 { 17917- return fmt.Errorf("short buffer too short: %v vs %v*2", n, len(short)) 17918- } 17919- long := make([]uint16, buflen) 17920- n, err = syscall.GetLongPathName(&short[0], &long[0], uint32(len(long)*2)) 17921- if err != nil { 17922- return err 17923- } 17924- if int(n) > len(long)*2 { 17925- return fmt.Errorf("long buffer too short: %v vs %v*2", n, len(long)) 17926- } 17927- longstr := syscall.UTF16ToString(long) 17928- 17929- isRoot := func(p string) bool { 17930- return p[len(p)-1] == filepath.Separator 17931- } 17932- for got, want := path, longstr; !isRoot(got) && !isRoot(want); got, want = filepath.Dir(got), filepath.Dir(want) { 17933- if g, w := filepath.Base(got), filepath.Base(want); g != w { 17934- return fmt.Errorf("case mismatch in path %q: component %q is listed by Windows as %q", path, g, w) 17935- } 17936- } 17937- return nil 17938-} 17939diff -urN a/gopls/internal/lsp/cache/parse_cache.go b/gopls/internal/lsp/cache/parse_cache.go 17940--- a/gopls/internal/lsp/cache/parse_cache.go 2000-01-01 00:00:00.000000000 -0000 17941+++ b/gopls/internal/lsp/cache/parse_cache.go 1970-01-01 00:00:00.000000000 +0000 17942@@ -1,298 +0,0 @@ 17943-// Copyright 2023 The Go Authors. All rights reserved. 17944-// Use of this source code is governed by a BSD-style 17945-// license that can be found in the LICENSE file. 17946- 17947-package cache 17948- 17949-import ( 17950- "container/heap" 17951- "context" 17952- "go/token" 17953- "runtime" 17954- "sort" 17955- "sync" 17956- 17957- "golang.org/x/sync/errgroup" 17958- "golang.org/x/tools/gopls/internal/lsp/source" 17959- "golang.org/x/tools/internal/memoize" 17960-) 17961- 17962-// This file contains an implementation of a bounded-size parse cache, that 17963-// offsets the base token.Pos value of each cached file so that they may be 17964-// later described by a single dedicated FileSet. 17965-// 17966-// This is achieved by tracking a monotonic offset in the token.Pos space, that 17967-// is incremented before parsing allow room for the resulting parsed file. 17968- 17969-// Keep 200 recently parsed files, based on the following rationale: 17970-// - One of the most important benefits of caching is avoiding re-parsing 17971-// everything in a package when working on a single file. No packages in 17972-// Kubernetes have > 200 files (only one has > 100). 17973-// - Experience has shown that ~1000 parsed files can use noticeable space. 17974-// 200 feels like a sweet spot between limiting cache size and optimizing 17975-// cache hits for low-latency operations. 17976-const parseCacheMaxFiles = 200 17977- 17978-// parsePadding is additional padding allocated between entries in the parse 17979-// cache to allow for increases in length (such as appending missing braces) 17980-// caused by fixAST. 17981-// 17982-// This is used to mitigate a chicken and egg problem: we must know the base 17983-// offset of the file we're about to parse, before we start parsing, and yet 17984-// src fixups may affect the actual size of the parsed content (and therefore 17985-// the offsets of subsequent files). 17986-// 17987-// When we encounter a file that no longer fits in its allocated space in the 17988-// fileset, we have no choice but to re-parse it. Leaving a generous padding 17989-// reduces the likelihood of this "slow path". 17990-// 17991-// This value is mutable for testing, so that we can exercise the slow path. 17992-var parsePadding = 1000 // mutable for testing 17993- 17994-// A parseCache holds a bounded number of recently accessed parsed Go files. As 17995-// new files are stored, older files may be evicted from the cache. 17996-// 17997-// The parseCache.parseFiles method exposes a batch API for parsing (and 17998-// caching) multiple files. This is necessary for type-checking, where files 17999-// must be parsed in a common fileset. 18000-type parseCache struct { 18001- mu sync.Mutex 18002- m map[parseKey]*parseCacheEntry 18003- lru queue // min-atime priority queue of *parseCacheEntry 18004- clock uint64 // clock time, incremented when the cache is updated 18005- nextOffset token.Pos // token.Pos offset for the next parsed file 18006-} 18007- 18008-// parseKey uniquely identifies a parsed Go file. 18009-type parseKey struct { 18010- file source.FileIdentity 18011- mode source.ParseMode 18012-} 18013- 18014-type parseCacheEntry struct { 18015- key parseKey 18016- promise *memoize.Promise // memoize.Promise[*source.ParsedGoFile] 18017- atime uint64 // clock time of last access 18018- lruIndex int 18019-} 18020- 18021-// startParse prepares a parsing pass, using the following steps: 18022-// - search for cache hits 18023-// - create new promises for cache misses 18024-// - store as many new promises in the cache as space will allow 18025-// 18026-// The resulting slice has an entry for every given file handle, though some 18027-// entries may be nil if there was an error reading the file (in which case the 18028-// resulting error will be non-nil). 18029-func (c *parseCache) startParse(mode source.ParseMode, fhs ...source.FileHandle) ([]*memoize.Promise, error) { 18030- c.mu.Lock() 18031- defer c.mu.Unlock() 18032- 18033- // Any parsing pass increments the clock, as we'll update access times. 18034- // (technically, if fhs is empty this isn't necessary, but that's a degenerate case). 18035- // 18036- // All entries parsed from a single call get the same access time. 18037- c.clock++ 18038- 18039- // Read file data and collect cacheable files. 18040- var ( 18041- data = make([][]byte, len(fhs)) // file content for each readable file 18042- promises = make([]*memoize.Promise, len(fhs)) 18043- firstReadError error // first error from fh.Read, or nil 18044- ) 18045- for i, fh := range fhs { 18046- src, err := fh.Read() 18047- if err != nil { 18048- if firstReadError == nil { 18049- firstReadError = err 18050- } 18051- continue 18052- } 18053- data[i] = src 18054- 18055- key := parseKey{ 18056- file: fh.FileIdentity(), 18057- mode: mode, 18058- } 18059- 18060- // Check for a cache hit. 18061- if e, ok := c.m[key]; ok { 18062- e.atime = c.clock 18063- heap.Fix(&c.lru, e.lruIndex) 18064- promises[i] = e.promise 18065- continue 18066- } 18067- 18068- // ...otherwise, create a new promise to parse with a non-overlapping offset 18069- fset := token.NewFileSet() 18070- if c.nextOffset > 0 { 18071- // Add a dummy file so that this parsed file does not overlap with others. 18072- fset.AddFile("", 1, int(c.nextOffset)) 18073- } 18074- c.nextOffset += token.Pos(len(src) + parsePadding + 1) // leave room for src fixes 18075- fh := fh 18076- promise := memoize.NewPromise(string(fh.URI()), func(ctx context.Context, _ interface{}) interface{} { 18077- return parseGoSrc(ctx, fset, fh.URI(), src, mode) 18078- }) 18079- promises[i] = promise 18080- 18081- var e *parseCacheEntry 18082- if len(c.lru) < parseCacheMaxFiles { 18083- // add new entry 18084- e = new(parseCacheEntry) 18085- if c.m == nil { 18086- c.m = make(map[parseKey]*parseCacheEntry) 18087- } 18088- } else { 18089- // evict oldest entry 18090- e = heap.Pop(&c.lru).(*parseCacheEntry) 18091- delete(c.m, e.key) 18092- } 18093- e.key = key 18094- e.promise = promise 18095- e.atime = c.clock 18096- c.m[e.key] = e 18097- heap.Push(&c.lru, e) 18098- } 18099- 18100- if len(c.m) != len(c.lru) { 18101- panic("map and LRU are inconsistent") 18102- } 18103- 18104- return promises, firstReadError 18105-} 18106- 18107-// parseFiles returns a ParsedGoFile for the given file handles in the 18108-// requested parse mode. 18109-// 18110-// If parseFiles returns an error, it still returns a slice, 18111-// but with a nil entry for each file that could not be parsed. 18112-// 18113-// The second result is a FileSet describing all resulting parsed files. 18114-// 18115-// For parsed files that already exists in the cache, access time will be 18116-// updated. For others, parseFiles will parse and store as many results in the 18117-// cache as space allows. 18118-func (c *parseCache) parseFiles(ctx context.Context, mode source.ParseMode, fhs ...source.FileHandle) ([]*source.ParsedGoFile, *token.FileSet, error) { 18119- promises, firstReadError := c.startParse(mode, fhs...) 18120- 18121- // Await all parsing. 18122- var g errgroup.Group 18123- g.SetLimit(runtime.GOMAXPROCS(-1)) // parsing is CPU-bound. 18124- pgfs := make([]*source.ParsedGoFile, len(fhs)) 18125- for i, promise := range promises { 18126- if promise == nil { 18127- continue 18128- } 18129- i := i 18130- promise := promise 18131- g.Go(func() error { 18132- result, err := promise.Get(ctx, nil) 18133- if err != nil { 18134- return err 18135- } 18136- pgfs[i] = result.(*source.ParsedGoFile) 18137- return nil 18138- }) 18139- } 18140- if err := g.Wait(); err != nil { 18141- return nil, nil, err 18142- } 18143- 18144- // Construct a token.FileSet mapping all parsed files, and update their 18145- // Tok to the corresponding file in the new fileset. 18146- // 18147- // In the unlikely event that a parsed file no longer fits in its allocated 18148- // space in the FileSet range, it will need to be re-parsed. 18149- 18150- var tokenFiles []*token.File 18151- fileIndex := make(map[*token.File]int) // to look up original indexes after sorting 18152- for i, pgf := range pgfs { 18153- if pgf == nil { 18154- continue 18155- } 18156- fileIndex[pgf.Tok] = i 18157- tokenFiles = append(tokenFiles, pgf.Tok) 18158- } 18159- 18160- sort.Slice(tokenFiles, func(i, j int) bool { 18161- return tokenFiles[i].Base() < tokenFiles[j].Base() 18162- }) 18163- 18164- var needReparse []int // files requiring reparsing 18165- out := tokenFiles[:0] 18166- for i, f := range tokenFiles { 18167- if i < len(tokenFiles)-1 && f.Base()+f.Size() >= tokenFiles[i+1].Base() { 18168- if f != tokenFiles[i+1] { // no need to re-parse duplicates 18169- needReparse = append(needReparse, fileIndex[f]) 18170- } 18171- } else { 18172- out = append(out, f) 18173- } 18174- } 18175- fset := source.FileSetFor(out...) 18176- 18177- // Re-parse any remaining files using the stitched fileSet. 18178- for _, i := range needReparse { 18179- // Start from scratch, rather than using ParsedGoFile.Src, so that source 18180- // fixing operates exactly the same (note that fixing stops after a limited 18181- // number of tries). 18182- fh := fhs[i] 18183- src, err := fh.Read() 18184- if err != nil { 18185- if firstReadError == nil { 18186- firstReadError = err 18187- } 18188- continue 18189- } 18190- pgfs[i] = parseGoSrc(ctx, fset, fh.URI(), src, mode) 18191- } 18192- 18193- // Ensure each PGF refers to a token.File from the new FileSet. 18194- for i, pgf := range pgfs { 18195- if pgf == nil { 18196- continue 18197- } 18198- newTok := fset.File(token.Pos(pgf.Tok.Base())) 18199- if newTok == nil { 18200- panic("internal error: missing tok for " + pgf.URI) 18201- } 18202- if newTok.Base() != pgf.Tok.Base() || newTok.Size() != pgf.Tok.Size() { 18203- panic("internal error: mismatching token.File in synthetic FileSet") 18204- } 18205- pgf2 := *pgf 18206- pgf2.Tok = newTok 18207- pgfs[i] = &pgf2 18208- } 18209- 18210- return pgfs, fset, firstReadError 18211-} 18212- 18213-// -- priority queue boilerplate -- 18214- 18215-// queue is a min-atime prority queue of cache entries. 18216-type queue []*parseCacheEntry 18217- 18218-func (q queue) Len() int { return len(q) } 18219- 18220-func (q queue) Less(i, j int) bool { return q[i].atime < q[j].atime } 18221- 18222-func (q queue) Swap(i, j int) { 18223- q[i], q[j] = q[j], q[i] 18224- q[i].lruIndex = i 18225- q[j].lruIndex = j 18226-} 18227- 18228-func (q *queue) Push(x interface{}) { 18229- e := x.(*parseCacheEntry) 18230- e.lruIndex = len(*q) 18231- *q = append(*q, e) 18232-} 18233- 18234-func (q *queue) Pop() interface{} { 18235- last := len(*q) - 1 18236- e := (*q)[last] 18237- (*q)[last] = nil // aid GC 18238- *q = (*q)[:last] 18239- return e 18240-} 18241diff -urN a/gopls/internal/lsp/cache/parse_cache_test.go b/gopls/internal/lsp/cache/parse_cache_test.go 18242--- a/gopls/internal/lsp/cache/parse_cache_test.go 2000-01-01 00:00:00.000000000 -0000 18243+++ b/gopls/internal/lsp/cache/parse_cache_test.go 1970-01-01 00:00:00.000000000 +0000 18244@@ -1,142 +0,0 @@ 18245-// Copyright 2023 The Go Authors. All rights reserved. 18246-// Use of this source code is governed by a BSD-style 18247-// license that can be found in the LICENSE file. 18248- 18249-package cache 18250- 18251-import ( 18252- "context" 18253- "fmt" 18254- "go/token" 18255- "testing" 18256- 18257- "golang.org/x/tools/gopls/internal/lsp/source" 18258- "golang.org/x/tools/gopls/internal/span" 18259-) 18260- 18261-func TestParseCache(t *testing.T) { 18262- ctx := context.Background() 18263- uri := span.URI("file:///myfile") 18264- fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\"")) 18265- 18266- var cache parseCache 18267- pgfs1, _, err := cache.parseFiles(ctx, source.ParseFull, fh) 18268- if err != nil { 18269- t.Fatal(err) 18270- } 18271- pgf1 := pgfs1[0] 18272- pgfs2, _, err := cache.parseFiles(ctx, source.ParseFull, fh) 18273- pgf2 := pgfs2[0] 18274- if err != nil { 18275- t.Fatal(err) 18276- } 18277- if pgf1.File != pgf2.File { 18278- t.Errorf("parseFiles(%q): unexpected cache miss on repeated call", uri) 18279- } 18280- 18281- // Fill up the cache with other files, but don't evict the file above. 18282- files := []source.FileHandle{fh} 18283- files = append(files, dummyFileHandles(parseCacheMaxFiles-1)...) 18284- pgfs3, fset, err := cache.parseFiles(ctx, source.ParseFull, files...) 18285- pgf3 := pgfs3[0] 18286- if pgf3.File != pgf1.File { 18287- t.Errorf("parseFiles(%q, ...): unexpected cache miss", uri) 18288- } 18289- if pgf3.Tok == pgf1.Tok { 18290- t.Errorf("parseFiles(%q, ...): unexpectedly matching token file", uri) 18291- } 18292- if pgf3.Tok.Base() != pgf1.Tok.Base() || pgf3.Tok.Size() != pgf1.Tok.Size() { 18293- t.Errorf("parseFiles(%q, ...): result.Tok has base: %d, size: %d, want (%d, %d)", uri, pgf3.Tok.Base(), pgf3.Tok.Size(), pgf1.Tok.Base(), pgf1.Tok.Size()) 18294- } 18295- if tok := fset.File(token.Pos(pgf3.Tok.Base())); tok != pgf3.Tok { 18296- t.Errorf("parseFiles(%q, ...): result.Tok not contained in FileSet", uri) 18297- } 18298- 18299- // Now overwrite the cache, after which we should get new results. 18300- files = dummyFileHandles(parseCacheMaxFiles) 18301- _, _, err = cache.parseFiles(ctx, source.ParseFull, files...) 18302- if err != nil { 18303- t.Fatal(err) 18304- } 18305- pgfs4, _, err := cache.parseFiles(ctx, source.ParseFull, fh) 18306- if err != nil { 18307- t.Fatal(err) 18308- } 18309- if pgfs4[0].File == pgf1.File { 18310- t.Errorf("parseFiles(%q): unexpected cache hit after overwriting cache", uri) 18311- } 18312-} 18313- 18314-func TestParseCache_Reparsing(t *testing.T) { 18315- defer func(padding int) { 18316- parsePadding = padding 18317- }(parsePadding) 18318- parsePadding = 0 18319- 18320- files := dummyFileHandles(parseCacheMaxFiles) 18321- danglingSelector := []byte("package p\nfunc _() {\n\tx.\n}") 18322- files = append(files, makeFakeFileHandle("file:///bad1", danglingSelector)) 18323- files = append(files, makeFakeFileHandle("file:///bad2", danglingSelector)) 18324- 18325- // Parsing should succeed even though we overflow the padding. 18326- var cache parseCache 18327- _, _, err := cache.parseFiles(context.Background(), source.ParseFull, files...) 18328- if err != nil { 18329- t.Fatal(err) 18330- } 18331-} 18332- 18333-func TestParseCache_Duplicates(t *testing.T) { 18334- ctx := context.Background() 18335- uri := span.URI("file:///myfile") 18336- fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\"")) 18337- 18338- var cache parseCache 18339- pgfs, _, err := cache.parseFiles(ctx, source.ParseFull, fh, fh) 18340- if err != nil { 18341- t.Fatal(err) 18342- } 18343- if pgfs[0].File != pgfs[1].File { 18344- t.Errorf("parseFiles(fh, fh): = [%p, %p], want duplicate files", pgfs[0].File, pgfs[1].File) 18345- } 18346-} 18347- 18348-func dummyFileHandles(n int) []source.FileHandle { 18349- var fhs []source.FileHandle 18350- for i := 0; i < n; i++ { 18351- uri := span.URI(fmt.Sprintf("file:///_%d", i)) 18352- src := []byte(fmt.Sprintf("package p\nvar _ = %d", i)) 18353- fhs = append(fhs, makeFakeFileHandle(uri, src)) 18354- } 18355- return fhs 18356-} 18357- 18358-func makeFakeFileHandle(uri span.URI, src []byte) fakeFileHandle { 18359- return fakeFileHandle{ 18360- uri: uri, 18361- data: src, 18362- hash: source.HashOf(src), 18363- } 18364-} 18365- 18366-type fakeFileHandle struct { 18367- source.FileHandle 18368- uri span.URI 18369- data []byte 18370- hash source.Hash 18371-} 18372- 18373-func (h fakeFileHandle) URI() span.URI { 18374- return h.uri 18375-} 18376- 18377-func (h fakeFileHandle) Read() ([]byte, error) { 18378- return h.data, nil 18379-} 18380- 18381-func (h fakeFileHandle) FileIdentity() source.FileIdentity { 18382- return source.FileIdentity{ 18383- URI: h.uri, 18384- Hash: h.hash, 18385- } 18386-} 18387diff -urN a/gopls/internal/lsp/cache/parse.go b/gopls/internal/lsp/cache/parse.go 18388--- a/gopls/internal/lsp/cache/parse.go 2000-01-01 00:00:00.000000000 -0000 18389+++ b/gopls/internal/lsp/cache/parse.go 1970-01-01 00:00:00.000000000 +0000 18390@@ -1,900 +0,0 @@ 18391-// Copyright 2019 The Go Authors. All rights reserved. 18392-// Use of this source code is governed by a BSD-style 18393-// license that can be found in the LICENSE file. 18394- 18395-package cache 18396- 18397-import ( 18398- "bytes" 18399- "context" 18400- "fmt" 18401- "go/ast" 18402- "go/parser" 18403- "go/scanner" 18404- "go/token" 18405- "path/filepath" 18406- "reflect" 18407- 18408- "golang.org/x/tools/gopls/internal/lsp/protocol" 18409- "golang.org/x/tools/gopls/internal/lsp/safetoken" 18410- "golang.org/x/tools/gopls/internal/lsp/source" 18411- "golang.org/x/tools/gopls/internal/span" 18412- "golang.org/x/tools/internal/diff" 18413- "golang.org/x/tools/internal/event" 18414- "golang.org/x/tools/internal/event/tag" 18415-) 18416- 18417-// ParseGo parses the file whose contents are provided by fh, using a cache. 18418-// The resulting tree may have beeen fixed up. 18419-func (s *snapshot) ParseGo(ctx context.Context, fh source.FileHandle, mode source.ParseMode) (*source.ParsedGoFile, error) { 18420- pgfs, _, err := s.parseCache.parseFiles(ctx, mode, fh) 18421- if err != nil { 18422- return nil, err 18423- } 18424- return pgfs[0], nil 18425-} 18426- 18427-// parseGoImpl parses the Go source file whose content is provided by fh. 18428-func parseGoImpl(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mode source.ParseMode) (*source.ParsedGoFile, error) { 18429- ctx, done := event.Start(ctx, "cache.parseGo", tag.File.Of(fh.URI().Filename())) 18430- defer done() 18431- 18432- ext := filepath.Ext(fh.URI().Filename()) 18433- if ext != ".go" && ext != "" { // files generated by cgo have no extension 18434- return nil, fmt.Errorf("cannot parse non-Go file %s", fh.URI()) 18435- } 18436- src, err := fh.Read() 18437- if err != nil { 18438- return nil, err 18439- } 18440- return parseGoSrc(ctx, fset, fh.URI(), src, mode), nil 18441-} 18442- 18443-// parseGoSrc parses a buffer of Go source, repairing the tree if necessary. 18444-func parseGoSrc(ctx context.Context, fset *token.FileSet, uri span.URI, src []byte, mode source.ParseMode) (res *source.ParsedGoFile) { 18445- parserMode := parser.AllErrors | parser.ParseComments 18446- if mode == source.ParseHeader { 18447- parserMode = parser.ImportsOnly | parser.ParseComments 18448- } 18449- 18450- file, err := parser.ParseFile(fset, uri.Filename(), src, parserMode) 18451- var parseErr scanner.ErrorList 18452- if err != nil { 18453- // We passed a byte slice, so the only possible error is a parse error. 18454- parseErr = err.(scanner.ErrorList) 18455- } 18456- 18457- tok := fset.File(file.Pos()) 18458- if tok == nil { 18459- // file.Pos is the location of the package declaration (issue #53202). If there was 18460- // none, we can't find the token.File that ParseFile created, and we 18461- // have no choice but to recreate it. 18462- tok = fset.AddFile(uri.Filename(), -1, len(src)) 18463- tok.SetLinesForContent(src) 18464- } 18465- 18466- fixed := false 18467- // If there were parse errors, attempt to fix them up. 18468- if parseErr != nil { 18469- // Fix any badly parsed parts of the AST. 18470- fixed = fixAST(file, tok, src) 18471- 18472- for i := 0; i < 10; i++ { 18473- // Fix certain syntax errors that render the file unparseable. 18474- newSrc := fixSrc(file, tok, src) 18475- if newSrc == nil { 18476- break 18477- } 18478- 18479- // If we thought there was something to fix 10 times in a row, 18480- // it is likely we got stuck in a loop somehow. Log out a diff 18481- // of the last changes we made to aid in debugging. 18482- if i == 9 { 18483- unified := diff.Unified("before", "after", string(src), string(newSrc)) 18484- event.Log(ctx, fmt.Sprintf("fixSrc loop - last diff:\n%v", unified), tag.File.Of(tok.Name())) 18485- } 18486- 18487- newFile, _ := parser.ParseFile(fset, uri.Filename(), newSrc, parserMode) 18488- if newFile != nil { 18489- // Maintain the original parseError so we don't try formatting the doctored file. 18490- file = newFile 18491- src = newSrc 18492- tok = fset.File(file.Pos()) 18493- 18494- fixed = fixAST(file, tok, src) 18495- } 18496- } 18497- } 18498- 18499- return &source.ParsedGoFile{ 18500- URI: uri, 18501- Mode: mode, 18502- Src: src, 18503- Fixed: fixed, 18504- File: file, 18505- Tok: tok, 18506- Mapper: protocol.NewMapper(uri, src), 18507- ParseErr: parseErr, 18508- } 18509-} 18510- 18511-// fixAST inspects the AST and potentially modifies any *ast.BadStmts so that it can be 18512-// type-checked more effectively. 18513-// 18514-// If fixAST returns true, the resulting AST is considered "fixed", meaning 18515-// positions have been mangled, and type checker errors may not make sense. 18516-func fixAST(n ast.Node, tok *token.File, src []byte) (fixed bool) { 18517- var err error 18518- walkASTWithParent(n, func(n, parent ast.Node) bool { 18519- switch n := n.(type) { 18520- case *ast.BadStmt: 18521- if fixed = fixDeferOrGoStmt(n, parent, tok, src); fixed { 18522- // Recursively fix in our fixed node. 18523- _ = fixAST(parent, tok, src) 18524- } else { 18525- err = fmt.Errorf("unable to parse defer or go from *ast.BadStmt: %v", err) 18526- } 18527- return false 18528- case *ast.BadExpr: 18529- if fixed = fixArrayType(n, parent, tok, src); fixed { 18530- // Recursively fix in our fixed node. 18531- _ = fixAST(parent, tok, src) 18532- return false 18533- } 18534- 18535- // Fix cases where parser interprets if/for/switch "init" 18536- // statement as "cond" expression, e.g.: 18537- // 18538- // // "i := foo" is init statement, not condition. 18539- // for i := foo 18540- // 18541- fixInitStmt(n, parent, tok, src) 18542- 18543- return false 18544- case *ast.SelectorExpr: 18545- // Fix cases where a keyword prefix results in a phantom "_" selector, e.g.: 18546- // 18547- // foo.var<> // want to complete to "foo.variance" 18548- // 18549- fixPhantomSelector(n, tok, src) 18550- return true 18551- 18552- case *ast.BlockStmt: 18553- switch parent.(type) { 18554- case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt: 18555- // Adjust closing curly brace of empty switch/select 18556- // statements so we can complete inside them. 18557- fixEmptySwitch(n, tok, src) 18558- } 18559- 18560- return true 18561- default: 18562- return true 18563- } 18564- }) 18565- return fixed 18566-} 18567- 18568-// walkASTWithParent walks the AST rooted at n. The semantics are 18569-// similar to ast.Inspect except it does not call f(nil). 18570-func walkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) { 18571- var ancestors []ast.Node 18572- ast.Inspect(n, func(n ast.Node) (recurse bool) { 18573- defer func() { 18574- if recurse { 18575- ancestors = append(ancestors, n) 18576- } 18577- }() 18578- 18579- if n == nil { 18580- ancestors = ancestors[:len(ancestors)-1] 18581- return false 18582- } 18583- 18584- var parent ast.Node 18585- if len(ancestors) > 0 { 18586- parent = ancestors[len(ancestors)-1] 18587- } 18588- 18589- return f(n, parent) 18590- }) 18591-} 18592- 18593-// fixSrc attempts to modify the file's source code to fix certain 18594-// syntax errors that leave the rest of the file unparsed. 18595-func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte) { 18596- walkASTWithParent(f, func(n, parent ast.Node) bool { 18597- if newSrc != nil { 18598- return false 18599- } 18600- 18601- switch n := n.(type) { 18602- case *ast.BlockStmt: 18603- newSrc = fixMissingCurlies(f, n, parent, tf, src) 18604- case *ast.SelectorExpr: 18605- newSrc = fixDanglingSelector(n, tf, src) 18606- } 18607- 18608- return newSrc == nil 18609- }) 18610- 18611- return newSrc 18612-} 18613- 18614-// fixMissingCurlies adds in curly braces for block statements that 18615-// are missing curly braces. For example: 18616-// 18617-// if foo 18618-// 18619-// becomes 18620-// 18621-// if foo {} 18622-func fixMissingCurlies(f *ast.File, b *ast.BlockStmt, parent ast.Node, tok *token.File, src []byte) []byte { 18623- // If the "{" is already in the source code, there isn't anything to 18624- // fix since we aren't missing curlies. 18625- if b.Lbrace.IsValid() { 18626- braceOffset, err := safetoken.Offset(tok, b.Lbrace) 18627- if err != nil { 18628- return nil 18629- } 18630- if braceOffset < len(src) && src[braceOffset] == '{' { 18631- return nil 18632- } 18633- } 18634- 18635- parentLine := tok.Line(parent.Pos()) 18636- 18637- if parentLine >= tok.LineCount() { 18638- // If we are the last line in the file, no need to fix anything. 18639- return nil 18640- } 18641- 18642- // Insert curlies at the end of parent's starting line. The parent 18643- // is the statement that contains the block, e.g. *ast.IfStmt. The 18644- // block's Pos()/End() can't be relied upon because they are based 18645- // on the (missing) curly braces. We assume the statement is a 18646- // single line for now and try sticking the curly braces at the end. 18647- insertPos := tok.LineStart(parentLine+1) - 1 18648- 18649- // Scootch position backwards until it's not in a comment. For example: 18650- // 18651- // if foo<> // some amazing comment | 18652- // someOtherCode() 18653- // 18654- // insertPos will be located at "|", so we back it out of the comment. 18655- didSomething := true 18656- for didSomething { 18657- didSomething = false 18658- for _, c := range f.Comments { 18659- if c.Pos() < insertPos && insertPos <= c.End() { 18660- insertPos = c.Pos() 18661- didSomething = true 18662- } 18663- } 18664- } 18665- 18666- // Bail out if line doesn't end in an ident or ".". This is to avoid 18667- // cases like below where we end up making things worse by adding 18668- // curlies: 18669- // 18670- // if foo && 18671- // bar<> 18672- switch precedingToken(insertPos, tok, src) { 18673- case token.IDENT, token.PERIOD: 18674- // ok 18675- default: 18676- return nil 18677- } 18678- 18679- var buf bytes.Buffer 18680- buf.Grow(len(src) + 3) 18681- offset, err := safetoken.Offset(tok, insertPos) 18682- if err != nil { 18683- return nil 18684- } 18685- buf.Write(src[:offset]) 18686- 18687- // Detect if we need to insert a semicolon to fix "for" loop situations like: 18688- // 18689- // for i := foo(); foo<> 18690- // 18691- // Just adding curlies is not sufficient to make things parse well. 18692- if fs, ok := parent.(*ast.ForStmt); ok { 18693- if _, ok := fs.Cond.(*ast.BadExpr); !ok { 18694- if xs, ok := fs.Post.(*ast.ExprStmt); ok { 18695- if _, ok := xs.X.(*ast.BadExpr); ok { 18696- buf.WriteByte(';') 18697- } 18698- } 18699- } 18700- } 18701- 18702- // Insert "{}" at insertPos. 18703- buf.WriteByte('{') 18704- buf.WriteByte('}') 18705- buf.Write(src[offset:]) 18706- return buf.Bytes() 18707-} 18708- 18709-// fixEmptySwitch moves empty switch/select statements' closing curly 18710-// brace down one line. This allows us to properly detect incomplete 18711-// "case" and "default" keywords as inside the switch statement. For 18712-// example: 18713-// 18714-// switch { 18715-// def<> 18716-// } 18717-// 18718-// gets parsed like: 18719-// 18720-// switch { 18721-// } 18722-// 18723-// Later we manually pull out the "def" token, but we need to detect 18724-// that our "<>" position is inside the switch block. To do that we 18725-// move the curly brace so it looks like: 18726-// 18727-// switch { 18728-// 18729-// } 18730-func fixEmptySwitch(body *ast.BlockStmt, tok *token.File, src []byte) { 18731- // We only care about empty switch statements. 18732- if len(body.List) > 0 || !body.Rbrace.IsValid() { 18733- return 18734- } 18735- 18736- // If the right brace is actually in the source code at the 18737- // specified position, don't mess with it. 18738- braceOffset, err := safetoken.Offset(tok, body.Rbrace) 18739- if err != nil { 18740- return 18741- } 18742- if braceOffset < len(src) && src[braceOffset] == '}' { 18743- return 18744- } 18745- 18746- braceLine := tok.Line(body.Rbrace) 18747- if braceLine >= tok.LineCount() { 18748- // If we are the last line in the file, no need to fix anything. 18749- return 18750- } 18751- 18752- // Move the right brace down one line. 18753- body.Rbrace = tok.LineStart(braceLine + 1) 18754-} 18755- 18756-// fixDanglingSelector inserts real "_" selector expressions in place 18757-// of phantom "_" selectors. For example: 18758-// 18759-// func _() { 18760-// x.<> 18761-// } 18762-// 18763-// var x struct { i int } 18764-// 18765-// To fix completion at "<>", we insert a real "_" after the "." so the 18766-// following declaration of "x" can be parsed and type checked 18767-// normally. 18768-func fixDanglingSelector(s *ast.SelectorExpr, tf *token.File, src []byte) []byte { 18769- if !isPhantomUnderscore(s.Sel, tf, src) { 18770- return nil 18771- } 18772- 18773- if !s.X.End().IsValid() { 18774- return nil 18775- } 18776- 18777- insertOffset, err := safetoken.Offset(tf, s.X.End()) 18778- if err != nil { 18779- return nil 18780- } 18781- // Insert directly after the selector's ".". 18782- insertOffset++ 18783- if src[insertOffset-1] != '.' { 18784- return nil 18785- } 18786- 18787- var buf bytes.Buffer 18788- buf.Grow(len(src) + 1) 18789- buf.Write(src[:insertOffset]) 18790- buf.WriteByte('_') 18791- buf.Write(src[insertOffset:]) 18792- return buf.Bytes() 18793-} 18794- 18795-// fixPhantomSelector tries to fix selector expressions with phantom 18796-// "_" selectors. In particular, we check if the selector is a 18797-// keyword, and if so we swap in an *ast.Ident with the keyword text. For example: 18798-// 18799-// foo.var 18800-// 18801-// yields a "_" selector instead of "var" since "var" is a keyword. 18802-// 18803-// TODO(rfindley): should this constitute an ast 'fix'? 18804-func fixPhantomSelector(sel *ast.SelectorExpr, tf *token.File, src []byte) { 18805- if !isPhantomUnderscore(sel.Sel, tf, src) { 18806- return 18807- } 18808- 18809- // Only consider selectors directly abutting the selector ".". This 18810- // avoids false positives in cases like: 18811- // 18812- // foo. // don't think "var" is our selector 18813- // var bar = 123 18814- // 18815- if sel.Sel.Pos() != sel.X.End()+1 { 18816- return 18817- } 18818- 18819- maybeKeyword := readKeyword(sel.Sel.Pos(), tf, src) 18820- if maybeKeyword == "" { 18821- return 18822- } 18823- 18824- replaceNode(sel, sel.Sel, &ast.Ident{ 18825- Name: maybeKeyword, 18826- NamePos: sel.Sel.Pos(), 18827- }) 18828-} 18829- 18830-// isPhantomUnderscore reports whether the given ident is a phantom 18831-// underscore. The parser sometimes inserts phantom underscores when 18832-// it encounters otherwise unparseable situations. 18833-func isPhantomUnderscore(id *ast.Ident, tok *token.File, src []byte) bool { 18834- if id == nil || id.Name != "_" { 18835- return false 18836- } 18837- 18838- // Phantom underscore means the underscore is not actually in the 18839- // program text. 18840- offset, err := safetoken.Offset(tok, id.Pos()) 18841- if err != nil { 18842- return false 18843- } 18844- return len(src) <= offset || src[offset] != '_' 18845-} 18846- 18847-// fixInitStmt fixes cases where the parser misinterprets an 18848-// if/for/switch "init" statement as the "cond" conditional. In cases 18849-// like "if i := 0" the user hasn't typed the semicolon yet so the 18850-// parser is looking for the conditional expression. However, "i := 0" 18851-// are not valid expressions, so we get a BadExpr. 18852-// 18853-// fixInitStmt returns valid AST for the original source. 18854-func fixInitStmt(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) { 18855- if !bad.Pos().IsValid() || !bad.End().IsValid() { 18856- return 18857- } 18858- 18859- // Try to extract a statement from the BadExpr. 18860- start, end, err := safetoken.Offsets(tok, bad.Pos(), bad.End()-1) 18861- if err != nil { 18862- return 18863- } 18864- stmtBytes := src[start : end+1] 18865- stmt, err := parseStmt(bad.Pos(), stmtBytes) 18866- if err != nil { 18867- return 18868- } 18869- 18870- // If the parent statement doesn't already have an "init" statement, 18871- // move the extracted statement into the "init" field and insert a 18872- // dummy expression into the required "cond" field. 18873- switch p := parent.(type) { 18874- case *ast.IfStmt: 18875- if p.Init != nil { 18876- return 18877- } 18878- p.Init = stmt 18879- p.Cond = &ast.Ident{ 18880- Name: "_", 18881- NamePos: stmt.End(), 18882- } 18883- case *ast.ForStmt: 18884- if p.Init != nil { 18885- return 18886- } 18887- p.Init = stmt 18888- p.Cond = &ast.Ident{ 18889- Name: "_", 18890- NamePos: stmt.End(), 18891- } 18892- case *ast.SwitchStmt: 18893- if p.Init != nil { 18894- return 18895- } 18896- p.Init = stmt 18897- p.Tag = nil 18898- } 18899-} 18900- 18901-// readKeyword reads the keyword starting at pos, if any. 18902-func readKeyword(pos token.Pos, tok *token.File, src []byte) string { 18903- var kwBytes []byte 18904- offset, err := safetoken.Offset(tok, pos) 18905- if err != nil { 18906- return "" 18907- } 18908- for i := offset; i < len(src); i++ { 18909- // Use a simplified identifier check since keywords are always lowercase ASCII. 18910- if src[i] < 'a' || src[i] > 'z' { 18911- break 18912- } 18913- kwBytes = append(kwBytes, src[i]) 18914- 18915- // Stop search at arbitrarily chosen too-long-for-a-keyword length. 18916- if len(kwBytes) > 15 { 18917- return "" 18918- } 18919- } 18920- 18921- if kw := string(kwBytes); token.Lookup(kw).IsKeyword() { 18922- return kw 18923- } 18924- 18925- return "" 18926-} 18927- 18928-// fixArrayType tries to parse an *ast.BadExpr into an *ast.ArrayType. 18929-// go/parser often turns lone array types like "[]int" into BadExprs 18930-// if it isn't expecting a type. 18931-func fixArrayType(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) bool { 18932- // Our expected input is a bad expression that looks like "[]someExpr". 18933- 18934- from := bad.Pos() 18935- to := bad.End() 18936- 18937- if !from.IsValid() || !to.IsValid() { 18938- return false 18939- } 18940- 18941- exprBytes := make([]byte, 0, int(to-from)+3) 18942- // Avoid doing tok.Offset(to) since that panics if badExpr ends at EOF. 18943- // It also panics if the position is not in the range of the file, and 18944- // badExprs may not necessarily have good positions, so check first. 18945- fromOffset, toOffset, err := safetoken.Offsets(tok, from, to-1) 18946- if err != nil { 18947- return false 18948- } 18949- exprBytes = append(exprBytes, src[fromOffset:toOffset+1]...) 18950- exprBytes = bytes.TrimSpace(exprBytes) 18951- 18952- // If our expression ends in "]" (e.g. "[]"), add a phantom selector 18953- // so we can complete directly after the "[]". 18954- if len(exprBytes) > 0 && exprBytes[len(exprBytes)-1] == ']' { 18955- exprBytes = append(exprBytes, '_') 18956- } 18957- 18958- // Add "{}" to turn our ArrayType into a CompositeLit. This is to 18959- // handle the case of "[...]int" where we must make it a composite 18960- // literal to be parseable. 18961- exprBytes = append(exprBytes, '{', '}') 18962- 18963- expr, err := parseExpr(from, exprBytes) 18964- if err != nil { 18965- return false 18966- } 18967- 18968- cl, _ := expr.(*ast.CompositeLit) 18969- if cl == nil { 18970- return false 18971- } 18972- 18973- at, _ := cl.Type.(*ast.ArrayType) 18974- if at == nil { 18975- return false 18976- } 18977- 18978- return replaceNode(parent, bad, at) 18979-} 18980- 18981-// precedingToken scans src to find the token preceding pos. 18982-func precedingToken(pos token.Pos, tok *token.File, src []byte) token.Token { 18983- s := &scanner.Scanner{} 18984- s.Init(tok, src, nil, 0) 18985- 18986- var lastTok token.Token 18987- for { 18988- p, t, _ := s.Scan() 18989- if t == token.EOF || p >= pos { 18990- break 18991- } 18992- 18993- lastTok = t 18994- } 18995- return lastTok 18996-} 18997- 18998-// fixDeferOrGoStmt tries to parse an *ast.BadStmt into a defer or a go statement. 18999-// 19000-// go/parser packages a statement of the form "defer x." as an *ast.BadStmt because 19001-// it does not include a call expression. This means that go/types skips type-checking 19002-// this statement entirely, and we can't use the type information when completing. 19003-// Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST, 19004-// instead of the *ast.BadStmt. 19005-func fixDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) bool { 19006- // Check if we have a bad statement containing either a "go" or "defer". 19007- s := &scanner.Scanner{} 19008- s.Init(tok, src, nil, 0) 19009- 19010- var ( 19011- pos token.Pos 19012- tkn token.Token 19013- ) 19014- for { 19015- if tkn == token.EOF { 19016- return false 19017- } 19018- if pos >= bad.From { 19019- break 19020- } 19021- pos, tkn, _ = s.Scan() 19022- } 19023- 19024- var stmt ast.Stmt 19025- switch tkn { 19026- case token.DEFER: 19027- stmt = &ast.DeferStmt{ 19028- Defer: pos, 19029- } 19030- case token.GO: 19031- stmt = &ast.GoStmt{ 19032- Go: pos, 19033- } 19034- default: 19035- return false 19036- } 19037- 19038- var ( 19039- from, to, last token.Pos 19040- lastToken token.Token 19041- braceDepth int 19042- phantomSelectors []token.Pos 19043- ) 19044-FindTo: 19045- for { 19046- to, tkn, _ = s.Scan() 19047- 19048- if from == token.NoPos { 19049- from = to 19050- } 19051- 19052- switch tkn { 19053- case token.EOF: 19054- break FindTo 19055- case token.SEMICOLON: 19056- // If we aren't in nested braces, end of statement means 19057- // end of expression. 19058- if braceDepth == 0 { 19059- break FindTo 19060- } 19061- case token.LBRACE: 19062- braceDepth++ 19063- } 19064- 19065- // This handles the common dangling selector case. For example in 19066- // 19067- // defer fmt. 19068- // y := 1 19069- // 19070- // we notice the dangling period and end our expression. 19071- // 19072- // If the previous token was a "." and we are looking at a "}", 19073- // the period is likely a dangling selector and needs a phantom 19074- // "_". Likewise if the current token is on a different line than 19075- // the period, the period is likely a dangling selector. 19076- if lastToken == token.PERIOD && (tkn == token.RBRACE || tok.Line(to) > tok.Line(last)) { 19077- // Insert phantom "_" selector after the dangling ".". 19078- phantomSelectors = append(phantomSelectors, last+1) 19079- // If we aren't in a block then end the expression after the ".". 19080- if braceDepth == 0 { 19081- to = last + 1 19082- break 19083- } 19084- } 19085- 19086- lastToken = tkn 19087- last = to 19088- 19089- switch tkn { 19090- case token.RBRACE: 19091- braceDepth-- 19092- if braceDepth <= 0 { 19093- if braceDepth == 0 { 19094- // +1 to include the "}" itself. 19095- to += 1 19096- } 19097- break FindTo 19098- } 19099- } 19100- } 19101- 19102- fromOffset, toOffset, err := safetoken.Offsets(tok, from, to) 19103- if err != nil { 19104- return false 19105- } 19106- if !from.IsValid() || fromOffset >= len(src) { 19107- return false 19108- } 19109- if !to.IsValid() || toOffset >= len(src) { 19110- return false 19111- } 19112- 19113- // Insert any phantom selectors needed to prevent dangling "." from messing 19114- // up the AST. 19115- exprBytes := make([]byte, 0, int(to-from)+len(phantomSelectors)) 19116- for i, b := range src[fromOffset:toOffset] { 19117- if len(phantomSelectors) > 0 && from+token.Pos(i) == phantomSelectors[0] { 19118- exprBytes = append(exprBytes, '_') 19119- phantomSelectors = phantomSelectors[1:] 19120- } 19121- exprBytes = append(exprBytes, b) 19122- } 19123- 19124- if len(phantomSelectors) > 0 { 19125- exprBytes = append(exprBytes, '_') 19126- } 19127- 19128- expr, err := parseExpr(from, exprBytes) 19129- if err != nil { 19130- return false 19131- } 19132- 19133- // Package the expression into a fake *ast.CallExpr and re-insert 19134- // into the function. 19135- call := &ast.CallExpr{ 19136- Fun: expr, 19137- Lparen: to, 19138- Rparen: to, 19139- } 19140- 19141- switch stmt := stmt.(type) { 19142- case *ast.DeferStmt: 19143- stmt.Call = call 19144- case *ast.GoStmt: 19145- stmt.Call = call 19146- } 19147- 19148- return replaceNode(parent, bad, stmt) 19149-} 19150- 19151-// parseStmt parses the statement in src and updates its position to 19152-// start at pos. 19153-func parseStmt(pos token.Pos, src []byte) (ast.Stmt, error) { 19154- // Wrap our expression to make it a valid Go file we can pass to ParseFile. 19155- fileSrc := bytes.Join([][]byte{ 19156- []byte("package fake;func _(){"), 19157- src, 19158- []byte("}"), 19159- }, nil) 19160- 19161- // Use ParseFile instead of ParseExpr because ParseFile has 19162- // best-effort behavior, whereas ParseExpr fails hard on any error. 19163- fakeFile, err := parser.ParseFile(token.NewFileSet(), "", fileSrc, 0) 19164- if fakeFile == nil { 19165- return nil, fmt.Errorf("error reading fake file source: %v", err) 19166- } 19167- 19168- // Extract our expression node from inside the fake file. 19169- if len(fakeFile.Decls) == 0 { 19170- return nil, fmt.Errorf("error parsing fake file: %v", err) 19171- } 19172- 19173- fakeDecl, _ := fakeFile.Decls[0].(*ast.FuncDecl) 19174- if fakeDecl == nil || len(fakeDecl.Body.List) == 0 { 19175- return nil, fmt.Errorf("no statement in %s: %v", src, err) 19176- } 19177- 19178- stmt := fakeDecl.Body.List[0] 19179- 19180- // parser.ParseFile returns undefined positions. 19181- // Adjust them for the current file. 19182- offsetPositions(stmt, pos-1-(stmt.Pos()-1)) 19183- 19184- return stmt, nil 19185-} 19186- 19187-// parseExpr parses the expression in src and updates its position to 19188-// start at pos. 19189-func parseExpr(pos token.Pos, src []byte) (ast.Expr, error) { 19190- stmt, err := parseStmt(pos, src) 19191- if err != nil { 19192- return nil, err 19193- } 19194- 19195- exprStmt, ok := stmt.(*ast.ExprStmt) 19196- if !ok { 19197- return nil, fmt.Errorf("no expr in %s: %v", src, err) 19198- } 19199- 19200- return exprStmt.X, nil 19201-} 19202- 19203-var tokenPosType = reflect.TypeOf(token.NoPos) 19204- 19205-// offsetPositions applies an offset to the positions in an ast.Node. 19206-func offsetPositions(n ast.Node, offset token.Pos) { 19207- ast.Inspect(n, func(n ast.Node) bool { 19208- if n == nil { 19209- return false 19210- } 19211- 19212- v := reflect.ValueOf(n).Elem() 19213- 19214- switch v.Kind() { 19215- case reflect.Struct: 19216- for i := 0; i < v.NumField(); i++ { 19217- f := v.Field(i) 19218- if f.Type() != tokenPosType { 19219- continue 19220- } 19221- 19222- if !f.CanSet() { 19223- continue 19224- } 19225- 19226- // Don't offset invalid positions: they should stay invalid. 19227- if !token.Pos(f.Int()).IsValid() { 19228- continue 19229- } 19230- 19231- f.SetInt(f.Int() + int64(offset)) 19232- } 19233- } 19234- 19235- return true 19236- }) 19237-} 19238- 19239-// replaceNode updates parent's child oldChild to be newChild. It 19240-// returns whether it replaced successfully. 19241-func replaceNode(parent, oldChild, newChild ast.Node) bool { 19242- if parent == nil || oldChild == nil || newChild == nil { 19243- return false 19244- } 19245- 19246- parentVal := reflect.ValueOf(parent).Elem() 19247- if parentVal.Kind() != reflect.Struct { 19248- return false 19249- } 19250- 19251- newChildVal := reflect.ValueOf(newChild) 19252- 19253- tryReplace := func(v reflect.Value) bool { 19254- if !v.CanSet() || !v.CanInterface() { 19255- return false 19256- } 19257- 19258- // If the existing value is oldChild, we found our child. Make 19259- // sure our newChild is assignable and then make the swap. 19260- if v.Interface() == oldChild && newChildVal.Type().AssignableTo(v.Type()) { 19261- v.Set(newChildVal) 19262- return true 19263- } 19264- 19265- return false 19266- } 19267- 19268- // Loop over parent's struct fields. 19269- for i := 0; i < parentVal.NumField(); i++ { 19270- f := parentVal.Field(i) 19271- 19272- switch f.Kind() { 19273- // Check interface and pointer fields. 19274- case reflect.Interface, reflect.Ptr: 19275- if tryReplace(f) { 19276- return true 19277- } 19278- 19279- // Search through any slice fields. 19280- case reflect.Slice: 19281- for i := 0; i < f.Len(); i++ { 19282- if tryReplace(f.Index(i)) { 19283- return true 19284- } 19285- } 19286- } 19287- } 19288- 19289- return false 19290-} 19291diff -urN a/gopls/internal/lsp/cache/parsemode_go116.go b/gopls/internal/lsp/cache/parsemode_go116.go 19292--- a/gopls/internal/lsp/cache/parsemode_go116.go 2000-01-01 00:00:00.000000000 -0000 19293+++ b/gopls/internal/lsp/cache/parsemode_go116.go 1970-01-01 00:00:00.000000000 +0000 19294@@ -1,11 +0,0 @@ 19295-// Copyright 2022 The Go Authors. All rights reserved. 19296-// Use of this source code is governed by a BSD-style 19297-// license that can be found in the LICENSE file. 19298- 19299-//go:build !go1.17 19300-// +build !go1.17 19301- 19302-package cache 19303- 19304-// The parser.SkipObjectResolution mode flag is not supported before Go 1.17. 19305-const skipObjectResolution = 0 19306diff -urN a/gopls/internal/lsp/cache/parsemode_go117.go b/gopls/internal/lsp/cache/parsemode_go117.go 19307--- a/gopls/internal/lsp/cache/parsemode_go117.go 2000-01-01 00:00:00.000000000 -0000 19308+++ b/gopls/internal/lsp/cache/parsemode_go117.go 1970-01-01 00:00:00.000000000 +0000 19309@@ -1,12 +0,0 @@ 19310-// Copyright 2022 The Go Authors. All rights reserved. 19311-// Use of this source code is governed by a BSD-style 19312-// license that can be found in the LICENSE file. 19313- 19314-//go:build go1.17 19315-// +build go1.17 19316- 19317-package cache 19318- 19319-import "go/parser" 19320- 19321-const skipObjectResolution = parser.SkipObjectResolution 19322diff -urN a/gopls/internal/lsp/cache/pkg.go b/gopls/internal/lsp/cache/pkg.go 19323--- a/gopls/internal/lsp/cache/pkg.go 2000-01-01 00:00:00.000000000 -0000 19324+++ b/gopls/internal/lsp/cache/pkg.go 1970-01-01 00:00:00.000000000 +0000 19325@@ -1,165 +0,0 @@ 19326-// Copyright 2019 The Go Authors. All rights reserved. 19327-// Use of this source code is governed by a BSD-style 19328-// license that can be found in the LICENSE file. 19329- 19330-package cache 19331- 19332-import ( 19333- "context" 19334- "fmt" 19335- "go/ast" 19336- "go/scanner" 19337- "go/token" 19338- "go/types" 19339- 19340- "golang.org/x/tools/gopls/internal/lsp/source" 19341- "golang.org/x/tools/gopls/internal/lsp/source/methodsets" 19342- "golang.org/x/tools/gopls/internal/span" 19343- "golang.org/x/tools/internal/memoize" 19344-) 19345- 19346-// Convenient local aliases for typed strings. 19347-type ( 19348- PackageID = source.PackageID 19349- PackagePath = source.PackagePath 19350- PackageName = source.PackageName 19351- ImportPath = source.ImportPath 19352-) 19353- 19354-// A Package is the union of snapshot-local information (Metadata) and shared 19355-// type-checking information (a syntaxPackage). 19356-// 19357-// TODO(rfindley): for now, we do not persist the post-processing of 19358-// loadDiagnostics, because the value of the snapshot.packages map is just the 19359-// package handle. Fix this. 19360-type Package struct { 19361- m *source.Metadata 19362- pkg *syntaxPackage 19363-} 19364- 19365-// syntaxPackage contains parse trees and type information for a package. 19366-type syntaxPackage struct { 19367- // -- identifiers -- 19368- id PackageID 19369- mode source.ParseMode 19370- 19371- // -- outputs -- 19372- fset *token.FileSet // for now, same as the snapshot's FileSet 19373- goFiles []*source.ParsedGoFile 19374- compiledGoFiles []*source.ParsedGoFile 19375- diagnostics []*source.Diagnostic 19376- parseErrors []scanner.ErrorList 19377- typeErrors []types.Error 19378- types *types.Package 19379- typesInfo *types.Info 19380- importMap map[string]*types.Package // keys are PackagePaths 19381- hasFixedFiles bool // if true, AST was sufficiently mangled that we should hide type errors 19382- analyses memoize.Store // maps analyzer.Name to Promise[actionResult] 19383- xrefs []byte 19384- methodsets *methodsets.Index 19385-} 19386- 19387-func (p *Package) String() string { return string(p.m.ID) } 19388- 19389-func (p *Package) Metadata() *source.Metadata { return p.m } 19390- 19391-// A loadScope defines a package loading scope for use with go/packages. 19392-// 19393-// TODO(rfindley): move this to load.go. 19394-type loadScope interface { 19395- aScope() 19396-} 19397- 19398-type ( 19399- fileLoadScope span.URI // load packages containing a file (including command-line-arguments) 19400- packageLoadScope string // load a specific package (the value is its PackageID) 19401- moduleLoadScope string // load packages in a specific module 19402- viewLoadScope span.URI // load the workspace 19403-) 19404- 19405-// Implement the loadScope interface. 19406-func (fileLoadScope) aScope() {} 19407-func (packageLoadScope) aScope() {} 19408-func (moduleLoadScope) aScope() {} 19409-func (viewLoadScope) aScope() {} 19410- 19411-func (p *Package) ParseMode() source.ParseMode { 19412- return p.pkg.mode 19413-} 19414- 19415-func (p *Package) CompiledGoFiles() []*source.ParsedGoFile { 19416- return p.pkg.compiledGoFiles 19417-} 19418- 19419-func (p *Package) File(uri span.URI) (*source.ParsedGoFile, error) { 19420- return p.pkg.File(uri) 19421-} 19422- 19423-func (pkg *syntaxPackage) File(uri span.URI) (*source.ParsedGoFile, error) { 19424- for _, cgf := range pkg.compiledGoFiles { 19425- if cgf.URI == uri { 19426- return cgf, nil 19427- } 19428- } 19429- for _, gf := range pkg.goFiles { 19430- if gf.URI == uri { 19431- return gf, nil 19432- } 19433- } 19434- return nil, fmt.Errorf("no parsed file for %s in %v", uri, pkg.id) 19435-} 19436- 19437-func (p *Package) GetSyntax() []*ast.File { 19438- var syntax []*ast.File 19439- for _, pgf := range p.pkg.compiledGoFiles { 19440- syntax = append(syntax, pgf.File) 19441- } 19442- return syntax 19443-} 19444- 19445-func (p *Package) FileSet() *token.FileSet { 19446- return p.pkg.fset 19447-} 19448- 19449-func (p *Package) GetTypes() *types.Package { 19450- return p.pkg.types 19451-} 19452- 19453-func (p *Package) GetTypesInfo() *types.Info { 19454- return p.pkg.typesInfo 19455-} 19456- 19457-// DependencyTypes returns the type checker's symbol for the specified 19458-// package. It returns nil if path is not among the transitive 19459-// dependencies of p, or if no symbols from that package were 19460-// referenced during the type-checking of p. 19461-func (p *Package) DependencyTypes(path source.PackagePath) *types.Package { 19462- if path == p.m.PkgPath { 19463- return p.pkg.types 19464- } 19465- return p.pkg.importMap[string(path)] 19466-} 19467- 19468-func (p *Package) HasParseErrors() bool { 19469- return len(p.pkg.parseErrors) != 0 19470-} 19471- 19472-func (p *Package) HasTypeErrors() bool { 19473- return len(p.pkg.typeErrors) != 0 19474-} 19475- 19476-func (p *Package) DiagnosticsForFile(ctx context.Context, s source.Snapshot, uri span.URI) ([]*source.Diagnostic, error) { 19477- var diags []*source.Diagnostic 19478- for _, diag := range p.m.Diagnostics { 19479- if diag.URI == uri { 19480- diags = append(diags, diag) 19481- } 19482- } 19483- for _, diag := range p.pkg.diagnostics { 19484- if diag.URI == uri { 19485- diags = append(diags, diag) 19486- } 19487- } 19488- 19489- return diags, nil 19490-} 19491diff -urN a/gopls/internal/lsp/cache/session.go b/gopls/internal/lsp/cache/session.go 19492--- a/gopls/internal/lsp/cache/session.go 2000-01-01 00:00:00.000000000 -0000 19493+++ b/gopls/internal/lsp/cache/session.go 1970-01-01 00:00:00.000000000 +0000 19494@@ -1,730 +0,0 @@ 19495-// Copyright 2019 The Go Authors. All rights reserved. 19496-// Use of this source code is governed by a BSD-style 19497-// license that can be found in the LICENSE file. 19498- 19499-package cache 19500- 19501-import ( 19502- "context" 19503- "fmt" 19504- "strconv" 19505- "strings" 19506- "sync" 19507- "sync/atomic" 19508- 19509- "golang.org/x/tools/gopls/internal/govulncheck" 19510- "golang.org/x/tools/gopls/internal/lsp/source" 19511- "golang.org/x/tools/gopls/internal/span" 19512- "golang.org/x/tools/internal/bug" 19513- "golang.org/x/tools/internal/event" 19514- "golang.org/x/tools/internal/gocommand" 19515- "golang.org/x/tools/internal/imports" 19516- "golang.org/x/tools/internal/persistent" 19517- "golang.org/x/tools/internal/xcontext" 19518-) 19519- 19520-type Session struct { 19521- // Unique identifier for this session. 19522- id string 19523- 19524- // Immutable attributes shared across views. 19525- cache *Cache // shared cache 19526- gocmdRunner *gocommand.Runner // limits go command concurrency 19527- 19528- optionsMu sync.Mutex 19529- options *source.Options 19530- 19531- viewMu sync.Mutex 19532- views []*View 19533- viewMap map[span.URI]*View // map of URI->best view 19534- 19535- *overlayFS 19536-} 19537- 19538-// ID returns the unique identifier for this session on this server. 19539-func (s *Session) ID() string { return s.id } 19540-func (s *Session) String() string { return s.id } 19541- 19542-// Options returns a copy of the SessionOptions for this session. 19543-func (s *Session) Options() *source.Options { 19544- s.optionsMu.Lock() 19545- defer s.optionsMu.Unlock() 19546- return s.options 19547-} 19548- 19549-// SetOptions sets the options of this session to new values. 19550-func (s *Session) SetOptions(options *source.Options) { 19551- s.optionsMu.Lock() 19552- defer s.optionsMu.Unlock() 19553- s.options = options 19554-} 19555- 19556-// Shutdown the session and all views it has created. 19557-func (s *Session) Shutdown(ctx context.Context) { 19558- var views []*View 19559- s.viewMu.Lock() 19560- views = append(views, s.views...) 19561- s.views = nil 19562- s.viewMap = nil 19563- s.viewMu.Unlock() 19564- for _, view := range views { 19565- view.shutdown() 19566- } 19567- event.Log(ctx, "Shutdown session", KeyShutdownSession.Of(s)) 19568-} 19569- 19570-// Cache returns the cache that created this session, for debugging only. 19571-func (s *Session) Cache() *Cache { 19572- return s.cache 19573-} 19574- 19575-// NewView creates a new View, returning it and its first snapshot. If a 19576-// non-empty tempWorkspace directory is provided, the View will record a copy 19577-// of its gopls workspace module in that directory, so that client tooling 19578-// can execute in the same main module. On success it also returns a release 19579-// function that must be called when the Snapshot is no longer needed. 19580-func (s *Session) NewView(ctx context.Context, name string, folder span.URI, options *source.Options) (*View, source.Snapshot, func(), error) { 19581- s.viewMu.Lock() 19582- defer s.viewMu.Unlock() 19583- for _, view := range s.views { 19584- if span.SameExistingFile(view.folder, folder) { 19585- return nil, nil, nil, source.ErrViewExists 19586- } 19587- } 19588- view, snapshot, release, err := s.createView(ctx, name, folder, options, 0) 19589- if err != nil { 19590- return nil, nil, nil, err 19591- } 19592- s.views = append(s.views, view) 19593- // we always need to drop the view map 19594- s.viewMap = make(map[span.URI]*View) 19595- return view, snapshot, release, nil 19596-} 19597- 19598-// TODO(rfindley): clarify that createView can never be cancelled (with the 19599-// possible exception of server shutdown). 19600-func (s *Session) createView(ctx context.Context, name string, folder span.URI, options *source.Options, seqID uint64) (*View, *snapshot, func(), error) { 19601- index := atomic.AddInt64(&viewIndex, 1) 19602- 19603- // Get immutable workspace information. 19604- info, err := s.getWorkspaceInformation(ctx, folder, options) 19605- if err != nil { 19606- return nil, nil, func() {}, err 19607- } 19608- 19609- wsModFiles, wsModFilesErr := computeWorkspaceModFiles(ctx, info.gomod, info.effectiveGOWORK(), info.effectiveGO111MODULE(), s) 19610- 19611- // We want a true background context and not a detached context here 19612- // the spans need to be unrelated and no tag values should pollute it. 19613- baseCtx := event.Detach(xcontext.Detach(ctx)) 19614- backgroundCtx, cancel := context.WithCancel(baseCtx) 19615- 19616- v := &View{ 19617- id: strconv.FormatInt(index, 10), 19618- gocmdRunner: s.gocmdRunner, 19619- initialWorkspaceLoad: make(chan struct{}), 19620- initializationSema: make(chan struct{}, 1), 19621- options: options, 19622- baseCtx: baseCtx, 19623- name: name, 19624- folder: folder, 19625- moduleUpgrades: map[span.URI]map[string]string{}, 19626- vulns: map[span.URI]*govulncheck.Result{}, 19627- fs: s.overlayFS, 19628- workspaceInformation: info, 19629- } 19630- v.importsState = &importsState{ 19631- ctx: backgroundCtx, 19632- processEnv: &imports.ProcessEnv{ 19633- GocmdRunner: s.gocmdRunner, 19634- SkipPathInScan: func(dir string) bool { 19635- prefix := strings.TrimSuffix(string(v.folder), "/") + "/" 19636- uri := strings.TrimSuffix(string(span.URIFromPath(dir)), "/") 19637- if !strings.HasPrefix(uri+"/", prefix) { 19638- return false 19639- } 19640- filterer := source.NewFilterer(options.DirectoryFilters) 19641- rel := strings.TrimPrefix(uri, prefix) 19642- disallow := filterer.Disallow(rel) 19643- return disallow 19644- }, 19645- }, 19646- } 19647- v.snapshot = &snapshot{ 19648- sequenceID: seqID, 19649- globalID: nextSnapshotID(), 19650- view: v, 19651- backgroundCtx: backgroundCtx, 19652- cancel: cancel, 19653- store: s.cache.store, 19654- packages: persistent.NewMap(packageIDLessInterface), 19655- meta: new(metadataGraph), 19656- files: newFilesMap(), 19657- parseCache: new(parseCache), 19658- activePackages: persistent.NewMap(packageIDLessInterface), 19659- symbolizeHandles: persistent.NewMap(uriLessInterface), 19660- analyses: persistent.NewMap(analysisKeyLessInterface), 19661- workspacePackages: make(map[PackageID]PackagePath), 19662- unloadableFiles: make(map[span.URI]struct{}), 19663- parseModHandles: persistent.NewMap(uriLessInterface), 19664- parseWorkHandles: persistent.NewMap(uriLessInterface), 19665- modTidyHandles: persistent.NewMap(uriLessInterface), 19666- modVulnHandles: persistent.NewMap(uriLessInterface), 19667- modWhyHandles: persistent.NewMap(uriLessInterface), 19668- knownSubdirs: newKnownDirsSet(), 19669- workspaceModFiles: wsModFiles, 19670- workspaceModFilesErr: wsModFilesErr, 19671- } 19672- // Save one reference in the view. 19673- v.releaseSnapshot = v.snapshot.Acquire() 19674- 19675- // Record the environment of the newly created view in the log. 19676- event.Log(ctx, viewEnv(v)) 19677- 19678- // Initialize the view without blocking. 19679- initCtx, initCancel := context.WithCancel(xcontext.Detach(ctx)) 19680- v.initCancelFirstAttempt = initCancel 19681- snapshot := v.snapshot 19682- 19683- // Pass a second reference to the background goroutine. 19684- bgRelease := snapshot.Acquire() 19685- go func() { 19686- defer bgRelease() 19687- snapshot.initialize(initCtx, true) 19688- }() 19689- 19690- // Return a third reference to the caller. 19691- return v, snapshot, snapshot.Acquire(), nil 19692-} 19693- 19694-// View returns a view with a matching name, if the session has one. 19695-func (s *Session) View(name string) *View { 19696- s.viewMu.Lock() 19697- defer s.viewMu.Unlock() 19698- for _, view := range s.views { 19699- if view.Name() == name { 19700- return view 19701- } 19702- } 19703- return nil 19704-} 19705- 19706-// ViewOf returns a view corresponding to the given URI. 19707-// If the file is not already associated with a view, pick one using some heuristics. 19708-func (s *Session) ViewOf(uri span.URI) (*View, error) { 19709- s.viewMu.Lock() 19710- defer s.viewMu.Unlock() 19711- return s.viewOfLocked(uri) 19712-} 19713- 19714-// Precondition: caller holds s.viewMu lock. 19715-func (s *Session) viewOfLocked(uri span.URI) (*View, error) { 19716- // Check if we already know this file. 19717- if v, found := s.viewMap[uri]; found { 19718- return v, nil 19719- } 19720- // Pick the best view for this file and memoize the result. 19721- if len(s.views) == 0 { 19722- return nil, fmt.Errorf("no views in session") 19723- } 19724- s.viewMap[uri] = bestViewForURI(uri, s.views) 19725- return s.viewMap[uri], nil 19726-} 19727- 19728-func (s *Session) Views() []*View { 19729- s.viewMu.Lock() 19730- defer s.viewMu.Unlock() 19731- result := make([]*View, len(s.views)) 19732- copy(result, s.views) 19733- return result 19734-} 19735- 19736-// bestViewForURI returns the most closely matching view for the given URI 19737-// out of the given set of views. 19738-func bestViewForURI(uri span.URI, views []*View) *View { 19739- // we need to find the best view for this file 19740- var longest *View 19741- for _, view := range views { 19742- if longest != nil && len(longest.Folder()) > len(view.Folder()) { 19743- continue 19744- } 19745- // TODO(rfindley): this should consider the workspace layout (i.e. 19746- // go.work). 19747- if view.contains(uri) { 19748- longest = view 19749- } 19750- } 19751- if longest != nil { 19752- return longest 19753- } 19754- // Try our best to return a view that knows the file. 19755- for _, view := range views { 19756- if view.knownFile(uri) { 19757- return view 19758- } 19759- } 19760- // TODO: are there any more heuristics we can use? 19761- return views[0] 19762-} 19763- 19764-// RemoveView removes the view v from the session 19765-func (s *Session) RemoveView(view *View) { 19766- s.viewMu.Lock() 19767- defer s.viewMu.Unlock() 19768- i := s.dropView(view) 19769- if i == -1 { // error reported elsewhere 19770- return 19771- } 19772- // delete this view... we don't care about order but we do want to make 19773- // sure we can garbage collect the view 19774- s.views = removeElement(s.views, i) 19775-} 19776- 19777-// updateView recreates the view with the given options. 19778-// 19779-// If the resulting error is non-nil, the view may or may not have already been 19780-// dropped from the session. 19781-func (s *Session) updateView(ctx context.Context, view *View, options *source.Options) (*View, error) { 19782- s.viewMu.Lock() 19783- defer s.viewMu.Unlock() 19784- 19785- return s.updateViewLocked(ctx, view, options) 19786-} 19787- 19788-func (s *Session) updateViewLocked(ctx context.Context, view *View, options *source.Options) (*View, error) { 19789- // Preserve the snapshot ID if we are recreating the view. 19790- view.snapshotMu.Lock() 19791- if view.snapshot == nil { 19792- view.snapshotMu.Unlock() 19793- panic("updateView called after View was already shut down") 19794- } 19795- seqID := view.snapshot.sequenceID // Preserve sequence IDs when updating a view in place. 19796- view.snapshotMu.Unlock() 19797- 19798- i := s.dropView(view) 19799- if i == -1 { 19800- return nil, fmt.Errorf("view %q not found", view.id) 19801- } 19802- 19803- v, _, release, err := s.createView(ctx, view.name, view.folder, options, seqID) 19804- release() 19805- 19806- if err != nil { 19807- // we have dropped the old view, but could not create the new one 19808- // this should not happen and is very bad, but we still need to clean 19809- // up the view array if it happens 19810- s.views = removeElement(s.views, i) 19811- return nil, err 19812- } 19813- // substitute the new view into the array where the old view was 19814- s.views[i] = v 19815- return v, nil 19816-} 19817- 19818-// removeElement removes the ith element from the slice replacing it with the last element. 19819-// TODO(adonovan): generics, someday. 19820-func removeElement(slice []*View, index int) []*View { 19821- last := len(slice) - 1 19822- slice[index] = slice[last] 19823- slice[last] = nil // aid GC 19824- return slice[:last] 19825-} 19826- 19827-// dropView removes v from the set of views for the receiver s and calls 19828-// v.shutdown, returning the index of v in s.views (if found), or -1 if v was 19829-// not found. s.viewMu must be held while calling this function. 19830-func (s *Session) dropView(v *View) int { 19831- // we always need to drop the view map 19832- s.viewMap = make(map[span.URI]*View) 19833- for i := range s.views { 19834- if v == s.views[i] { 19835- // we found the view, drop it and return the index it was found at 19836- s.views[i] = nil 19837- v.shutdown() 19838- return i 19839- } 19840- } 19841- // TODO(rfindley): it looks wrong that we don't shutdown v in this codepath. 19842- // We should never get here. 19843- bug.Reportf("tried to drop nonexistent view %q", v.id) 19844- return -1 19845-} 19846- 19847-func (s *Session) ModifyFiles(ctx context.Context, changes []source.FileModification) error { 19848- _, release, err := s.DidModifyFiles(ctx, changes) 19849- release() 19850- return err 19851-} 19852- 19853-// TODO(rfindley): fileChange seems redundant with source.FileModification. 19854-// De-dupe into a common representation for changes. 19855-type fileChange struct { 19856- content []byte 19857- exists bool 19858- fileHandle source.FileHandle 19859- 19860- // isUnchanged indicates whether the file action is one that does not 19861- // change the actual contents of the file. Opens and closes should not 19862- // be treated like other changes, since the file content doesn't change. 19863- isUnchanged bool 19864-} 19865- 19866-// DidModifyFiles reports a file modification to the session. It returns 19867-// the new snapshots after the modifications have been applied, paired with 19868-// the affected file URIs for those snapshots. 19869-// On success, it returns a release function that 19870-// must be called when the snapshots are no longer needed. 19871-// 19872-// TODO(rfindley): what happens if this function fails? It must leave us in a 19873-// broken state, which we should surface to the user, probably as a request to 19874-// restart gopls. 19875-func (s *Session) DidModifyFiles(ctx context.Context, changes []source.FileModification) (map[source.Snapshot][]span.URI, func(), error) { 19876- s.viewMu.Lock() 19877- defer s.viewMu.Unlock() 19878- 19879- // Update overlays. 19880- // 19881- // TODO(rfindley): I think we do this while holding viewMu to prevent views 19882- // from seeing the updated file content before they have processed 19883- // invalidations, which could lead to a partial view of the changes (i.e. 19884- // spurious diagnostics). However, any such view would immediately be 19885- // invalidated here, so it is possible that we could update overlays before 19886- // acquiring viewMu. 19887- if err := s.updateOverlays(ctx, changes); err != nil { 19888- return nil, nil, err 19889- } 19890- 19891- // Re-create views whose definition may have changed. 19892- // 19893- // checkViews controls whether to re-evaluate view definitions when 19894- // collecting views below. Any addition or deletion of a go.mod or go.work 19895- // file may have affected the definition of the view. 19896- checkViews := false 19897- 19898- for _, c := range changes { 19899- if isGoMod(c.URI) || isGoWork(c.URI) { 19900- // Change, InvalidateMetadata, and UnknownFileAction actions do not cause 19901- // us to re-evaluate views. 19902- redoViews := (c.Action != source.Change && 19903- c.Action != source.InvalidateMetadata && 19904- c.Action != source.UnknownFileAction) 19905- 19906- if redoViews { 19907- checkViews = true 19908- break 19909- } 19910- } 19911- } 19912- 19913- if checkViews { 19914- for _, view := range s.views { 19915- // TODO(rfindley): can we avoid running the go command (go env) 19916- // synchronously to change processing? Can we assume that the env did not 19917- // change, and derive go.work using a combination of the configured 19918- // GOWORK value and filesystem? 19919- info, err := s.getWorkspaceInformation(ctx, view.folder, view.Options()) 19920- if err != nil { 19921- // Catastrophic failure, equivalent to a failure of session 19922- // initialization and therefore should almost never happen. One 19923- // scenario where this failure mode could occur is if some file 19924- // permissions have changed preventing us from reading go.mod 19925- // files. 19926- // 19927- // TODO(rfindley): consider surfacing this error more loudly. We 19928- // could report a bug, but it's not really a bug. 19929- event.Error(ctx, "fetching workspace information", err) 19930- } 19931- 19932- if info != view.workspaceInformation { 19933- _, err := s.updateViewLocked(ctx, view, view.Options()) 19934- if err != nil { 19935- // More catastrophic failure. The view may or may not still exist. 19936- // The best we can do is log and move on. 19937- event.Error(ctx, "recreating view", err) 19938- } 19939- } 19940- } 19941- } 19942- 19943- // Collect information about views affected by these changes. 19944- views := make(map[*View]map[span.URI]*fileChange) 19945- affectedViews := map[span.URI][]*View{} 19946- // forceReloadMetadata records whether any change is the magic 19947- // source.InvalidateMetadata action. 19948- forceReloadMetadata := false 19949- for _, c := range changes { 19950- if c.Action == source.InvalidateMetadata { 19951- forceReloadMetadata = true 19952- } 19953- // Build the list of affected views. 19954- var changedViews []*View 19955- for _, view := range s.views { 19956- // Don't propagate changes that are outside of the view's scope 19957- // or knowledge. 19958- if !view.relevantChange(c) { 19959- continue 19960- } 19961- changedViews = append(changedViews, view) 19962- } 19963- // If the change is not relevant to any view, but the change is 19964- // happening in the editor, assign it the most closely matching view. 19965- if len(changedViews) == 0 { 19966- if c.OnDisk { 19967- continue 19968- } 19969- bestView, err := s.viewOfLocked(c.URI) 19970- if err != nil { 19971- return nil, nil, err 19972- } 19973- changedViews = append(changedViews, bestView) 19974- } 19975- affectedViews[c.URI] = changedViews 19976- 19977- isUnchanged := c.Action == source.Open || c.Action == source.Close 19978- 19979- // Apply the changes to all affected views. 19980- for _, view := range changedViews { 19981- // Make sure that the file is added to the view's seenFiles set. 19982- view.markKnown(c.URI) 19983- if _, ok := views[view]; !ok { 19984- views[view] = make(map[span.URI]*fileChange) 19985- } 19986- fh, err := s.GetFile(ctx, c.URI) 19987- if err != nil { 19988- return nil, nil, err 19989- } 19990- content, err := fh.Read() 19991- if err != nil { 19992- // Ignore the error: the file may be deleted. 19993- content = nil 19994- } 19995- views[view][c.URI] = &fileChange{ 19996- content: content, 19997- exists: err == nil, 19998- fileHandle: fh, 19999- isUnchanged: isUnchanged, 20000- } 20001- } 20002- } 20003- 20004- var releases []func() 20005- viewToSnapshot := map[*View]*snapshot{} 20006- for view, changed := range views { 20007- snapshot, release := view.invalidateContent(ctx, changed, forceReloadMetadata) 20008- releases = append(releases, release) 20009- viewToSnapshot[view] = snapshot 20010- } 20011- 20012- // The release function is called when the 20013- // returned URIs no longer need to be valid. 20014- release := func() { 20015- for _, release := range releases { 20016- release() 20017- } 20018- } 20019- 20020- // We only want to diagnose each changed file once, in the view to which 20021- // it "most" belongs. We do this by picking the best view for each URI, 20022- // and then aggregating the set of snapshots and their URIs (to avoid 20023- // diagnosing the same snapshot multiple times). 20024- snapshotURIs := map[source.Snapshot][]span.URI{} 20025- for _, mod := range changes { 20026- viewSlice, ok := affectedViews[mod.URI] 20027- if !ok || len(viewSlice) == 0 { 20028- continue 20029- } 20030- view := bestViewForURI(mod.URI, viewSlice) 20031- snapshot, ok := viewToSnapshot[view] 20032- if !ok { 20033- panic(fmt.Sprintf("no snapshot for view %s", view.Folder())) 20034- } 20035- snapshotURIs[snapshot] = append(snapshotURIs[snapshot], mod.URI) 20036- } 20037- 20038- return snapshotURIs, release, nil 20039-} 20040- 20041-// ExpandModificationsToDirectories returns the set of changes with the 20042-// directory changes removed and expanded to include all of the files in 20043-// the directory. 20044-func (s *Session) ExpandModificationsToDirectories(ctx context.Context, changes []source.FileModification) []source.FileModification { 20045- var snapshots []*snapshot 20046- s.viewMu.Lock() 20047- for _, v := range s.views { 20048- snapshot, release, err := v.getSnapshot() 20049- if err != nil { 20050- continue // view is shut down; continue with others 20051- } 20052- defer release() 20053- snapshots = append(snapshots, snapshot) 20054- } 20055- s.viewMu.Unlock() 20056- 20057- knownDirs := knownDirectories(ctx, snapshots) 20058- defer knownDirs.Destroy() 20059- 20060- var result []source.FileModification 20061- for _, c := range changes { 20062- if !knownDirs.Contains(c.URI) { 20063- result = append(result, c) 20064- continue 20065- } 20066- affectedFiles := knownFilesInDir(ctx, snapshots, c.URI) 20067- var fileChanges []source.FileModification 20068- for uri := range affectedFiles { 20069- fileChanges = append(fileChanges, source.FileModification{ 20070- URI: uri, 20071- Action: c.Action, 20072- LanguageID: "", 20073- OnDisk: c.OnDisk, 20074- // changes to directories cannot include text or versions 20075- }) 20076- } 20077- result = append(result, fileChanges...) 20078- } 20079- return result 20080-} 20081- 20082-// knownDirectories returns all of the directories known to the given 20083-// snapshots, including workspace directories and their subdirectories. 20084-// It is responsibility of the caller to destroy the returned set. 20085-func knownDirectories(ctx context.Context, snapshots []*snapshot) knownDirsSet { 20086- result := newKnownDirsSet() 20087- for _, snapshot := range snapshots { 20088- dirs := snapshot.dirs(ctx) 20089- for _, dir := range dirs { 20090- result.Insert(dir) 20091- } 20092- knownSubdirs := snapshot.getKnownSubdirs(dirs) 20093- result.SetAll(knownSubdirs) 20094- knownSubdirs.Destroy() 20095- } 20096- return result 20097-} 20098- 20099-// knownFilesInDir returns the files known to the snapshots in the session. 20100-// It does not respect symlinks. 20101-func knownFilesInDir(ctx context.Context, snapshots []*snapshot, dir span.URI) map[span.URI]struct{} { 20102- files := map[span.URI]struct{}{} 20103- 20104- for _, snapshot := range snapshots { 20105- for _, uri := range snapshot.knownFilesInDir(ctx, dir) { 20106- files[uri] = struct{}{} 20107- } 20108- } 20109- return files 20110-} 20111- 20112-// Precondition: caller holds s.viewMu lock. 20113-// TODO(rfindley): move this to fs_overlay.go. 20114-func (fs *overlayFS) updateOverlays(ctx context.Context, changes []source.FileModification) error { 20115- fs.mu.Lock() 20116- defer fs.mu.Unlock() 20117- 20118- for _, c := range changes { 20119- // Don't update overlays for metadata invalidations. 20120- if c.Action == source.InvalidateMetadata { 20121- continue 20122- } 20123- 20124- o, ok := fs.overlays[c.URI] 20125- 20126- // If the file is not opened in an overlay and the change is on disk, 20127- // there's no need to update an overlay. If there is an overlay, we 20128- // may need to update the overlay's saved value. 20129- if !ok && c.OnDisk { 20130- continue 20131- } 20132- 20133- // Determine the file kind on open, otherwise, assume it has been cached. 20134- var kind source.FileKind 20135- switch c.Action { 20136- case source.Open: 20137- kind = source.FileKindForLang(c.LanguageID) 20138- default: 20139- if !ok { 20140- return fmt.Errorf("updateOverlays: modifying unopened overlay %v", c.URI) 20141- } 20142- kind = o.kind 20143- } 20144- 20145- // Closing a file just deletes its overlay. 20146- if c.Action == source.Close { 20147- delete(fs.overlays, c.URI) 20148- continue 20149- } 20150- 20151- // If the file is on disk, check if its content is the same as in the 20152- // overlay. Saves and on-disk file changes don't come with the file's 20153- // content. 20154- text := c.Text 20155- if text == nil && (c.Action == source.Save || c.OnDisk) { 20156- if !ok { 20157- return fmt.Errorf("no known content for overlay for %s", c.Action) 20158- } 20159- text = o.content 20160- } 20161- // On-disk changes don't come with versions. 20162- version := c.Version 20163- if c.OnDisk || c.Action == source.Save { 20164- version = o.version 20165- } 20166- hash := source.HashOf(text) 20167- var sameContentOnDisk bool 20168- switch c.Action { 20169- case source.Delete: 20170- // Do nothing. sameContentOnDisk should be false. 20171- case source.Save: 20172- // Make sure the version and content (if present) is the same. 20173- if false && o.version != version { // Client no longer sends the version 20174- return fmt.Errorf("updateOverlays: saving %s at version %v, currently at %v", c.URI, c.Version, o.version) 20175- } 20176- if c.Text != nil && o.hash != hash { 20177- return fmt.Errorf("updateOverlays: overlay %s changed on save", c.URI) 20178- } 20179- sameContentOnDisk = true 20180- default: 20181- fh, err := fs.delegate.GetFile(ctx, c.URI) 20182- if err != nil { 20183- return err 20184- } 20185- _, readErr := fh.Read() 20186- sameContentOnDisk = (readErr == nil && fh.FileIdentity().Hash == hash) 20187- } 20188- o = &Overlay{ 20189- uri: c.URI, 20190- version: version, 20191- content: text, 20192- kind: kind, 20193- hash: hash, 20194- saved: sameContentOnDisk, 20195- } 20196- 20197- // NOTE: previous versions of this code checked here that the overlay had a 20198- // view and file kind (but we don't know why). 20199- 20200- fs.overlays[c.URI] = o 20201- } 20202- 20203- return nil 20204-} 20205- 20206-// FileWatchingGlobPatterns returns glob patterns to watch every directory 20207-// known by the view. For views within a module, this is the module root, 20208-// any directory in the module root, and any replace targets. 20209-func (s *Session) FileWatchingGlobPatterns(ctx context.Context) map[string]struct{} { 20210- s.viewMu.Lock() 20211- defer s.viewMu.Unlock() 20212- patterns := map[string]struct{}{} 20213- for _, view := range s.views { 20214- snapshot, release, err := view.getSnapshot() 20215- if err != nil { 20216- continue // view is shut down; continue with others 20217- } 20218- for k, v := range snapshot.fileWatchingGlobPatterns(ctx) { 20219- patterns[k] = v 20220- } 20221- release() 20222- } 20223- return patterns 20224-} 20225diff -urN a/gopls/internal/lsp/cache/snapshot.go b/gopls/internal/lsp/cache/snapshot.go 20226--- a/gopls/internal/lsp/cache/snapshot.go 2000-01-01 00:00:00.000000000 -0000 20227+++ b/gopls/internal/lsp/cache/snapshot.go 1970-01-01 00:00:00.000000000 +0000 20228@@ -1,2214 +0,0 @@ 20229-// Copyright 2019 The Go Authors. All rights reserved. 20230-// Use of this source code is governed by a BSD-style 20231-// license that can be found in the LICENSE file. 20232- 20233-package cache 20234- 20235-import ( 20236- "bytes" 20237- "context" 20238- "errors" 20239- "fmt" 20240- "go/ast" 20241- "go/token" 20242- "go/types" 20243- "io" 20244- "io/ioutil" 20245- "log" 20246- "os" 20247- "path/filepath" 20248- "regexp" 20249- "runtime" 20250- "sort" 20251- "strconv" 20252- "strings" 20253- "sync" 20254- "sync/atomic" 20255- "unsafe" 20256- 20257- "golang.org/x/sync/errgroup" 20258- "golang.org/x/tools/go/packages" 20259- "golang.org/x/tools/go/types/objectpath" 20260- "golang.org/x/tools/gopls/internal/lsp/protocol" 20261- "golang.org/x/tools/gopls/internal/lsp/source" 20262- "golang.org/x/tools/gopls/internal/lsp/source/methodsets" 20263- "golang.org/x/tools/gopls/internal/lsp/source/xrefs" 20264- "golang.org/x/tools/gopls/internal/span" 20265- "golang.org/x/tools/internal/bug" 20266- "golang.org/x/tools/internal/event" 20267- "golang.org/x/tools/internal/event/tag" 20268- "golang.org/x/tools/internal/gocommand" 20269- "golang.org/x/tools/internal/memoize" 20270- "golang.org/x/tools/internal/packagesinternal" 20271- "golang.org/x/tools/internal/persistent" 20272- "golang.org/x/tools/internal/typesinternal" 20273-) 20274- 20275-type snapshot struct { 20276- sequenceID uint64 20277- globalID source.GlobalSnapshotID 20278- 20279- // TODO(rfindley): the snapshot holding a reference to the view poses 20280- // lifecycle problems: a view may be shut down and waiting for work 20281- // associated with this snapshot to complete. While most accesses of the view 20282- // are benign (options or workspace information), this is not formalized and 20283- // it is wrong for the snapshot to use a shutdown view. 20284- // 20285- // Fix this by passing options and workspace information to the snapshot, 20286- // both of which should be immutable for the snapshot. 20287- view *View 20288- 20289- cancel func() 20290- backgroundCtx context.Context 20291- 20292- store *memoize.Store // cache of handles shared by all snapshots 20293- 20294- refcount sync.WaitGroup // number of references 20295- destroyedBy *string // atomically set to non-nil in Destroy once refcount = 0 20296- 20297- // initialized reports whether the snapshot has been initialized. Concurrent 20298- // initialization is guarded by the view.initializationSema. Each snapshot is 20299- // initialized at most once: concurrent initialization is guarded by 20300- // view.initializationSema. 20301- initialized bool 20302- // initializedErr holds the last error resulting from initialization. If 20303- // initialization fails, we only retry when the the workspace modules change, 20304- // to avoid too many go/packages calls. 20305- initializedErr *source.CriticalError 20306- 20307- // mu guards all of the maps in the snapshot, as well as the builtin URI. 20308- mu sync.Mutex 20309- 20310- // builtin pins the AST and package for builtin.go in memory. 20311- builtin span.URI 20312- 20313- // meta holds loaded metadata. 20314- // 20315- // meta is guarded by mu, but the metadataGraph itself is immutable. 20316- // TODO(rfindley): in many places we hold mu while operating on meta, even 20317- // though we only need to hold mu while reading the pointer. 20318- meta *metadataGraph 20319- 20320- // files maps file URIs to their corresponding FileHandles. 20321- // It may invalidated when a file's content changes. 20322- files filesMap 20323- 20324- // parseCache holds an LRU cache of recently parsed files. 20325- parseCache *parseCache 20326- 20327- // symbolizeHandles maps each file URI to a handle for the future 20328- // result of computing the symbols declared in that file. 20329- symbolizeHandles *persistent.Map // from span.URI to *memoize.Promise[symbolizeResult] 20330- 20331- // packages maps a packageKey to a *packageHandle. 20332- // It may be invalidated when a file's content changes. 20333- // 20334- // Invariants to preserve: 20335- // - packages.Get(id).meta == meta.metadata[id] for all ids 20336- // - if a package is in packages, then all of its dependencies should also 20337- // be in packages, unless there is a missing import 20338- packages *persistent.Map // from packageID to *packageHandle 20339- 20340- // activePackages maps a package ID to a memoized active package, or nil if 20341- // the package is known not to be open. 20342- // 20343- // IDs not contained in the map are not known to be open or not open. 20344- activePackages *persistent.Map // from packageID to *Package 20345- 20346- // analyses maps an analysisKey (which identifies a package 20347- // and a set of analyzers) to the handle for the future result 20348- // of loading the package and analyzing it. 20349- analyses *persistent.Map // from analysisKey to analysisPromise 20350- 20351- // workspacePackages contains the workspace's packages, which are loaded 20352- // when the view is created. 20353- workspacePackages map[PackageID]PackagePath 20354- 20355- // shouldLoad tracks packages that need to be reloaded, mapping a PackageID 20356- // to the package paths that should be used to reload it 20357- // 20358- // When we try to load a package, we clear it from the shouldLoad map 20359- // regardless of whether the load succeeded, to prevent endless loads. 20360- shouldLoad map[PackageID][]PackagePath 20361- 20362- // unloadableFiles keeps track of files that we've failed to load. 20363- unloadableFiles map[span.URI]struct{} 20364- 20365- // TODO(rfindley): rename the handles below to "promises". A promise is 20366- // different from a handle (we mutate the package handle.) 20367- 20368- // parseModHandles keeps track of any parseModHandles for the snapshot. 20369- // The handles need not refer to only the view's go.mod file. 20370- parseModHandles *persistent.Map // from span.URI to *memoize.Promise[parseModResult] 20371- 20372- // parseWorkHandles keeps track of any parseWorkHandles for the snapshot. 20373- // The handles need not refer to only the view's go.work file. 20374- parseWorkHandles *persistent.Map // from span.URI to *memoize.Promise[parseWorkResult] 20375- 20376- // Preserve go.mod-related handles to avoid garbage-collecting the results 20377- // of various calls to the go command. The handles need not refer to only 20378- // the view's go.mod file. 20379- modTidyHandles *persistent.Map // from span.URI to *memoize.Promise[modTidyResult] 20380- modWhyHandles *persistent.Map // from span.URI to *memoize.Promise[modWhyResult] 20381- modVulnHandles *persistent.Map // from span.URI to *memoize.Promise[modVulnResult] 20382- 20383- // knownSubdirs is the set of subdirectories in the workspace, used to 20384- // create glob patterns for file watching. 20385- knownSubdirs knownDirsSet 20386- knownSubdirsPatternCache string 20387- // unprocessedSubdirChanges are any changes that might affect the set of 20388- // subdirectories in the workspace. They are not reflected to knownSubdirs 20389- // during the snapshot cloning step as it can slow down cloning. 20390- unprocessedSubdirChanges []*fileChange 20391- 20392- // workspaceModFiles holds the set of mod files active in this snapshot. 20393- // 20394- // This is either empty, a single entry for the workspace go.mod file, or the 20395- // set of mod files used by the workspace go.work file. 20396- // 20397- // This set is immutable inside the snapshot, and therefore is not guarded by mu. 20398- workspaceModFiles map[span.URI]struct{} 20399- workspaceModFilesErr error // error encountered computing workspaceModFiles 20400-} 20401- 20402-var globalSnapshotID uint64 20403- 20404-func nextSnapshotID() source.GlobalSnapshotID { 20405- return source.GlobalSnapshotID(atomic.AddUint64(&globalSnapshotID, 1)) 20406-} 20407- 20408-var _ memoize.RefCounted = (*snapshot)(nil) // snapshots are reference-counted 20409- 20410-// Acquire prevents the snapshot from being destroyed until the returned function is called. 20411-// 20412-// (s.Acquire().release() could instead be expressed as a pair of 20413-// method calls s.IncRef(); s.DecRef(). The latter has the advantage 20414-// that the DecRefs are fungible and don't require holding anything in 20415-// addition to the refcounted object s, but paradoxically that is also 20416-// an advantage of the current approach, which forces the caller to 20417-// consider the release function at every stage, making a reference 20418-// leak more obvious.) 20419-func (s *snapshot) Acquire() func() { 20420- type uP = unsafe.Pointer 20421- if destroyedBy := atomic.LoadPointer((*uP)(uP(&s.destroyedBy))); destroyedBy != nil { 20422- log.Panicf("%d: acquire() after Destroy(%q)", s.globalID, *(*string)(destroyedBy)) 20423- } 20424- s.refcount.Add(1) 20425- return s.refcount.Done 20426-} 20427- 20428-func (s *snapshot) awaitPromise(ctx context.Context, p *memoize.Promise) (interface{}, error) { 20429- return p.Get(ctx, s) 20430-} 20431- 20432-// destroy waits for all leases on the snapshot to expire then releases 20433-// any resources (reference counts and files) associated with it. 20434-// Snapshots being destroyed can be awaited using v.destroyWG. 20435-// 20436-// TODO(adonovan): move this logic into the release function returned 20437-// by Acquire when the reference count becomes zero. (This would cost 20438-// us the destroyedBy debug info, unless we add it to the signature of 20439-// memoize.RefCounted.Acquire.) 20440-// 20441-// The destroyedBy argument is used for debugging. 20442-// 20443-// v.snapshotMu must be held while calling this function, in order to preserve 20444-// the invariants described by the the docstring for v.snapshot. 20445-func (v *View) destroy(s *snapshot, destroyedBy string) { 20446- v.snapshotWG.Add(1) 20447- go func() { 20448- defer v.snapshotWG.Done() 20449- s.destroy(destroyedBy) 20450- }() 20451-} 20452- 20453-func (s *snapshot) destroy(destroyedBy string) { 20454- // Wait for all leases to end before commencing destruction. 20455- s.refcount.Wait() 20456- 20457- // Report bad state as a debugging aid. 20458- // Not foolproof: another thread could acquire() at this moment. 20459- type uP = unsafe.Pointer // looking forward to generics... 20460- if old := atomic.SwapPointer((*uP)(uP(&s.destroyedBy)), uP(&destroyedBy)); old != nil { 20461- log.Panicf("%d: Destroy(%q) after Destroy(%q)", s.globalID, destroyedBy, *(*string)(old)) 20462- } 20463- 20464- s.packages.Destroy() 20465- s.activePackages.Destroy() 20466- s.analyses.Destroy() 20467- s.files.Destroy() 20468- s.knownSubdirs.Destroy() 20469- s.symbolizeHandles.Destroy() 20470- s.parseModHandles.Destroy() 20471- s.parseWorkHandles.Destroy() 20472- s.modTidyHandles.Destroy() 20473- s.modVulnHandles.Destroy() 20474- s.modWhyHandles.Destroy() 20475-} 20476- 20477-func (s *snapshot) SequenceID() uint64 { 20478- return s.sequenceID 20479-} 20480- 20481-func (s *snapshot) GlobalID() source.GlobalSnapshotID { 20482- return s.globalID 20483-} 20484- 20485-func (s *snapshot) View() source.View { 20486- return s.view 20487-} 20488- 20489-func (s *snapshot) BackgroundContext() context.Context { 20490- return s.backgroundCtx 20491-} 20492- 20493-func (s *snapshot) ModFiles() []span.URI { 20494- var uris []span.URI 20495- for modURI := range s.workspaceModFiles { 20496- uris = append(uris, modURI) 20497- } 20498- return uris 20499-} 20500- 20501-func (s *snapshot) WorkFile() span.URI { 20502- return s.view.effectiveGOWORK() 20503-} 20504- 20505-func (s *snapshot) Templates() map[span.URI]source.FileHandle { 20506- s.mu.Lock() 20507- defer s.mu.Unlock() 20508- 20509- tmpls := map[span.URI]source.FileHandle{} 20510- s.files.Range(func(k span.URI, fh source.FileHandle) { 20511- if s.view.FileKind(fh) == source.Tmpl { 20512- tmpls[k] = fh 20513- } 20514- }) 20515- return tmpls 20516-} 20517- 20518-func (s *snapshot) ValidBuildConfiguration() bool { 20519- // Since we only really understand the `go` command, if the user has a 20520- // different GOPACKAGESDRIVER, assume that their configuration is valid. 20521- if s.view.hasGopackagesDriver { 20522- return true 20523- } 20524- // Check if the user is working within a module or if we have found 20525- // multiple modules in the workspace. 20526- if len(s.workspaceModFiles) > 0 { 20527- return true 20528- } 20529- // The user may have a multiple directories in their GOPATH. 20530- // Check if the workspace is within any of them. 20531- // TODO(rfindley): this should probably be subject to "if GO111MODULES = off {...}". 20532- for _, gp := range filepath.SplitList(s.view.gopath) { 20533- if source.InDir(filepath.Join(gp, "src"), s.view.folder.Filename()) { 20534- return true 20535- } 20536- } 20537- return false 20538-} 20539- 20540-// moduleMode reports whether the current snapshot uses Go modules. 20541-// 20542-// From https://go.dev/ref/mod, module mode is active if either of the 20543-// following hold: 20544-// - GO111MODULE=on 20545-// - GO111MODULE=auto and we are inside a module or have a GOWORK value. 20546-// 20547-// Additionally, this method returns false if GOPACKAGESDRIVER is set. 20548-// 20549-// TODO(rfindley): use this more widely. 20550-func (s *snapshot) moduleMode() bool { 20551- // Since we only really understand the `go` command, if the user has a 20552- // different GOPACKAGESDRIVER, assume that their configuration is valid. 20553- if s.view.hasGopackagesDriver { 20554- return false 20555- } 20556- 20557- switch s.view.effectiveGO111MODULE() { 20558- case on: 20559- return true 20560- case off: 20561- return false 20562- default: 20563- return len(s.workspaceModFiles) > 0 || s.view.gowork != "" 20564- } 20565-} 20566- 20567-// workspaceMode describes the way in which the snapshot's workspace should 20568-// be loaded. 20569-// 20570-// TODO(rfindley): remove this, in favor of specific methods. 20571-func (s *snapshot) workspaceMode() workspaceMode { 20572- var mode workspaceMode 20573- 20574- // If the view has an invalid configuration, don't build the workspace 20575- // module. 20576- validBuildConfiguration := s.ValidBuildConfiguration() 20577- if !validBuildConfiguration { 20578- return mode 20579- } 20580- // If the view is not in a module and contains no modules, but still has a 20581- // valid workspace configuration, do not create the workspace module. 20582- // It could be using GOPATH or a different build system entirely. 20583- if len(s.workspaceModFiles) == 0 && validBuildConfiguration { 20584- return mode 20585- } 20586- mode |= moduleMode 20587- options := s.view.Options() 20588- if options.TempModfile { 20589- mode |= tempModfile 20590- } 20591- return mode 20592-} 20593- 20594-// config returns the configuration used for the snapshot's interaction with 20595-// the go/packages API. It uses the given working directory. 20596-// 20597-// TODO(rstambler): go/packages requires that we do not provide overlays for 20598-// multiple modules in on config, so buildOverlay needs to filter overlays by 20599-// module. 20600-func (s *snapshot) config(ctx context.Context, inv *gocommand.Invocation) *packages.Config { 20601- s.view.optionsMu.Lock() 20602- verboseOutput := s.view.options.VerboseOutput 20603- s.view.optionsMu.Unlock() 20604- 20605- cfg := &packages.Config{ 20606- Context: ctx, 20607- Dir: inv.WorkingDir, 20608- Env: inv.Env, 20609- BuildFlags: inv.BuildFlags, 20610- Mode: packages.NeedName | 20611- packages.NeedFiles | 20612- packages.NeedCompiledGoFiles | 20613- packages.NeedImports | 20614- packages.NeedDeps | 20615- packages.NeedTypesSizes | 20616- packages.NeedModule | 20617- packages.NeedEmbedFiles | 20618- packages.LoadMode(packagesinternal.DepsErrors) | 20619- packages.LoadMode(packagesinternal.ForTest), 20620- Fset: nil, // we do our own parsing 20621- Overlay: s.buildOverlay(), 20622- ParseFile: func(*token.FileSet, string, []byte) (*ast.File, error) { 20623- panic("go/packages must not be used to parse files") 20624- }, 20625- Logf: func(format string, args ...interface{}) { 20626- if verboseOutput { 20627- event.Log(ctx, fmt.Sprintf(format, args...)) 20628- } 20629- }, 20630- Tests: true, 20631- } 20632- packagesinternal.SetModFile(cfg, inv.ModFile) 20633- packagesinternal.SetModFlag(cfg, inv.ModFlag) 20634- // We want to type check cgo code if go/types supports it. 20635- if typesinternal.SetUsesCgo(&types.Config{}) { 20636- cfg.Mode |= packages.LoadMode(packagesinternal.TypecheckCgo) 20637- } 20638- packagesinternal.SetGoCmdRunner(cfg, s.view.gocmdRunner) 20639- return cfg 20640-} 20641- 20642-func (s *snapshot) RunGoCommandDirect(ctx context.Context, mode source.InvocationFlags, inv *gocommand.Invocation) (*bytes.Buffer, error) { 20643- _, inv, cleanup, err := s.goCommandInvocation(ctx, mode, inv) 20644- if err != nil { 20645- return nil, err 20646- } 20647- defer cleanup() 20648- 20649- return s.view.gocmdRunner.Run(ctx, *inv) 20650-} 20651- 20652-func (s *snapshot) RunGoCommandPiped(ctx context.Context, mode source.InvocationFlags, inv *gocommand.Invocation, stdout, stderr io.Writer) error { 20653- _, inv, cleanup, err := s.goCommandInvocation(ctx, mode, inv) 20654- if err != nil { 20655- return err 20656- } 20657- defer cleanup() 20658- return s.view.gocmdRunner.RunPiped(ctx, *inv, stdout, stderr) 20659-} 20660- 20661-func (s *snapshot) RunGoCommands(ctx context.Context, allowNetwork bool, wd string, run func(invoke func(...string) (*bytes.Buffer, error)) error) (bool, []byte, []byte, error) { 20662- var flags source.InvocationFlags 20663- if s.workspaceMode()&tempModfile != 0 { 20664- flags = source.WriteTemporaryModFile 20665- } else { 20666- flags = source.Normal 20667- } 20668- if allowNetwork { 20669- flags |= source.AllowNetwork 20670- } 20671- tmpURI, inv, cleanup, err := s.goCommandInvocation(ctx, flags, &gocommand.Invocation{WorkingDir: wd}) 20672- if err != nil { 20673- return false, nil, nil, err 20674- } 20675- defer cleanup() 20676- invoke := func(args ...string) (*bytes.Buffer, error) { 20677- inv.Verb = args[0] 20678- inv.Args = args[1:] 20679- return s.view.gocmdRunner.Run(ctx, *inv) 20680- } 20681- if err := run(invoke); err != nil { 20682- return false, nil, nil, err 20683- } 20684- if flags.Mode() != source.WriteTemporaryModFile { 20685- return false, nil, nil, nil 20686- } 20687- var modBytes, sumBytes []byte 20688- modBytes, err = ioutil.ReadFile(tmpURI.Filename()) 20689- if err != nil && !os.IsNotExist(err) { 20690- return false, nil, nil, err 20691- } 20692- sumBytes, err = ioutil.ReadFile(strings.TrimSuffix(tmpURI.Filename(), ".mod") + ".sum") 20693- if err != nil && !os.IsNotExist(err) { 20694- return false, nil, nil, err 20695- } 20696- return true, modBytes, sumBytes, nil 20697-} 20698- 20699-// goCommandInvocation populates inv with configuration for running go commands on the snapshot. 20700-// 20701-// TODO(rfindley): refactor this function to compose the required configuration 20702-// explicitly, rather than implicitly deriving it from flags and inv. 20703-// 20704-// TODO(adonovan): simplify cleanup mechanism. It's hard to see, but 20705-// it used only after call to tempModFile. Clarify that it is only 20706-// non-nil on success. 20707-func (s *snapshot) goCommandInvocation(ctx context.Context, flags source.InvocationFlags, inv *gocommand.Invocation) (tmpURI span.URI, updatedInv *gocommand.Invocation, cleanup func(), err error) { 20708- s.view.optionsMu.Lock() 20709- allowModfileModificationOption := s.view.options.AllowModfileModifications 20710- allowNetworkOption := s.view.options.AllowImplicitNetworkAccess 20711- 20712- // TODO(rfindley): this is very hard to follow, and may not even be doing the 20713- // right thing: should inv.Env really trample view.options? Do we ever invoke 20714- // this with a non-empty inv.Env? 20715- // 20716- // We should refactor to make it clearer that the correct env is being used. 20717- inv.Env = append(append(append(os.Environ(), s.view.options.EnvSlice()...), inv.Env...), "GO111MODULE="+s.view.GO111MODULE()) 20718- inv.BuildFlags = append([]string{}, s.view.options.BuildFlags...) 20719- s.view.optionsMu.Unlock() 20720- cleanup = func() {} // fallback 20721- 20722- // All logic below is for module mode. 20723- if s.workspaceMode()&moduleMode == 0 { 20724- return "", inv, cleanup, nil 20725- } 20726- 20727- mode, allowNetwork := flags.Mode(), flags.AllowNetwork() 20728- if !allowNetwork && !allowNetworkOption { 20729- inv.Env = append(inv.Env, "GOPROXY=off") 20730- } 20731- 20732- // What follows is rather complicated logic for how to actually run the go 20733- // command. A word of warning: this is the result of various incremental 20734- // features added to gopls, and varying behavior of the Go command across Go 20735- // versions. It can surely be cleaned up significantly, but tread carefully. 20736- // 20737- // Roughly speaking we need to resolve four things: 20738- // - the working directory. 20739- // - the -mod flag 20740- // - the -modfile flag 20741- // 20742- // These are dependent on a number of factors: whether we need to run in a 20743- // synthetic workspace, whether flags are supported at the current go 20744- // version, and what we're actually trying to achieve (the 20745- // source.InvocationFlags). 20746- 20747- var modURI span.URI 20748- // Select the module context to use. 20749- // If we're type checking, we need to use the workspace context, meaning 20750- // the main (workspace) module. Otherwise, we should use the module for 20751- // the passed-in working dir. 20752- if mode == source.LoadWorkspace { 20753- if s.view.effectiveGOWORK() == "" && s.view.gomod != "" { 20754- modURI = s.view.gomod 20755- } 20756- } else { 20757- modURI = s.GoModForFile(span.URIFromPath(inv.WorkingDir)) 20758- } 20759- 20760- var modContent []byte 20761- if modURI != "" { 20762- modFH, err := s.GetFile(ctx, modURI) 20763- if err != nil { 20764- return "", nil, cleanup, err 20765- } 20766- modContent, err = modFH.Read() 20767- if err != nil { 20768- return "", nil, cleanup, err 20769- } 20770- } 20771- 20772- // TODO(rfindley): in the case of go.work mode, modURI is empty and we fall 20773- // back on the default behavior of vendorEnabled with an empty modURI. Figure 20774- // out what is correct here and implement it explicitly. 20775- vendorEnabled, err := s.vendorEnabled(ctx, modURI, modContent) 20776- if err != nil { 20777- return "", nil, cleanup, err 20778- } 20779- 20780- const mutableModFlag = "mod" 20781- // If the mod flag isn't set, populate it based on the mode and workspace. 20782- // TODO(rfindley): this doesn't make sense if we're not in module mode 20783- if inv.ModFlag == "" { 20784- switch mode { 20785- case source.LoadWorkspace, source.Normal: 20786- if vendorEnabled { 20787- inv.ModFlag = "vendor" 20788- } else if !allowModfileModificationOption { 20789- inv.ModFlag = "readonly" 20790- } else { 20791- inv.ModFlag = mutableModFlag 20792- } 20793- case source.WriteTemporaryModFile: 20794- inv.ModFlag = mutableModFlag 20795- // -mod must be readonly when using go.work files - see issue #48941 20796- inv.Env = append(inv.Env, "GOWORK=off") 20797- } 20798- } 20799- 20800- // Only use a temp mod file if the modfile can actually be mutated. 20801- needTempMod := inv.ModFlag == mutableModFlag 20802- useTempMod := s.workspaceMode()&tempModfile != 0 20803- if needTempMod && !useTempMod { 20804- return "", nil, cleanup, source.ErrTmpModfileUnsupported 20805- } 20806- 20807- // We should use -modfile if: 20808- // - the workspace mode supports it 20809- // - we're using a go.work file on go1.18+, or we need a temp mod file (for 20810- // example, if running go mod tidy in a go.work workspace) 20811- // 20812- // TODO(rfindley): this is very hard to follow. Refactor. 20813- if !needTempMod && s.view.gowork != "" { 20814- // Since we're running in the workspace root, the go command will resolve GOWORK automatically. 20815- } else if useTempMod { 20816- if modURI == "" { 20817- return "", nil, cleanup, fmt.Errorf("no go.mod file found in %s", inv.WorkingDir) 20818- } 20819- modFH, err := s.GetFile(ctx, modURI) 20820- if err != nil { 20821- return "", nil, cleanup, err 20822- } 20823- // Use the go.sum if it happens to be available. 20824- gosum := s.goSum(ctx, modURI) 20825- tmpURI, cleanup, err = tempModFile(modFH, gosum) 20826- if err != nil { 20827- return "", nil, cleanup, err 20828- } 20829- inv.ModFile = tmpURI.Filename() 20830- } 20831- 20832- return tmpURI, inv, cleanup, nil 20833-} 20834- 20835-func (s *snapshot) buildOverlay() map[string][]byte { 20836- s.mu.Lock() 20837- defer s.mu.Unlock() 20838- 20839- overlays := make(map[string][]byte) 20840- s.files.Range(func(uri span.URI, fh source.FileHandle) { 20841- overlay, ok := fh.(*Overlay) 20842- if !ok { 20843- return 20844- } 20845- if overlay.saved { 20846- return 20847- } 20848- // TODO(rstambler): Make sure not to send overlays outside of the current view. 20849- overlays[uri.Filename()] = overlay.content 20850- }) 20851- return overlays 20852-} 20853- 20854-// Package data kinds, identifying various package data that may be stored in 20855-// the file cache. 20856-const ( 20857- xrefsKind = "xrefs" 20858- methodSetsKind = "methodsets" 20859- exportDataKind = "export" 20860- diagnosticsKind = "diagnostics" 20861-) 20862- 20863-func (s *snapshot) PackageDiagnostics(ctx context.Context, ids ...PackageID) (map[span.URI][]*source.Diagnostic, error) { 20864- // TODO(rfindley): opt: avoid unnecessary encode->decode after type-checking. 20865- data, err := s.getPackageData(ctx, diagnosticsKind, ids, func(p *syntaxPackage) []byte { 20866- return encodeDiagnostics(p.diagnostics) 20867- }) 20868- perFile := make(map[span.URI][]*source.Diagnostic) 20869- for _, data := range data { 20870- if data != nil { 20871- for _, diag := range data.m.Diagnostics { 20872- perFile[diag.URI] = append(perFile[diag.URI], diag) 20873- } 20874- diags := decodeDiagnostics(data.data) 20875- for _, diag := range diags { 20876- perFile[diag.URI] = append(perFile[diag.URI], diag) 20877- } 20878- } 20879- } 20880- return perFile, err 20881-} 20882- 20883-func (s *snapshot) References(ctx context.Context, ids ...PackageID) ([]source.XrefIndex, error) { 20884- data, err := s.getPackageData(ctx, xrefsKind, ids, func(p *syntaxPackage) []byte { return p.xrefs }) 20885- indexes := make([]source.XrefIndex, len(ids)) 20886- for i, data := range data { 20887- if data != nil { 20888- indexes[i] = XrefIndex{m: data.m, data: data.data} 20889- } 20890- } 20891- return indexes, err 20892-} 20893- 20894-// An XrefIndex is a helper for looking up a package in a given package. 20895-type XrefIndex struct { 20896- m *source.Metadata 20897- data []byte 20898-} 20899- 20900-func (index XrefIndex) Lookup(targets map[PackagePath]map[objectpath.Path]struct{}) []protocol.Location { 20901- return xrefs.Lookup(index.m, index.data, targets) 20902-} 20903- 20904-func (s *snapshot) MethodSets(ctx context.Context, ids ...PackageID) ([]*methodsets.Index, error) { 20905- // TODO(rfindley): opt: avoid unnecessary encode->decode after type-checking. 20906- data, err := s.getPackageData(ctx, methodSetsKind, ids, func(p *syntaxPackage) []byte { 20907- return p.methodsets.Encode() 20908- }) 20909- indexes := make([]*methodsets.Index, len(ids)) 20910- for i, data := range data { 20911- if data != nil { 20912- indexes[i] = methodsets.Decode(data.data) 20913- } else if ids[i] == "unsafe" { 20914- indexes[i] = &methodsets.Index{} 20915- } else { 20916- panic(fmt.Sprintf("nil data for %s", ids[i])) 20917- } 20918- } 20919- return indexes, err 20920-} 20921- 20922-func (s *snapshot) MetadataForFile(ctx context.Context, uri span.URI) ([]*source.Metadata, error) { 20923- s.mu.Lock() 20924- 20925- // Start with the set of package associations derived from the last load. 20926- ids := s.meta.ids[uri] 20927- 20928- shouldLoad := false // whether any packages containing uri are marked 'shouldLoad' 20929- for _, id := range ids { 20930- if len(s.shouldLoad[id]) > 0 { 20931- shouldLoad = true 20932- } 20933- } 20934- 20935- // Check if uri is known to be unloadable. 20936- _, unloadable := s.unloadableFiles[uri] 20937- 20938- s.mu.Unlock() 20939- 20940- // Reload if loading is likely to improve the package associations for uri: 20941- // - uri is not contained in any valid packages 20942- // - ...or one of the packages containing uri is marked 'shouldLoad' 20943- // - ...but uri is not unloadable 20944- if (shouldLoad || len(ids) == 0) && !unloadable { 20945- scope := fileLoadScope(uri) 20946- err := s.load(ctx, false, scope) 20947- 20948- // Guard against failed loads due to context cancellation. 20949- // 20950- // Return the context error here as the current operation is no longer 20951- // valid. 20952- if ctxErr := ctx.Err(); ctxErr != nil { 20953- return nil, ctxErr 20954- } 20955- 20956- // We must clear scopes after loading. 20957- // 20958- // TODO(rfindley): unlike reloadWorkspace, this is simply marking loaded 20959- // packages as loaded. We could do this from snapshot.load and avoid 20960- // raciness. 20961- s.clearShouldLoad(scope) 20962- 20963- // Don't return an error here, as we may still return stale IDs. 20964- // Furthermore, the result of MetadataForFile should be consistent upon 20965- // subsequent calls, even if the file is marked as unloadable. 20966- if err != nil && !errors.Is(err, errNoPackages) { 20967- event.Error(ctx, "MetadataForFile", err) 20968- } 20969- } 20970- 20971- // Retrieve the metadata. 20972- s.mu.Lock() 20973- defer s.mu.Unlock() 20974- ids = s.meta.ids[uri] 20975- metas := make([]*source.Metadata, len(ids)) 20976- for i, id := range ids { 20977- metas[i] = s.meta.metadata[id] 20978- if metas[i] == nil { 20979- panic("nil metadata") 20980- } 20981- } 20982- // Metadata is only ever added by loading, 20983- // so if we get here and still have 20984- // no IDs, uri is unloadable. 20985- if !unloadable && len(ids) == 0 { 20986- s.unloadableFiles[uri] = struct{}{} 20987- } 20988- 20989- // Sort packages "narrowest" to "widest" (in practice: non-tests before tests). 20990- sort.Slice(metas, func(i, j int) bool { 20991- return len(metas[i].CompiledGoFiles) < len(metas[j].CompiledGoFiles) 20992- }) 20993- 20994- return metas, nil 20995-} 20996- 20997-func (s *snapshot) ReverseDependencies(ctx context.Context, id PackageID, transitive bool) (map[PackageID]*source.Metadata, error) { 20998- if err := s.awaitLoaded(ctx); err != nil { 20999- return nil, err 21000- } 21001- s.mu.Lock() 21002- meta := s.meta 21003- s.mu.Unlock() 21004- 21005- var rdeps map[PackageID]*source.Metadata 21006- if transitive { 21007- rdeps = meta.reverseReflexiveTransitiveClosure(id) 21008- 21009- // Remove the original package ID from the map. 21010- // (Callers all want irreflexivity but it's easier 21011- // to compute reflexively then subtract.) 21012- delete(rdeps, id) 21013- 21014- } else { 21015- // direct reverse dependencies 21016- rdeps = make(map[PackageID]*source.Metadata) 21017- for _, rdepID := range meta.importedBy[id] { 21018- if rdep := meta.metadata[rdepID]; rdep != nil { 21019- rdeps[rdepID] = rdep 21020- } 21021- } 21022- } 21023- 21024- return rdeps, nil 21025-} 21026- 21027-func (s *snapshot) workspaceMetadata() (meta []*source.Metadata) { 21028- s.mu.Lock() 21029- defer s.mu.Unlock() 21030- 21031- for id := range s.workspacePackages { 21032- meta = append(meta, s.meta.metadata[id]) 21033- } 21034- return meta 21035-} 21036- 21037-// -- Active package tracking -- 21038-// 21039-// We say a package is "active" if any of its files are open. After 21040-// type-checking we keep active packages in memory. The activePackages 21041-// peristent map does bookkeeping for the set of active packages. 21042- 21043-// getActivePackage returns a the memoized active package for id, if it exists. 21044-// If id is not active or has not yet been type-checked, it returns nil. 21045-func (s *snapshot) getActivePackage(id PackageID) *Package { 21046- s.mu.Lock() 21047- defer s.mu.Unlock() 21048- 21049- if value, ok := s.activePackages.Get(id); ok { 21050- return value.(*Package) // possibly nil, if we have already checked this id. 21051- } 21052- return nil 21053-} 21054- 21055-// memoizeActivePackage checks if pkg is active, and if so either records it in 21056-// the active packages map or returns the existing memoized active package for id. 21057-// 21058-// The resulting package is non-nil if and only if the specified package is open. 21059-func (s *snapshot) memoizeActivePackage(id PackageID, pkg *Package) (active *Package) { 21060- s.mu.Lock() 21061- defer s.mu.Unlock() 21062- 21063- if value, ok := s.activePackages.Get(id); ok { 21064- return value.(*Package) // possibly nil, if we have already checked this id. 21065- } 21066- 21067- defer func() { 21068- s.activePackages.Set(id, active, nil) // store the result either way: remember that pkg is not open 21069- }() 21070- for _, cgf := range pkg.Metadata().GoFiles { 21071- if s.isOpenLocked(cgf) { 21072- return pkg 21073- } 21074- } 21075- for _, cgf := range pkg.Metadata().CompiledGoFiles { 21076- if s.isOpenLocked(cgf) { 21077- return pkg 21078- } 21079- } 21080- return nil 21081-} 21082- 21083-func (s *snapshot) resetActivePackagesLocked() { 21084- s.activePackages.Destroy() 21085- s.activePackages = persistent.NewMap(packageIDLessInterface) 21086-} 21087- 21088-const fileExtensions = "go,mod,sum,work" 21089- 21090-func (s *snapshot) fileWatchingGlobPatterns(ctx context.Context) map[string]struct{} { 21091- extensions := fileExtensions 21092- for _, ext := range s.View().Options().TemplateExtensions { 21093- extensions += "," + ext 21094- } 21095- // Work-around microsoft/vscode#100870 by making sure that we are, 21096- // at least, watching the user's entire workspace. This will still be 21097- // applied to every folder in the workspace. 21098- patterns := map[string]struct{}{ 21099- fmt.Sprintf("**/*.{%s}", extensions): {}, 21100- } 21101- 21102- // If GOWORK is outside the folder, ensure we are watching it. 21103- gowork := s.view.effectiveGOWORK() 21104- if gowork != "" && !source.InDir(s.view.folder.Filename(), gowork.Filename()) { 21105- patterns[gowork.Filename()] = struct{}{} 21106- } 21107- 21108- // Add a pattern for each Go module in the workspace that is not within the view. 21109- dirs := s.dirs(ctx) 21110- for _, dir := range dirs { 21111- dirName := dir.Filename() 21112- 21113- // If the directory is within the view's folder, we're already watching 21114- // it with the first pattern above. 21115- if source.InDir(s.view.folder.Filename(), dirName) { 21116- continue 21117- } 21118- // TODO(rstambler): If microsoft/vscode#3025 is resolved before 21119- // microsoft/vscode#101042, we will need a work-around for Windows 21120- // drive letter casing. 21121- patterns[fmt.Sprintf("%s/**/*.{%s}", dirName, extensions)] = struct{}{} 21122- } 21123- 21124- // Some clients do not send notifications for changes to directories that 21125- // contain Go code (golang/go#42348). To handle this, explicitly watch all 21126- // of the directories in the workspace. We find them by adding the 21127- // directories of every file in the snapshot's workspace directories. 21128- // There may be thousands. 21129- if pattern := s.getKnownSubdirsPattern(dirs); pattern != "" { 21130- patterns[pattern] = struct{}{} 21131- } 21132- 21133- return patterns 21134-} 21135- 21136-func (s *snapshot) getKnownSubdirsPattern(wsDirs []span.URI) string { 21137- s.mu.Lock() 21138- defer s.mu.Unlock() 21139- 21140- // First, process any pending changes and update the set of known 21141- // subdirectories. 21142- // It may change list of known subdirs and therefore invalidate the cache. 21143- s.applyKnownSubdirsChangesLocked(wsDirs) 21144- 21145- if s.knownSubdirsPatternCache == "" { 21146- var builder strings.Builder 21147- s.knownSubdirs.Range(func(uri span.URI) { 21148- if builder.Len() == 0 { 21149- builder.WriteString("{") 21150- } else { 21151- builder.WriteString(",") 21152- } 21153- builder.WriteString(uri.Filename()) 21154- }) 21155- if builder.Len() > 0 { 21156- builder.WriteString("}") 21157- s.knownSubdirsPatternCache = builder.String() 21158- } 21159- } 21160- 21161- return s.knownSubdirsPatternCache 21162-} 21163- 21164-// collectAllKnownSubdirs collects all of the subdirectories within the 21165-// snapshot's workspace directories. None of the workspace directories are 21166-// included. 21167-func (s *snapshot) collectAllKnownSubdirs(ctx context.Context) { 21168- dirs := s.dirs(ctx) 21169- 21170- s.mu.Lock() 21171- defer s.mu.Unlock() 21172- 21173- s.knownSubdirs.Destroy() 21174- s.knownSubdirs = newKnownDirsSet() 21175- s.knownSubdirsPatternCache = "" 21176- s.files.Range(func(uri span.URI, fh source.FileHandle) { 21177- s.addKnownSubdirLocked(uri, dirs) 21178- }) 21179-} 21180- 21181-func (s *snapshot) getKnownSubdirs(wsDirs []span.URI) knownDirsSet { 21182- s.mu.Lock() 21183- defer s.mu.Unlock() 21184- 21185- // First, process any pending changes and update the set of known 21186- // subdirectories. 21187- s.applyKnownSubdirsChangesLocked(wsDirs) 21188- 21189- return s.knownSubdirs.Clone() 21190-} 21191- 21192-func (s *snapshot) applyKnownSubdirsChangesLocked(wsDirs []span.URI) { 21193- for _, c := range s.unprocessedSubdirChanges { 21194- if c.isUnchanged { 21195- continue 21196- } 21197- if !c.exists { 21198- s.removeKnownSubdirLocked(c.fileHandle.URI()) 21199- } else { 21200- s.addKnownSubdirLocked(c.fileHandle.URI(), wsDirs) 21201- } 21202- } 21203- s.unprocessedSubdirChanges = nil 21204-} 21205- 21206-func (s *snapshot) addKnownSubdirLocked(uri span.URI, dirs []span.URI) { 21207- dir := filepath.Dir(uri.Filename()) 21208- // First check if the directory is already known, because then we can 21209- // return early. 21210- if s.knownSubdirs.Contains(span.URIFromPath(dir)) { 21211- return 21212- } 21213- var matched span.URI 21214- for _, wsDir := range dirs { 21215- if source.InDir(wsDir.Filename(), dir) { 21216- matched = wsDir 21217- break 21218- } 21219- } 21220- // Don't watch any directory outside of the workspace directories. 21221- if matched == "" { 21222- return 21223- } 21224- for { 21225- if dir == "" || dir == matched.Filename() { 21226- break 21227- } 21228- uri := span.URIFromPath(dir) 21229- if s.knownSubdirs.Contains(uri) { 21230- break 21231- } 21232- s.knownSubdirs.Insert(uri) 21233- dir = filepath.Dir(dir) 21234- s.knownSubdirsPatternCache = "" 21235- } 21236-} 21237- 21238-func (s *snapshot) removeKnownSubdirLocked(uri span.URI) { 21239- dir := filepath.Dir(uri.Filename()) 21240- for dir != "" { 21241- uri := span.URIFromPath(dir) 21242- if !s.knownSubdirs.Contains(uri) { 21243- break 21244- } 21245- if info, _ := os.Stat(dir); info == nil { 21246- s.knownSubdirs.Remove(uri) 21247- s.knownSubdirsPatternCache = "" 21248- } 21249- dir = filepath.Dir(dir) 21250- } 21251-} 21252- 21253-// knownFilesInDir returns the files known to the given snapshot that are in 21254-// the given directory. It does not respect symlinks. 21255-func (s *snapshot) knownFilesInDir(ctx context.Context, dir span.URI) []span.URI { 21256- var files []span.URI 21257- s.mu.Lock() 21258- defer s.mu.Unlock() 21259- 21260- s.files.Range(func(uri span.URI, fh source.FileHandle) { 21261- if source.InDir(dir.Filename(), uri.Filename()) { 21262- files = append(files, uri) 21263- } 21264- }) 21265- return files 21266-} 21267- 21268-func (s *snapshot) ActiveMetadata(ctx context.Context) ([]*source.Metadata, error) { 21269- if err := s.awaitLoaded(ctx); err != nil { 21270- return nil, err 21271- } 21272- return s.workspaceMetadata(), nil 21273-} 21274- 21275-// Symbols extracts and returns symbol information for every file contained in 21276-// a loaded package. It awaits snapshot loading. 21277-// 21278-// TODO(rfindley): move this to the top of cache/symbols.go 21279-func (s *snapshot) Symbols(ctx context.Context) (map[span.URI][]source.Symbol, error) { 21280- if err := s.awaitLoaded(ctx); err != nil { 21281- return nil, err 21282- } 21283- 21284- // Build symbols for all loaded Go files. 21285- s.mu.Lock() 21286- meta := s.meta 21287- s.mu.Unlock() 21288- 21289- goFiles := make(map[span.URI]struct{}) 21290- for _, m := range meta.metadata { 21291- for _, uri := range m.GoFiles { 21292- goFiles[uri] = struct{}{} 21293- } 21294- for _, uri := range m.CompiledGoFiles { 21295- goFiles[uri] = struct{}{} 21296- } 21297- } 21298- 21299- // Symbolize them in parallel. 21300- var ( 21301- group errgroup.Group 21302- nprocs = 2 * runtime.GOMAXPROCS(-1) // symbolize is a mix of I/O and CPU 21303- resultMu sync.Mutex 21304- result = make(map[span.URI][]source.Symbol) 21305- ) 21306- group.SetLimit(nprocs) 21307- for uri := range goFiles { 21308- uri := uri 21309- group.Go(func() error { 21310- symbols, err := s.symbolize(ctx, uri) 21311- if err != nil { 21312- return err 21313- } 21314- resultMu.Lock() 21315- result[uri] = symbols 21316- resultMu.Unlock() 21317- return nil 21318- }) 21319- } 21320- // Keep going on errors, but log the first failure. 21321- // Partial results are better than no symbol results. 21322- if err := group.Wait(); err != nil { 21323- event.Error(ctx, "getting snapshot symbols", err) 21324- } 21325- return result, nil 21326-} 21327- 21328-func (s *snapshot) AllMetadata(ctx context.Context) ([]*source.Metadata, error) { 21329- if err := s.awaitLoaded(ctx); err != nil { 21330- return nil, err 21331- } 21332- 21333- s.mu.Lock() 21334- g := s.meta 21335- s.mu.Unlock() 21336- 21337- meta := make([]*source.Metadata, 0, len(g.metadata)) 21338- for _, m := range g.metadata { 21339- meta = append(meta, m) 21340- } 21341- return meta, nil 21342-} 21343- 21344-// TODO(rfindley): clarify that this is only active modules. Or update to just 21345-// use findRootPattern. 21346-func (s *snapshot) GoModForFile(uri span.URI) span.URI { 21347- return moduleForURI(s.workspaceModFiles, uri) 21348-} 21349- 21350-func moduleForURI(modFiles map[span.URI]struct{}, uri span.URI) span.URI { 21351- var match span.URI 21352- for modURI := range modFiles { 21353- if !source.InDir(span.Dir(modURI).Filename(), uri.Filename()) { 21354- continue 21355- } 21356- if len(modURI) > len(match) { 21357- match = modURI 21358- } 21359- } 21360- return match 21361-} 21362- 21363-// nearestModFile finds the nearest go.mod file contained in the directory 21364-// containing uri, or a parent of that directory. 21365-// 21366-// The given uri must be a file, not a directory. 21367-func nearestModFile(ctx context.Context, uri span.URI, fs source.FileSource) (span.URI, error) { 21368- // TODO(rfindley) 21369- dir := filepath.Dir(uri.Filename()) 21370- mod, err := findRootPattern(ctx, dir, "go.mod", fs) 21371- if err != nil { 21372- return "", err 21373- } 21374- return span.URIFromPath(mod), nil 21375-} 21376- 21377-func (s *snapshot) Metadata(id PackageID) *source.Metadata { 21378- s.mu.Lock() 21379- defer s.mu.Unlock() 21380- return s.meta.metadata[id] 21381-} 21382- 21383-// clearShouldLoad clears package IDs that no longer need to be reloaded after 21384-// scopes has been loaded. 21385-func (s *snapshot) clearShouldLoad(scopes ...loadScope) { 21386- s.mu.Lock() 21387- defer s.mu.Unlock() 21388- 21389- for _, scope := range scopes { 21390- switch scope := scope.(type) { 21391- case packageLoadScope: 21392- scopePath := PackagePath(scope) 21393- var toDelete []PackageID 21394- for id, pkgPaths := range s.shouldLoad { 21395- for _, pkgPath := range pkgPaths { 21396- if pkgPath == scopePath { 21397- toDelete = append(toDelete, id) 21398- } 21399- } 21400- } 21401- for _, id := range toDelete { 21402- delete(s.shouldLoad, id) 21403- } 21404- case fileLoadScope: 21405- uri := span.URI(scope) 21406- ids := s.meta.ids[uri] 21407- for _, id := range ids { 21408- delete(s.shouldLoad, id) 21409- } 21410- } 21411- } 21412-} 21413- 21414-// noValidMetadataForURILocked reports whether there is any valid metadata for 21415-// the given URI. 21416-func (s *snapshot) noValidMetadataForURILocked(uri span.URI) bool { 21417- for _, id := range s.meta.ids[uri] { 21418- if _, ok := s.meta.metadata[id]; ok { 21419- return false 21420- } 21421- } 21422- return true 21423-} 21424- 21425-func (s *snapshot) isWorkspacePackage(id PackageID) bool { 21426- s.mu.Lock() 21427- defer s.mu.Unlock() 21428- 21429- _, ok := s.workspacePackages[id] 21430- return ok 21431-} 21432- 21433-func (s *snapshot) FindFile(uri span.URI) source.FileHandle { 21434- s.view.markKnown(uri) 21435- 21436- s.mu.Lock() 21437- defer s.mu.Unlock() 21438- 21439- result, _ := s.files.Get(uri) 21440- return result 21441-} 21442- 21443-// GetFile returns a File for the given URI. If the file is unknown it is added 21444-// to the managed set. 21445-// 21446-// GetFile succeeds even if the file does not exist. A non-nil error return 21447-// indicates some type of internal error, for example if ctx is cancelled. 21448-func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) { 21449- s.mu.Lock() 21450- defer s.mu.Unlock() 21451- 21452- return lockedSnapshot{s}.GetFile(ctx, uri) 21453-} 21454- 21455-// A lockedSnapshot implements the source.FileSource interface while holding 21456-// the lock for the wrapped snapshot. 21457-type lockedSnapshot struct{ wrapped *snapshot } 21458- 21459-func (s lockedSnapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) { 21460- s.wrapped.view.markKnown(uri) 21461- if fh, ok := s.wrapped.files.Get(uri); ok { 21462- return fh, nil 21463- } 21464- 21465- fh, err := s.wrapped.view.fs.GetFile(ctx, uri) // read the file 21466- if err != nil { 21467- return nil, err 21468- } 21469- s.wrapped.files.Set(uri, fh) 21470- return fh, nil 21471-} 21472- 21473-func (s *snapshot) IsOpen(uri span.URI) bool { 21474- s.mu.Lock() 21475- defer s.mu.Unlock() 21476- return s.isOpenLocked(uri) 21477- 21478-} 21479- 21480-func (s *snapshot) openFiles() []source.FileHandle { 21481- s.mu.Lock() 21482- defer s.mu.Unlock() 21483- 21484- var open []source.FileHandle 21485- s.files.Range(func(uri span.URI, fh source.FileHandle) { 21486- if isFileOpen(fh) { 21487- open = append(open, fh) 21488- } 21489- }) 21490- return open 21491-} 21492- 21493-func (s *snapshot) isOpenLocked(uri span.URI) bool { 21494- fh, _ := s.files.Get(uri) 21495- return isFileOpen(fh) 21496-} 21497- 21498-func isFileOpen(fh source.FileHandle) bool { 21499- _, open := fh.(*Overlay) 21500- return open 21501-} 21502- 21503-func (s *snapshot) awaitLoaded(ctx context.Context) error { 21504- loadErr := s.awaitLoadedAllErrors(ctx) 21505- 21506- // TODO(rfindley): eliminate this function as part of simplifying 21507- // CriticalErrors. 21508- if loadErr != nil { 21509- return loadErr.MainError 21510- } 21511- return nil 21512-} 21513- 21514-func (s *snapshot) GetCriticalError(ctx context.Context) *source.CriticalError { 21515- // If we couldn't compute workspace mod files, then the load below is 21516- // invalid. 21517- // 21518- // TODO(rfindley): is this a clear error to present to the user? 21519- if s.workspaceModFilesErr != nil { 21520- return &source.CriticalError{MainError: s.workspaceModFilesErr} 21521- } 21522- 21523- loadErr := s.awaitLoadedAllErrors(ctx) 21524- if loadErr != nil && errors.Is(loadErr.MainError, context.Canceled) { 21525- return nil 21526- } 21527- 21528- // Even if packages didn't fail to load, we still may want to show 21529- // additional warnings. 21530- if loadErr == nil { 21531- active, _ := s.ActiveMetadata(ctx) 21532- if msg := shouldShowAdHocPackagesWarning(s, active); msg != "" { 21533- return &source.CriticalError{ 21534- MainError: errors.New(msg), 21535- } 21536- } 21537- // Even if workspace packages were returned, there still may be an error 21538- // with the user's workspace layout. Workspace packages that only have the 21539- // ID "command-line-arguments" are usually a symptom of a bad workspace 21540- // configuration. 21541- // 21542- // This heuristic is path-dependent: we only get command-line-arguments 21543- // packages when we've loaded using file scopes, which only occurs 21544- // on-demand or via orphaned file reloading. 21545- // 21546- // TODO(rfindley): re-evaluate this heuristic. 21547- if containsCommandLineArguments(active) { 21548- err, diags := s.workspaceLayoutError(ctx) 21549- if err != nil { 21550- if ctx.Err() != nil { 21551- return nil // see the API documentation for source.Snapshot 21552- } 21553- return &source.CriticalError{ 21554- MainError: err, 21555- Diagnostics: diags, 21556- } 21557- } 21558- } 21559- return nil 21560- } 21561- 21562- if errMsg := loadErr.MainError.Error(); strings.Contains(errMsg, "cannot find main module") || strings.Contains(errMsg, "go.mod file not found") { 21563- err, diags := s.workspaceLayoutError(ctx) 21564- if err != nil { 21565- if ctx.Err() != nil { 21566- return nil // see the API documentation for source.Snapshot 21567- } 21568- return &source.CriticalError{ 21569- MainError: err, 21570- Diagnostics: diags, 21571- } 21572- } 21573- } 21574- return loadErr 21575-} 21576- 21577-// A portion of this text is expected by TestBrokenWorkspace_OutsideModule. 21578-const adHocPackagesWarning = `You are outside of a module and outside of $GOPATH/src. 21579-If you are using modules, please open your editor to a directory in your module. 21580-If you believe this warning is incorrect, please file an issue: https://github.com/golang/go/issues/new.` 21581- 21582-func shouldShowAdHocPackagesWarning(snapshot source.Snapshot, active []*source.Metadata) string { 21583- if !snapshot.ValidBuildConfiguration() { 21584- for _, m := range active { 21585- // A blank entry in DepsByImpPath 21586- // indicates a missing dependency. 21587- for _, importID := range m.DepsByImpPath { 21588- if importID == "" { 21589- return adHocPackagesWarning 21590- } 21591- } 21592- } 21593- } 21594- return "" 21595-} 21596- 21597-func containsCommandLineArguments(metas []*source.Metadata) bool { 21598- for _, m := range metas { 21599- if source.IsCommandLineArguments(m.ID) { 21600- return true 21601- } 21602- } 21603- return false 21604-} 21605- 21606-func (s *snapshot) awaitLoadedAllErrors(ctx context.Context) *source.CriticalError { 21607- // Do not return results until the snapshot's view has been initialized. 21608- s.AwaitInitialized(ctx) 21609- 21610- // TODO(rfindley): Should we be more careful about returning the 21611- // initialization error? Is it possible for the initialization error to be 21612- // corrected without a successful reinitialization? 21613- if err := s.getInitializationError(); err != nil { 21614- return err 21615- } 21616- 21617- // TODO(rfindley): revisit this handling. Calling reloadWorkspace with a 21618- // cancelled context should have the same effect, so this preemptive handling 21619- // should not be necessary. 21620- // 21621- // Also: GetCriticalError ignores context cancellation errors. Should we be 21622- // returning nil here? 21623- if ctx.Err() != nil { 21624- return &source.CriticalError{MainError: ctx.Err()} 21625- } 21626- 21627- // TODO(rfindley): reloading is not idempotent: if we try to reload or load 21628- // orphaned files below and fail, we won't try again. For that reason, we 21629- // could get different results from subsequent calls to this function, which 21630- // may cause critical errors to be suppressed. 21631- 21632- if err := s.reloadWorkspace(ctx); err != nil { 21633- diags := s.extractGoCommandErrors(ctx, err) 21634- return &source.CriticalError{ 21635- MainError: err, 21636- Diagnostics: diags, 21637- } 21638- } 21639- 21640- if err := s.reloadOrphanedOpenFiles(ctx); err != nil { 21641- diags := s.extractGoCommandErrors(ctx, err) 21642- return &source.CriticalError{ 21643- MainError: err, 21644- Diagnostics: diags, 21645- } 21646- } 21647- return nil 21648-} 21649- 21650-func (s *snapshot) getInitializationError() *source.CriticalError { 21651- s.mu.Lock() 21652- defer s.mu.Unlock() 21653- 21654- return s.initializedErr 21655-} 21656- 21657-func (s *snapshot) AwaitInitialized(ctx context.Context) { 21658- select { 21659- case <-ctx.Done(): 21660- return 21661- case <-s.view.initialWorkspaceLoad: 21662- } 21663- // We typically prefer to run something as intensive as the IWL without 21664- // blocking. I'm not sure if there is a way to do that here. 21665- s.initialize(ctx, false) 21666-} 21667- 21668-// reloadWorkspace reloads the metadata for all invalidated workspace packages. 21669-func (s *snapshot) reloadWorkspace(ctx context.Context) error { 21670- var scopes []loadScope 21671- var seen map[PackagePath]bool 21672- s.mu.Lock() 21673- for _, pkgPaths := range s.shouldLoad { 21674- for _, pkgPath := range pkgPaths { 21675- if seen == nil { 21676- seen = make(map[PackagePath]bool) 21677- } 21678- if seen[pkgPath] { 21679- continue 21680- } 21681- seen[pkgPath] = true 21682- scopes = append(scopes, packageLoadScope(pkgPath)) 21683- } 21684- } 21685- s.mu.Unlock() 21686- 21687- if len(scopes) == 0 { 21688- return nil 21689- } 21690- 21691- // If the view's build configuration is invalid, we cannot reload by 21692- // package path. Just reload the directory instead. 21693- if !s.ValidBuildConfiguration() { 21694- scopes = []loadScope{viewLoadScope("LOAD_INVALID_VIEW")} 21695- } 21696- 21697- err := s.load(ctx, false, scopes...) 21698- 21699- // Unless the context was canceled, set "shouldLoad" to false for all 21700- // of the metadata we attempted to load. 21701- if !errors.Is(err, context.Canceled) { 21702- s.clearShouldLoad(scopes...) 21703- } 21704- 21705- return err 21706-} 21707- 21708-func (s *snapshot) reloadOrphanedOpenFiles(ctx context.Context) error { 21709- // When we load ./... or a package path directly, we may not get packages 21710- // that exist only in overlays. As a workaround, we search all of the files 21711- // available in the snapshot and reload their metadata individually using a 21712- // file= query if the metadata is unavailable. 21713- files := s.orphanedOpenFiles() 21714- 21715- // Files without a valid package declaration can't be loaded. Don't try. 21716- var scopes []loadScope 21717- for _, file := range files { 21718- pgf, err := s.ParseGo(ctx, file, source.ParseHeader) 21719- if err != nil { 21720- continue 21721- } 21722- if !pgf.File.Package.IsValid() { 21723- continue 21724- } 21725- 21726- scopes = append(scopes, fileLoadScope(file.URI())) 21727- } 21728- 21729- if len(scopes) == 0 { 21730- return nil 21731- } 21732- 21733- // The regtests match this exact log message, keep them in sync. 21734- event.Log(ctx, "reloadOrphanedFiles reloading", tag.Query.Of(scopes)) 21735- err := s.load(ctx, false, scopes...) 21736- 21737- // If we failed to load some files, i.e. they have no metadata, 21738- // mark the failures so we don't bother retrying until the file's 21739- // content changes. 21740- // 21741- // TODO(rstambler): This may be an overestimate if the load stopped 21742- // early for an unrelated errors. Add a fallback? 21743- // 21744- // Check for context cancellation so that we don't incorrectly mark files 21745- // as unloadable, but don't return before setting all workspace packages. 21746- if ctx.Err() == nil && err != nil { 21747- event.Error(ctx, "reloadOrphanedFiles: failed to load", err, tag.Query.Of(scopes)) 21748- s.mu.Lock() 21749- for _, scope := range scopes { 21750- uri := span.URI(scope.(fileLoadScope)) 21751- if s.noValidMetadataForURILocked(uri) { 21752- s.unloadableFiles[uri] = struct{}{} 21753- } 21754- } 21755- s.mu.Unlock() 21756- } 21757- return nil 21758-} 21759- 21760-func (s *snapshot) orphanedOpenFiles() []source.FileHandle { 21761- s.mu.Lock() 21762- defer s.mu.Unlock() 21763- 21764- var files []source.FileHandle 21765- s.files.Range(func(uri span.URI, fh source.FileHandle) { 21766- // Only consider open files, which will be represented as overlays. 21767- if _, isOverlay := fh.(*Overlay); !isOverlay { 21768- return 21769- } 21770- // Don't try to reload metadata for go.mod files. 21771- if s.view.FileKind(fh) != source.Go { 21772- return 21773- } 21774- // If the URI doesn't belong to this view, then it's not in a workspace 21775- // package and should not be reloaded directly. 21776- if !source.InDir(s.view.folder.Filename(), uri.Filename()) { 21777- return 21778- } 21779- // Don't reload metadata for files we've already deemed unloadable. 21780- if _, ok := s.unloadableFiles[uri]; ok { 21781- return 21782- } 21783- if s.noValidMetadataForURILocked(uri) { 21784- files = append(files, fh) 21785- } 21786- }) 21787- return files 21788-} 21789- 21790-// TODO(golang/go#53756): this function needs to consider more than just the 21791-// absolute URI, for example: 21792-// - the position of /vendor/ with respect to the relevant module root 21793-// - whether or not go.work is in use (as vendoring isn't supported in workspace mode) 21794-// 21795-// Most likely, each call site of inVendor needs to be reconsidered to 21796-// understand and correctly implement the desired behavior. 21797-func inVendor(uri span.URI) bool { 21798- _, after, found := cut(string(uri), "/vendor/") 21799- // Only subdirectories of /vendor/ are considered vendored 21800- // (/vendor/a/foo.go is vendored, /vendor/foo.go is not). 21801- return found && strings.Contains(after, "/") 21802-} 21803- 21804-// TODO(adonovan): replace with strings.Cut when we can assume go1.18. 21805-func cut(s, sep string) (before, after string, found bool) { 21806- if i := strings.Index(s, sep); i >= 0 { 21807- return s[:i], s[i+len(sep):], true 21808- } 21809- return s, "", false 21810-} 21811- 21812-// unappliedChanges is a file source that handles an uncloned snapshot. 21813-type unappliedChanges struct { 21814- originalSnapshot *snapshot 21815- changes map[span.URI]*fileChange 21816-} 21817- 21818-func (ac *unappliedChanges) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) { 21819- if c, ok := ac.changes[uri]; ok { 21820- return c.fileHandle, nil 21821- } 21822- return ac.originalSnapshot.GetFile(ctx, uri) 21823-} 21824- 21825-func (s *snapshot) clone(ctx, bgCtx context.Context, changes map[span.URI]*fileChange, forceReloadMetadata bool) (*snapshot, func()) { 21826- ctx, done := event.Start(ctx, "snapshot.clone") 21827- defer done() 21828- 21829- reinit := false 21830- wsModFiles, wsModFilesErr := s.workspaceModFiles, s.workspaceModFilesErr 21831- 21832- if workURI := s.view.effectiveGOWORK(); workURI != "" { 21833- if change, ok := changes[workURI]; ok { 21834- wsModFiles, wsModFilesErr = computeWorkspaceModFiles(ctx, s.view.gomod, workURI, s.view.effectiveGO111MODULE(), &unappliedChanges{ 21835- originalSnapshot: s, 21836- changes: changes, 21837- }) 21838- // TODO(rfindley): don't rely on 'isUnchanged' here. Use a content hash instead. 21839- reinit = change.fileHandle.Saved() && !change.isUnchanged 21840- } 21841- } 21842- 21843- // Reinitialize if any workspace mod file has changed on disk. 21844- for uri, change := range changes { 21845- if _, ok := wsModFiles[uri]; ok && change.fileHandle.Saved() && !change.isUnchanged { 21846- reinit = true 21847- } 21848- } 21849- 21850- // Finally, process sumfile changes that may affect loading. 21851- for uri, change := range changes { 21852- if !change.fileHandle.Saved() { 21853- continue // like with go.mod files, we only reinit when things are saved 21854- } 21855- if filepath.Base(uri.Filename()) == "go.work.sum" && s.view.gowork != "" { 21856- if filepath.Dir(uri.Filename()) == filepath.Dir(s.view.gowork) { 21857- reinit = true 21858- } 21859- } 21860- if filepath.Base(uri.Filename()) == "go.sum" { 21861- dir := filepath.Dir(uri.Filename()) 21862- modURI := span.URIFromPath(filepath.Join(dir, "go.mod")) 21863- if _, active := wsModFiles[modURI]; active { 21864- reinit = true 21865- } 21866- } 21867- } 21868- 21869- s.mu.Lock() 21870- defer s.mu.Unlock() 21871- 21872- // Changes to vendor tree may require reinitialization, 21873- // either because of an initialization error 21874- // (e.g. "inconsistent vendoring detected"), or because 21875- // one or more modules may have moved into or out of the 21876- // vendor tree after 'go mod vendor' or 'rm -fr vendor/'. 21877- for uri := range changes { 21878- if inVendor(uri) && s.initializedErr != nil || 21879- strings.HasSuffix(string(uri), "/vendor/modules.txt") { 21880- reinit = true 21881- break 21882- } 21883- } 21884- 21885- bgCtx, cancel := context.WithCancel(bgCtx) 21886- result := &snapshot{ 21887- sequenceID: s.sequenceID + 1, 21888- globalID: nextSnapshotID(), 21889- store: s.store, 21890- view: s.view, 21891- backgroundCtx: bgCtx, 21892- cancel: cancel, 21893- builtin: s.builtin, 21894- initialized: s.initialized, 21895- initializedErr: s.initializedErr, 21896- packages: s.packages.Clone(), 21897- activePackages: s.activePackages.Clone(), 21898- analyses: s.analyses.Clone(), 21899- files: s.files.Clone(), 21900- parseCache: s.parseCache, 21901- symbolizeHandles: s.symbolizeHandles.Clone(), 21902- workspacePackages: make(map[PackageID]PackagePath, len(s.workspacePackages)), 21903- unloadableFiles: make(map[span.URI]struct{}, len(s.unloadableFiles)), 21904- parseModHandles: s.parseModHandles.Clone(), 21905- parseWorkHandles: s.parseWorkHandles.Clone(), 21906- modTidyHandles: s.modTidyHandles.Clone(), 21907- modWhyHandles: s.modWhyHandles.Clone(), 21908- modVulnHandles: s.modVulnHandles.Clone(), 21909- knownSubdirs: s.knownSubdirs.Clone(), 21910- workspaceModFiles: wsModFiles, 21911- workspaceModFilesErr: wsModFilesErr, 21912- } 21913- 21914- // The snapshot should be initialized if either s was uninitialized, or we've 21915- // detected a change that triggers reinitialization. 21916- if reinit { 21917- result.initialized = false 21918- } 21919- 21920- // Create a lease on the new snapshot. 21921- // (Best to do this early in case the code below hides an 21922- // incref/decref operation that might destroy it prematurely.) 21923- release := result.Acquire() 21924- 21925- // Copy the set of unloadable files. 21926- // 21927- // TODO(rfindley): this looks wrong. Shouldn't we clear unloadableFiles on 21928- // changes to environment or workspace layout, or more generally on any 21929- // metadata change? 21930- // 21931- // Maybe not, as major configuration changes cause a new view. 21932- for k, v := range s.unloadableFiles { 21933- result.unloadableFiles[k] = v 21934- } 21935- 21936- // Add all of the known subdirectories, but don't update them for the 21937- // changed files. We need to rebuild the workspace module to know the 21938- // true set of known subdirectories, but we don't want to do that in clone. 21939- result.knownSubdirs = s.knownSubdirs.Clone() 21940- result.knownSubdirsPatternCache = s.knownSubdirsPatternCache 21941- for _, c := range changes { 21942- result.unprocessedSubdirChanges = append(result.unprocessedSubdirChanges, c) 21943- } 21944- 21945- // directIDs keeps track of package IDs that have directly changed. 21946- // Note: this is not a set, it's a map from id to invalidateMetadata. 21947- directIDs := map[PackageID]bool{} 21948- 21949- // Invalidate all package metadata if the workspace module has changed. 21950- if reinit { 21951- for k := range s.meta.metadata { 21952- directIDs[k] = true 21953- } 21954- } 21955- 21956- // Compute invalidations based on file changes. 21957- anyImportDeleted := false // import deletions can resolve cycles 21958- anyFileOpenedOrClosed := false // opened files affect workspace packages 21959- anyFileAdded := false // adding a file can resolve missing dependencies 21960- 21961- for uri, change := range changes { 21962- // Invalidate go.mod-related handles. 21963- result.modTidyHandles.Delete(uri) 21964- result.modWhyHandles.Delete(uri) 21965- result.modVulnHandles.Delete(uri) 21966- 21967- // Invalidate handles for cached symbols. 21968- result.symbolizeHandles.Delete(uri) 21969- 21970- // The original FileHandle for this URI is cached on the snapshot. 21971- originalFH, _ := s.files.Get(uri) 21972- var originalOpen, newOpen bool 21973- _, originalOpen = originalFH.(*Overlay) 21974- _, newOpen = change.fileHandle.(*Overlay) 21975- anyFileOpenedOrClosed = anyFileOpenedOrClosed || (originalOpen != newOpen) 21976- anyFileAdded = anyFileAdded || (originalFH == nil && change.fileHandle != nil) 21977- 21978- // If uri is a Go file, check if it has changed in a way that would 21979- // invalidate metadata. Note that we can't use s.view.FileKind here, 21980- // because the file type that matters is not what the *client* tells us, 21981- // but what the Go command sees. 21982- var invalidateMetadata, pkgFileChanged, importDeleted bool 21983- if strings.HasSuffix(uri.Filename(), ".go") { 21984- invalidateMetadata, pkgFileChanged, importDeleted = metadataChanges(ctx, s, originalFH, change.fileHandle) 21985- } 21986- 21987- invalidateMetadata = invalidateMetadata || forceReloadMetadata || reinit 21988- anyImportDeleted = anyImportDeleted || importDeleted 21989- 21990- // Mark all of the package IDs containing the given file. 21991- filePackageIDs := invalidatedPackageIDs(uri, s.meta.ids, pkgFileChanged) 21992- for id := range filePackageIDs { 21993- directIDs[id] = directIDs[id] || invalidateMetadata // may insert 'false' 21994- } 21995- 21996- // Invalidate the previous modTidyHandle if any of the files have been 21997- // saved or if any of the metadata has been invalidated. 21998- if invalidateMetadata || fileWasSaved(originalFH, change.fileHandle) { 21999- // TODO(maybe): Only delete mod handles for 22000- // which the withoutURI is relevant. 22001- // Requires reverse-engineering the go command. (!) 22002- result.modTidyHandles.Clear() 22003- result.modWhyHandles.Clear() 22004- result.modVulnHandles.Clear() 22005- } 22006- 22007- result.parseModHandles.Delete(uri) 22008- result.parseWorkHandles.Delete(uri) 22009- // Handle the invalidated file; it may have new contents or not exist. 22010- if !change.exists { 22011- result.files.Delete(uri) 22012- } else { 22013- result.files.Set(uri, change.fileHandle) 22014- } 22015- 22016- // Make sure to remove the changed file from the unloadable set. 22017- delete(result.unloadableFiles, uri) 22018- } 22019- 22020- // Deleting an import can cause list errors due to import cycles to be 22021- // resolved. The best we can do without parsing the list error message is to 22022- // hope that list errors may have been resolved by a deleted import. 22023- // 22024- // We could do better by parsing the list error message. We already do this 22025- // to assign a better range to the list error, but for such critical 22026- // functionality as metadata, it's better to be conservative until it proves 22027- // impractical. 22028- // 22029- // We could also do better by looking at which imports were deleted and 22030- // trying to find cycles they are involved in. This fails when the file goes 22031- // from an unparseable state to a parseable state, as we don't have a 22032- // starting point to compare with. 22033- if anyImportDeleted { 22034- for id, metadata := range s.meta.metadata { 22035- if len(metadata.Errors) > 0 { 22036- directIDs[id] = true 22037- } 22038- } 22039- } 22040- 22041- // Adding a file can resolve missing dependencies from existing packages. 22042- // 22043- // We could be smart here and try to guess which packages may have been 22044- // fixed, but until that proves necessary, just invalidate metadata for any 22045- // package with missing dependencies. 22046- if anyFileAdded { 22047- for id, metadata := range s.meta.metadata { 22048- for _, impID := range metadata.DepsByImpPath { 22049- if impID == "" { // missing import 22050- directIDs[id] = true 22051- break 22052- } 22053- } 22054- } 22055- } 22056- 22057- // Invalidate reverse dependencies too. 22058- // idsToInvalidate keeps track of transitive reverse dependencies. 22059- // If an ID is present in the map, invalidate its types. 22060- // If an ID's value is true, invalidate its metadata too. 22061- idsToInvalidate := map[PackageID]bool{} 22062- var addRevDeps func(PackageID, bool) 22063- addRevDeps = func(id PackageID, invalidateMetadata bool) { 22064- current, seen := idsToInvalidate[id] 22065- newInvalidateMetadata := current || invalidateMetadata 22066- 22067- // If we've already seen this ID, and the value of invalidate 22068- // metadata has not changed, we can return early. 22069- if seen && current == newInvalidateMetadata { 22070- return 22071- } 22072- idsToInvalidate[id] = newInvalidateMetadata 22073- for _, rid := range s.meta.importedBy[id] { 22074- addRevDeps(rid, invalidateMetadata) 22075- } 22076- } 22077- for id, invalidateMetadata := range directIDs { 22078- addRevDeps(id, invalidateMetadata) 22079- } 22080- 22081- // Delete invalidated package type information. 22082- for id := range idsToInvalidate { 22083- result.packages.Delete(id) 22084- result.activePackages.Delete(id) 22085- } 22086- 22087- // Delete invalidated analysis actions. 22088- var actionsToDelete []analysisKey 22089- result.analyses.Range(func(k, _ interface{}) { 22090- key := k.(analysisKey) 22091- if _, ok := idsToInvalidate[key.pkgid]; ok { 22092- actionsToDelete = append(actionsToDelete, key) 22093- } 22094- }) 22095- for _, key := range actionsToDelete { 22096- result.analyses.Delete(key) 22097- } 22098- 22099- // If a file has been deleted, we must delete metadata for all packages 22100- // containing that file. 22101- // 22102- // TODO(rfindley): why not keep invalid metadata in this case? If we 22103- // otherwise allow operate on invalid metadata, why not continue to do so, 22104- // skipping the missing file? 22105- skipID := map[PackageID]bool{} 22106- for _, c := range changes { 22107- if c.exists { 22108- continue 22109- } 22110- // The file has been deleted. 22111- if ids, ok := s.meta.ids[c.fileHandle.URI()]; ok { 22112- for _, id := range ids { 22113- skipID[id] = true 22114- } 22115- } 22116- } 22117- 22118- // Any packages that need loading in s still need loading in the new 22119- // snapshot. 22120- for k, v := range s.shouldLoad { 22121- if result.shouldLoad == nil { 22122- result.shouldLoad = make(map[PackageID][]PackagePath) 22123- } 22124- result.shouldLoad[k] = v 22125- } 22126- 22127- // Compute which metadata updates are required. We only need to invalidate 22128- // packages directly containing the affected file, and only if it changed in 22129- // a relevant way. 22130- metadataUpdates := make(map[PackageID]*source.Metadata) 22131- for k, v := range s.meta.metadata { 22132- invalidateMetadata := idsToInvalidate[k] 22133- 22134- // For metadata that has been newly invalidated, capture package paths 22135- // requiring reloading in the shouldLoad map. 22136- if invalidateMetadata && !source.IsCommandLineArguments(v.ID) { 22137- if result.shouldLoad == nil { 22138- result.shouldLoad = make(map[PackageID][]PackagePath) 22139- } 22140- needsReload := []PackagePath{v.PkgPath} 22141- if v.ForTest != "" && v.ForTest != v.PkgPath { 22142- // When reloading test variants, always reload their ForTest package as 22143- // well. Otherwise, we may miss test variants in the resulting load. 22144- // 22145- // TODO(rfindley): is this actually sufficient? Is it possible that 22146- // other test variants may be invalidated? Either way, we should 22147- // determine exactly what needs to be reloaded here. 22148- needsReload = append(needsReload, v.ForTest) 22149- } 22150- result.shouldLoad[k] = needsReload 22151- } 22152- 22153- // Check whether the metadata should be deleted. 22154- if skipID[k] || invalidateMetadata { 22155- metadataUpdates[k] = nil 22156- continue 22157- } 22158- } 22159- 22160- // Update metadata, if necessary. 22161- result.meta = s.meta.Clone(metadataUpdates) 22162- 22163- // Update workspace and active packages, if necessary. 22164- if result.meta != s.meta || anyFileOpenedOrClosed { 22165- result.workspacePackages = computeWorkspacePackagesLocked(result, result.meta) 22166- result.resetActivePackagesLocked() 22167- } else { 22168- result.workspacePackages = s.workspacePackages 22169- } 22170- 22171- // Don't bother copying the importedBy graph, 22172- // as it changes each time we update metadata. 22173- 22174- // TODO(rfindley): consolidate the this workspace mode detection with 22175- // workspace invalidation. 22176- workspaceModeChanged := s.workspaceMode() != result.workspaceMode() 22177- 22178- // If the snapshot's workspace mode has changed, the packages loaded using 22179- // the previous mode are no longer relevant, so clear them out. 22180- if workspaceModeChanged { 22181- result.workspacePackages = map[PackageID]PackagePath{} 22182- } 22183- result.dumpWorkspace("clone") 22184- return result, release 22185-} 22186- 22187-// invalidatedPackageIDs returns all packages invalidated by a change to uri. 22188-// If we haven't seen this URI before, we guess based on files in the same 22189-// directory. This is of course incorrect in build systems where packages are 22190-// not organized by directory. 22191-// 22192-// If packageFileChanged is set, the file is either a new file, or has a new 22193-// package name. In this case, all known packages in the directory will be 22194-// invalidated. 22195-func invalidatedPackageIDs(uri span.URI, known map[span.URI][]PackageID, packageFileChanged bool) map[PackageID]struct{} { 22196- invalidated := make(map[PackageID]struct{}) 22197- 22198- // At a minimum, we invalidate packages known to contain uri. 22199- for _, id := range known[uri] { 22200- invalidated[id] = struct{}{} 22201- } 22202- 22203- // If the file didn't move to a new package, we should only invalidate the 22204- // packages it is currently contained inside. 22205- if !packageFileChanged && len(invalidated) > 0 { 22206- return invalidated 22207- } 22208- 22209- // This is a file we don't yet know about, or which has moved packages. Guess 22210- // relevant packages by considering files in the same directory. 22211- 22212- // Cache of FileInfo to avoid unnecessary stats for multiple files in the 22213- // same directory. 22214- stats := make(map[string]struct { 22215- os.FileInfo 22216- error 22217- }) 22218- getInfo := func(dir string) (os.FileInfo, error) { 22219- if res, ok := stats[dir]; ok { 22220- return res.FileInfo, res.error 22221- } 22222- fi, err := os.Stat(dir) 22223- stats[dir] = struct { 22224- os.FileInfo 22225- error 22226- }{fi, err} 22227- return fi, err 22228- } 22229- dir := filepath.Dir(uri.Filename()) 22230- fi, err := getInfo(dir) 22231- if err == nil { 22232- // Aggregate all possibly relevant package IDs. 22233- for knownURI, ids := range known { 22234- knownDir := filepath.Dir(knownURI.Filename()) 22235- knownFI, err := getInfo(knownDir) 22236- if err != nil { 22237- continue 22238- } 22239- if os.SameFile(fi, knownFI) { 22240- for _, id := range ids { 22241- invalidated[id] = struct{}{} 22242- } 22243- } 22244- } 22245- } 22246- return invalidated 22247-} 22248- 22249-// fileWasSaved reports whether the FileHandle passed in has been saved. It 22250-// accomplishes this by checking to see if the original and current FileHandles 22251-// are both overlays, and if the current FileHandle is saved while the original 22252-// FileHandle was not saved. 22253-func fileWasSaved(originalFH, currentFH source.FileHandle) bool { 22254- c, ok := currentFH.(*Overlay) 22255- if !ok || c == nil { 22256- return true 22257- } 22258- o, ok := originalFH.(*Overlay) 22259- if !ok || o == nil { 22260- return c.saved 22261- } 22262- return !o.saved && c.saved 22263-} 22264- 22265-// metadataChanges detects features of the change from oldFH->newFH that may 22266-// affect package metadata. 22267-// 22268-// It uses lockedSnapshot to access cached parse information. lockedSnapshot 22269-// must be locked. 22270-// 22271-// The result parameters have the following meaning: 22272-// - invalidate means that package metadata for packages containing the file 22273-// should be invalidated. 22274-// - pkgFileChanged means that the file->package associates for the file have 22275-// changed (possibly because the file is new, or because its package name has 22276-// changed). 22277-// - importDeleted means that an import has been deleted, or we can't 22278-// determine if an import was deleted due to errors. 22279-func metadataChanges(ctx context.Context, lockedSnapshot *snapshot, oldFH, newFH source.FileHandle) (invalidate, pkgFileChanged, importDeleted bool) { 22280- if oldFH == nil || newFH == nil { // existential changes 22281- changed := (oldFH == nil) != (newFH == nil) 22282- return changed, changed, (newFH == nil) // we don't know if an import was deleted 22283- } 22284- 22285- // If the file hasn't changed, there's no need to reload. 22286- if oldFH.FileIdentity() == newFH.FileIdentity() { 22287- return false, false, false 22288- } 22289- 22290- // Parse headers to compare package names and imports. 22291- oldHeads, _, oldErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseHeader, oldFH) 22292- newHeads, _, newErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseHeader, newFH) 22293- 22294- if oldErr != nil || newErr != nil { 22295- // TODO(rfindley): we can get here if newFH does not exist. There is 22296- // asymmetry, in that newFH may be non-nil even if the underlying file does 22297- // not exist. 22298- // 22299- // We should not produce a non-nil filehandle for a file that does not exist. 22300- errChanged := (oldErr == nil) != (newErr == nil) 22301- return errChanged, errChanged, (newErr != nil) // we don't know if an import was deleted 22302- } 22303- 22304- oldHead := oldHeads[0] 22305- newHead := newHeads[0] 22306- 22307- // `go list` fails completely if the file header cannot be parsed. If we go 22308- // from a non-parsing state to a parsing state, we should reload. 22309- if oldHead.ParseErr != nil && newHead.ParseErr == nil { 22310- return true, true, true // We don't know what changed, so fall back on full invalidation. 22311- } 22312- 22313- // If a package name has changed, the set of package imports may have changed 22314- // in ways we can't detect here. Assume an import has been deleted. 22315- if oldHead.File.Name.Name != newHead.File.Name.Name { 22316- return true, true, true 22317- } 22318- 22319- // Check whether package imports have changed. Only consider potentially 22320- // valid imports paths. 22321- oldImports := validImports(oldHead.File.Imports) 22322- newImports := validImports(newHead.File.Imports) 22323- 22324- for path := range newImports { 22325- if _, ok := oldImports[path]; ok { 22326- delete(oldImports, path) 22327- } else { 22328- invalidate = true // a new, potentially valid import was added 22329- } 22330- } 22331- 22332- if len(oldImports) > 0 { 22333- invalidate = true 22334- importDeleted = true 22335- } 22336- 22337- // If the change does not otherwise invalidate metadata, get the full ASTs in 22338- // order to check magic comments. 22339- // 22340- // Note: if this affects performance we can probably avoid parsing in the 22341- // common case by first scanning the source for potential comments. 22342- if !invalidate { 22343- origFulls, _, oldErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseFull, oldFH) 22344- newFulls, _, newErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseFull, newFH) 22345- if oldErr == nil && newErr == nil { 22346- invalidate = magicCommentsChanged(origFulls[0].File, newFulls[0].File) 22347- } else { 22348- // At this point, we shouldn't ever fail to produce a ParsedGoFile, as 22349- // we're already past header parsing. 22350- bug.Reportf("metadataChanges: unparseable file %v (old error: %v, new error: %v)", oldFH.URI(), oldErr, newErr) 22351- } 22352- } 22353- 22354- return invalidate, pkgFileChanged, importDeleted 22355-} 22356- 22357-func magicCommentsChanged(original *ast.File, current *ast.File) bool { 22358- oldComments := extractMagicComments(original) 22359- newComments := extractMagicComments(current) 22360- if len(oldComments) != len(newComments) { 22361- return true 22362- } 22363- for i := range oldComments { 22364- if oldComments[i] != newComments[i] { 22365- return true 22366- } 22367- } 22368- return false 22369-} 22370- 22371-// validImports extracts the set of valid import paths from imports. 22372-func validImports(imports []*ast.ImportSpec) map[string]struct{} { 22373- m := make(map[string]struct{}) 22374- for _, spec := range imports { 22375- if path := spec.Path.Value; validImportPath(path) { 22376- m[path] = struct{}{} 22377- } 22378- } 22379- return m 22380-} 22381- 22382-func validImportPath(path string) bool { 22383- path, err := strconv.Unquote(path) 22384- if err != nil { 22385- return false 22386- } 22387- if path == "" { 22388- return false 22389- } 22390- if path[len(path)-1] == '/' { 22391- return false 22392- } 22393- return true 22394-} 22395- 22396-var buildConstraintOrEmbedRe = regexp.MustCompile(`^//(go:embed|go:build|\s*\+build).*`) 22397- 22398-// extractMagicComments finds magic comments that affect metadata in f. 22399-func extractMagicComments(f *ast.File) []string { 22400- var results []string 22401- for _, cg := range f.Comments { 22402- for _, c := range cg.List { 22403- if buildConstraintOrEmbedRe.MatchString(c.Text) { 22404- results = append(results, c.Text) 22405- } 22406- } 22407- } 22408- return results 22409-} 22410- 22411-func (s *snapshot) BuiltinFile(ctx context.Context) (*source.ParsedGoFile, error) { 22412- s.AwaitInitialized(ctx) 22413- 22414- s.mu.Lock() 22415- builtin := s.builtin 22416- s.mu.Unlock() 22417- 22418- if builtin == "" { 22419- return nil, fmt.Errorf("no builtin package for view %s", s.view.name) 22420- } 22421- 22422- fh, err := s.GetFile(ctx, builtin) 22423- if err != nil { 22424- return nil, err 22425- } 22426- return s.ParseGo(ctx, fh, source.ParseFull) 22427-} 22428- 22429-func (s *snapshot) IsBuiltin(ctx context.Context, uri span.URI) bool { 22430- s.mu.Lock() 22431- defer s.mu.Unlock() 22432- // We should always get the builtin URI in a canonical form, so use simple 22433- // string comparison here. span.CompareURI is too expensive. 22434- return uri == s.builtin 22435-} 22436- 22437-func (s *snapshot) setBuiltin(path string) { 22438- s.mu.Lock() 22439- defer s.mu.Unlock() 22440- 22441- s.builtin = span.URIFromPath(path) 22442-} 22443diff -urN a/gopls/internal/lsp/cache/standalone_go115.go b/gopls/internal/lsp/cache/standalone_go115.go 22444--- a/gopls/internal/lsp/cache/standalone_go115.go 2000-01-01 00:00:00.000000000 -0000 22445+++ b/gopls/internal/lsp/cache/standalone_go115.go 1970-01-01 00:00:00.000000000 +0000 22446@@ -1,14 +0,0 @@ 22447-// Copyright 2022 The Go Authors. All rights reserved. 22448-// Use of this source code is governed by a BSD-style 22449-// license that can be found in the LICENSE file. 22450- 22451-//go:build !go1.16 22452-// +build !go1.16 22453- 22454-package cache 22455- 22456-// isStandaloneFile returns false, as the 'standaloneTags' setting is 22457-// unsupported on Go 1.15 and earlier. 22458-func isStandaloneFile(src []byte, standaloneTags []string) bool { 22459- return false 22460-} 22461diff -urN a/gopls/internal/lsp/cache/standalone_go116.go b/gopls/internal/lsp/cache/standalone_go116.go 22462--- a/gopls/internal/lsp/cache/standalone_go116.go 2000-01-01 00:00:00.000000000 -0000 22463+++ b/gopls/internal/lsp/cache/standalone_go116.go 1970-01-01 00:00:00.000000000 +0000 22464@@ -1,50 +0,0 @@ 22465-// Copyright 2022 The Go Authors. All rights reserved. 22466-// Use of this source code is governed by a BSD-style 22467-// license that can be found in the LICENSE file. 22468- 22469-//go:build go1.16 22470-// +build go1.16 22471- 22472-package cache 22473- 22474-import ( 22475- "go/build/constraint" 22476- "go/parser" 22477- "go/token" 22478-) 22479- 22480-// isStandaloneFile reports whether a file with the given contents should be 22481-// considered a 'standalone main file', meaning a package that consists of only 22482-// a single file. 22483-func isStandaloneFile(src []byte, standaloneTags []string) bool { 22484- f, err := parser.ParseFile(token.NewFileSet(), "", src, parser.PackageClauseOnly|parser.ParseComments) 22485- if err != nil { 22486- return false 22487- } 22488- 22489- if f.Name == nil || f.Name.Name != "main" { 22490- return false 22491- } 22492- 22493- for _, cg := range f.Comments { 22494- // Even with PackageClauseOnly the parser consumes the semicolon following 22495- // the package clause, so we must guard against comments that come after 22496- // the package name. 22497- if cg.Pos() > f.Name.Pos() { 22498- continue 22499- } 22500- for _, comment := range cg.List { 22501- if c, err := constraint.Parse(comment.Text); err == nil { 22502- if tag, ok := c.(*constraint.TagExpr); ok { 22503- for _, t := range standaloneTags { 22504- if t == tag.Tag { 22505- return true 22506- } 22507- } 22508- } 22509- } 22510- } 22511- } 22512- 22513- return false 22514-} 22515diff -urN a/gopls/internal/lsp/cache/standalone_go116_test.go b/gopls/internal/lsp/cache/standalone_go116_test.go 22516--- a/gopls/internal/lsp/cache/standalone_go116_test.go 2000-01-01 00:00:00.000000000 -0000 22517+++ b/gopls/internal/lsp/cache/standalone_go116_test.go 1970-01-01 00:00:00.000000000 +0000 22518@@ -1,96 +0,0 @@ 22519-// Copyright 2022 The Go Authors. All rights reserved. 22520-// Use of this source code is governed by a BSD-style 22521-// license that can be found in the LICENSE file. 22522- 22523-//go:build go1.16 22524-// +build go1.16 22525- 22526-package cache 22527- 22528-import ( 22529- "testing" 22530-) 22531- 22532-func TestIsStandaloneFile(t *testing.T) { 22533- tests := []struct { 22534- desc string 22535- contents string 22536- standaloneTags []string 22537- want bool 22538- }{ 22539- { 22540- "new syntax", 22541- "//go:build ignore\n\npackage main\n", 22542- []string{"ignore"}, 22543- true, 22544- }, 22545- { 22546- "legacy syntax", 22547- "// +build ignore\n\npackage main\n", 22548- []string{"ignore"}, 22549- true, 22550- }, 22551- { 22552- "multiple tags", 22553- "//go:build ignore\n\npackage main\n", 22554- []string{"exclude", "ignore"}, 22555- true, 22556- }, 22557- { 22558- "invalid tag", 22559- "// +build ignore\n\npackage main\n", 22560- []string{"script"}, 22561- false, 22562- }, 22563- { 22564- "non-main package", 22565- "//go:build ignore\n\npackage p\n", 22566- []string{"ignore"}, 22567- false, 22568- }, 22569- { 22570- "alternate tag", 22571- "// +build script\n\npackage main\n", 22572- []string{"script"}, 22573- true, 22574- }, 22575- { 22576- "both syntax", 22577- "//go:build ignore\n// +build ignore\n\npackage main\n", 22578- []string{"ignore"}, 22579- true, 22580- }, 22581- { 22582- "after comments", 22583- "// A non-directive comment\n//go:build ignore\n\npackage main\n", 22584- []string{"ignore"}, 22585- true, 22586- }, 22587- { 22588- "after package decl", 22589- "package main //go:build ignore\n", 22590- []string{"ignore"}, 22591- false, 22592- }, 22593- { 22594- "on line after package decl", 22595- "package main\n\n//go:build ignore\n", 22596- []string{"ignore"}, 22597- false, 22598- }, 22599- { 22600- "combined with other expressions", 22601- "\n\n//go:build ignore || darwin\n\npackage main\n", 22602- []string{"ignore"}, 22603- false, 22604- }, 22605- } 22606- 22607- for _, test := range tests { 22608- t.Run(test.desc, func(t *testing.T) { 22609- if got := isStandaloneFile([]byte(test.contents), test.standaloneTags); got != test.want { 22610- t.Errorf("isStandaloneFile(%q, %v) = %t, want %t", test.contents, test.standaloneTags, got, test.want) 22611- } 22612- }) 22613- } 22614-} 22615diff -urN a/gopls/internal/lsp/cache/symbols.go b/gopls/internal/lsp/cache/symbols.go 22616--- a/gopls/internal/lsp/cache/symbols.go 2000-01-01 00:00:00.000000000 -0000 22617+++ b/gopls/internal/lsp/cache/symbols.go 1970-01-01 00:00:00.000000000 +0000 22618@@ -1,213 +0,0 @@ 22619-// Copyright 2021 The Go Authors. All rights reserved. 22620-// Use of this source code is governed by a BSD-style 22621-// license that can be found in the LICENSE file. 22622- 22623-package cache 22624- 22625-import ( 22626- "context" 22627- "go/ast" 22628- "go/token" 22629- "go/types" 22630- "strings" 22631- 22632- "golang.org/x/tools/gopls/internal/lsp/protocol" 22633- "golang.org/x/tools/gopls/internal/lsp/source" 22634- "golang.org/x/tools/gopls/internal/span" 22635- "golang.org/x/tools/internal/memoize" 22636-) 22637- 22638-// symbolize returns the result of symbolizing the file identified by uri, using a cache. 22639-func (s *snapshot) symbolize(ctx context.Context, uri span.URI) ([]source.Symbol, error) { 22640- 22641- s.mu.Lock() 22642- entry, hit := s.symbolizeHandles.Get(uri) 22643- s.mu.Unlock() 22644- 22645- type symbolizeResult struct { 22646- symbols []source.Symbol 22647- err error 22648- } 22649- 22650- // Cache miss? 22651- if !hit { 22652- fh, err := s.GetFile(ctx, uri) 22653- if err != nil { 22654- return nil, err 22655- } 22656- type symbolHandleKey source.Hash 22657- key := symbolHandleKey(fh.FileIdentity().Hash) 22658- promise, release := s.store.Promise(key, func(ctx context.Context, arg interface{}) interface{} { 22659- symbols, err := symbolizeImpl(ctx, arg.(*snapshot), fh) 22660- return symbolizeResult{symbols, err} 22661- }) 22662- 22663- entry = promise 22664- 22665- s.mu.Lock() 22666- s.symbolizeHandles.Set(uri, entry, func(_, _ interface{}) { release() }) 22667- s.mu.Unlock() 22668- } 22669- 22670- // Await result. 22671- v, err := s.awaitPromise(ctx, entry.(*memoize.Promise)) 22672- if err != nil { 22673- return nil, err 22674- } 22675- res := v.(symbolizeResult) 22676- return res.symbols, res.err 22677-} 22678- 22679-// symbolizeImpl reads and parses a file and extracts symbols from it. 22680-// It may use a parsed file already present in the cache but 22681-// otherwise does not populate the cache. 22682-func symbolizeImpl(ctx context.Context, snapshot *snapshot, fh source.FileHandle) ([]source.Symbol, error) { 22683- pgfs, _, err := snapshot.parseCache.parseFiles(ctx, source.ParseFull, fh) 22684- if err != nil { 22685- return nil, err 22686- } 22687- 22688- w := &symbolWalker{ 22689- tokFile: pgfs[0].Tok, 22690- mapper: pgfs[0].Mapper, 22691- } 22692- w.fileDecls(pgfs[0].File.Decls) 22693- 22694- return w.symbols, w.firstError 22695-} 22696- 22697-type symbolWalker struct { 22698- // for computing positions 22699- tokFile *token.File 22700- mapper *protocol.Mapper 22701- 22702- symbols []source.Symbol 22703- firstError error 22704-} 22705- 22706-func (w *symbolWalker) atNode(node ast.Node, name string, kind protocol.SymbolKind, path ...*ast.Ident) { 22707- var b strings.Builder 22708- for _, ident := range path { 22709- if ident != nil { 22710- b.WriteString(ident.Name) 22711- b.WriteString(".") 22712- } 22713- } 22714- b.WriteString(name) 22715- 22716- rng, err := w.mapper.NodeRange(w.tokFile, node) 22717- if err != nil { 22718- w.error(err) 22719- return 22720- } 22721- sym := source.Symbol{ 22722- Name: b.String(), 22723- Kind: kind, 22724- Range: rng, 22725- } 22726- w.symbols = append(w.symbols, sym) 22727-} 22728- 22729-func (w *symbolWalker) error(err error) { 22730- if err != nil && w.firstError == nil { 22731- w.firstError = err 22732- } 22733-} 22734- 22735-func (w *symbolWalker) fileDecls(decls []ast.Decl) { 22736- for _, decl := range decls { 22737- switch decl := decl.(type) { 22738- case *ast.FuncDecl: 22739- kind := protocol.Function 22740- var recv *ast.Ident 22741- if decl.Recv.NumFields() > 0 { 22742- kind = protocol.Method 22743- recv = unpackRecv(decl.Recv.List[0].Type) 22744- } 22745- w.atNode(decl.Name, decl.Name.Name, kind, recv) 22746- case *ast.GenDecl: 22747- for _, spec := range decl.Specs { 22748- switch spec := spec.(type) { 22749- case *ast.TypeSpec: 22750- kind := guessKind(spec) 22751- w.atNode(spec.Name, spec.Name.Name, kind) 22752- w.walkType(spec.Type, spec.Name) 22753- case *ast.ValueSpec: 22754- for _, name := range spec.Names { 22755- kind := protocol.Variable 22756- if decl.Tok == token.CONST { 22757- kind = protocol.Constant 22758- } 22759- w.atNode(name, name.Name, kind) 22760- } 22761- } 22762- } 22763- } 22764- } 22765-} 22766- 22767-func guessKind(spec *ast.TypeSpec) protocol.SymbolKind { 22768- switch spec.Type.(type) { 22769- case *ast.InterfaceType: 22770- return protocol.Interface 22771- case *ast.StructType: 22772- return protocol.Struct 22773- case *ast.FuncType: 22774- return protocol.Function 22775- } 22776- return protocol.Class 22777-} 22778- 22779-func unpackRecv(rtyp ast.Expr) *ast.Ident { 22780- // Extract the receiver identifier. Lifted from go/types/resolver.go 22781-L: 22782- for { 22783- switch t := rtyp.(type) { 22784- case *ast.ParenExpr: 22785- rtyp = t.X 22786- case *ast.StarExpr: 22787- rtyp = t.X 22788- default: 22789- break L 22790- } 22791- } 22792- if name, _ := rtyp.(*ast.Ident); name != nil { 22793- return name 22794- } 22795- return nil 22796-} 22797- 22798-// walkType processes symbols related to a type expression. path is path of 22799-// nested type identifiers to the type expression. 22800-func (w *symbolWalker) walkType(typ ast.Expr, path ...*ast.Ident) { 22801- switch st := typ.(type) { 22802- case *ast.StructType: 22803- for _, field := range st.Fields.List { 22804- w.walkField(field, protocol.Field, protocol.Field, path...) 22805- } 22806- case *ast.InterfaceType: 22807- for _, field := range st.Methods.List { 22808- w.walkField(field, protocol.Interface, protocol.Method, path...) 22809- } 22810- } 22811-} 22812- 22813-// walkField processes symbols related to the struct field or interface method. 22814-// 22815-// unnamedKind and namedKind are the symbol kinds if the field is resp. unnamed 22816-// or named. path is the path of nested identifiers containing the field. 22817-func (w *symbolWalker) walkField(field *ast.Field, unnamedKind, namedKind protocol.SymbolKind, path ...*ast.Ident) { 22818- if len(field.Names) == 0 { 22819- switch typ := field.Type.(type) { 22820- case *ast.SelectorExpr: 22821- // embedded qualified type 22822- w.atNode(field, typ.Sel.Name, unnamedKind, path...) 22823- default: 22824- w.atNode(field, types.ExprString(field.Type), unnamedKind, path...) 22825- } 22826- } 22827- for _, name := range field.Names { 22828- w.atNode(name, name.Name, namedKind, path...) 22829- w.walkType(field.Type, append(path, name)...) 22830- } 22831-} 22832diff -urN a/gopls/internal/lsp/cache/view.go b/gopls/internal/lsp/cache/view.go 22833--- a/gopls/internal/lsp/cache/view.go 2000-01-01 00:00:00.000000000 -0000 22834+++ b/gopls/internal/lsp/cache/view.go 1970-01-01 00:00:00.000000000 +0000 22835@@ -1,1142 +0,0 @@ 22836-// Copyright 2018 The Go Authors. All rights reserved. 22837-// Use of this source code is governed by a BSD-style 22838-// license that can be found in the LICENSE file. 22839- 22840-// Package cache implements the caching layer for gopls. 22841-package cache 22842- 22843-import ( 22844- "bytes" 22845- "context" 22846- "encoding/json" 22847- "errors" 22848- "fmt" 22849- "io/ioutil" 22850- "os" 22851- "path" 22852- "path/filepath" 22853- "reflect" 22854- "regexp" 22855- "sort" 22856- "strings" 22857- "sync" 22858- "time" 22859- 22860- "golang.org/x/mod/modfile" 22861- "golang.org/x/mod/semver" 22862- exec "golang.org/x/sys/execabs" 22863- "golang.org/x/tools/gopls/internal/govulncheck" 22864- "golang.org/x/tools/gopls/internal/lsp/protocol" 22865- "golang.org/x/tools/gopls/internal/lsp/source" 22866- "golang.org/x/tools/gopls/internal/span" 22867- "golang.org/x/tools/internal/event" 22868- "golang.org/x/tools/internal/gocommand" 22869- "golang.org/x/tools/internal/imports" 22870- "golang.org/x/tools/internal/xcontext" 22871-) 22872- 22873-type View struct { 22874- id string 22875- 22876- gocmdRunner *gocommand.Runner // limits go command concurrency 22877- 22878- // baseCtx is the context handed to NewView. This is the parent of all 22879- // background contexts created for this view. 22880- baseCtx context.Context 22881- 22882- // name is the user-specified name of this view. 22883- name string 22884- 22885- optionsMu sync.Mutex 22886- options *source.Options 22887- 22888- // Workspace information. The fields below are immutable, and together with 22889- // options define the build list. Any change to these fields results in a new 22890- // View. 22891- folder span.URI // user-specified workspace folder 22892- workspaceInformation // Go environment information 22893- 22894- importsState *importsState 22895- 22896- // moduleUpgrades tracks known upgrades for module paths in each modfile. 22897- // Each modfile has a map of module name to upgrade version. 22898- moduleUpgradesMu sync.Mutex 22899- moduleUpgrades map[span.URI]map[string]string 22900- 22901- // vulns maps each go.mod file's URI to its known vulnerabilities. 22902- vulnsMu sync.Mutex 22903- vulns map[span.URI]*govulncheck.Result 22904- 22905- // fs is the file source used to populate this view. 22906- fs source.FileSource 22907- 22908- // seenFiles tracks files that the view has accessed. 22909- // TODO(golang/go#57558): this notion is fundamentally problematic, and 22910- // should be removed. 22911- knownFilesMu sync.Mutex 22912- knownFiles map[span.URI]bool 22913- 22914- // initCancelFirstAttempt can be used to terminate the view's first 22915- // attempt at initialization. 22916- initCancelFirstAttempt context.CancelFunc 22917- 22918- // Track the latest snapshot via the snapshot field, guarded by snapshotMu. 22919- // 22920- // Invariant: whenever the snapshot field is overwritten, destroy(snapshot) 22921- // is called on the previous (overwritten) snapshot while snapshotMu is held, 22922- // incrementing snapshotWG. During shutdown the final snapshot is 22923- // overwritten with nil and destroyed, guaranteeing that all observed 22924- // snapshots have been destroyed via the destroy method, and snapshotWG may 22925- // be waited upon to let these destroy operations complete. 22926- snapshotMu sync.Mutex 22927- snapshot *snapshot // latest snapshot; nil after shutdown has been called 22928- releaseSnapshot func() // called when snapshot is no longer needed 22929- snapshotWG sync.WaitGroup // refcount for pending destroy operations 22930- 22931- // initialWorkspaceLoad is closed when the first workspace initialization has 22932- // completed. If we failed to load, we only retry if the go.mod file changes, 22933- // to avoid too many go/packages calls. 22934- initialWorkspaceLoad chan struct{} 22935- 22936- // initializationSema is used limit concurrent initialization of snapshots in 22937- // the view. We use a channel instead of a mutex to avoid blocking when a 22938- // context is canceled. 22939- // 22940- // This field (along with snapshot.initialized) guards against duplicate 22941- // initialization of snapshots. Do not change it without adjusting snapshot 22942- // accordingly. 22943- initializationSema chan struct{} 22944-} 22945- 22946-// workspaceInformation holds the defining features of the View workspace. 22947-// 22948-// This type is compared to see if the View needs to be reconstructed. 22949-type workspaceInformation struct { 22950- // `go env` variables that need to be tracked by gopls. 22951- goEnv 22952- 22953- // gomod holds the relevant go.mod file for this workspace. 22954- gomod span.URI 22955- 22956- // The Go version in use: X in Go 1.X. 22957- goversion int 22958- 22959- // The complete output of the go version command. 22960- // (Call gocommand.ParseGoVersionOutput to extract a version 22961- // substring such as go1.19.1 or go1.20-rc.1, go1.21-abcdef01.) 22962- goversionOutput string 22963- 22964- // hasGopackagesDriver is true if the user has a value set for the 22965- // GOPACKAGESDRIVER environment variable or a gopackagesdriver binary on 22966- // their machine. 22967- hasGopackagesDriver bool 22968-} 22969- 22970-// effectiveGO111MODULE reports the value of GO111MODULE effective in the go 22971-// command at this go version, assuming at least Go 1.16. 22972-func (w workspaceInformation) effectiveGO111MODULE() go111module { 22973- switch w.GO111MODULE() { 22974- case "off": 22975- return off 22976- case "on", "": 22977- return on 22978- default: 22979- return auto 22980- } 22981-} 22982- 22983-// effectiveGOWORK returns the effective GOWORK value for this workspace, if 22984-// any, in URI form. 22985-func (w workspaceInformation) effectiveGOWORK() span.URI { 22986- if w.gowork == "off" || w.gowork == "" { 22987- return "" 22988- } 22989- return span.URIFromPath(w.gowork) 22990-} 22991- 22992-// GO111MODULE returns the value of GO111MODULE to use for running the go 22993-// command. It differs from the user's environment in order to allow for the 22994-// more forgiving default value "auto" when using recent go versions. 22995-// 22996-// TODO(rfindley): it is probably not worthwhile diverging from the go command 22997-// here. The extra forgiveness may be nice, but breaks the invariant that 22998-// running the go command from the command line produces the same build list. 22999-// 23000-// Put differently: we shouldn't go out of our way to make GOPATH work, when 23001-// the go command does not. 23002-func (w workspaceInformation) GO111MODULE() string { 23003- if w.go111module == "" { 23004- return "auto" 23005- } 23006- return w.go111module 23007-} 23008- 23009-type go111module int 23010- 23011-const ( 23012- off = go111module(iota) 23013- auto 23014- on 23015-) 23016- 23017-// goEnv holds important environment variables that gopls cares about. 23018-type goEnv struct { 23019- gocache, gopath, goroot, goprivate, gomodcache, gowork, goflags string 23020- 23021- // go111module holds the value of GO111MODULE as reported by go env. 23022- // 23023- // Don't use this value directly, because we choose to use a different 23024- // default (auto) on Go 1.16 and later, to avoid spurious errors. Use 23025- // the effectiveGO111MODULE method instead. 23026- go111module string 23027-} 23028- 23029-// loadGoEnv loads `go env` values into the receiver, using the provided user 23030-// environment and go command runner. 23031-func (env *goEnv) load(ctx context.Context, folder string, configEnv []string, runner *gocommand.Runner) error { 23032- vars := env.vars() 23033- 23034- // We can save ~200 ms by requesting only the variables we care about. 23035- args := []string{"-json"} 23036- for k := range vars { 23037- args = append(args, k) 23038- } 23039- 23040- inv := gocommand.Invocation{ 23041- Verb: "env", 23042- Args: args, 23043- Env: configEnv, 23044- WorkingDir: folder, 23045- } 23046- stdout, err := runner.Run(ctx, inv) 23047- if err != nil { 23048- return err 23049- } 23050- envMap := make(map[string]string) 23051- if err := json.Unmarshal(stdout.Bytes(), &envMap); err != nil { 23052- return fmt.Errorf("internal error unmarshaling JSON from 'go env': %w", err) 23053- } 23054- for key, ptr := range vars { 23055- *ptr = envMap[key] 23056- } 23057- 23058- return nil 23059-} 23060- 23061-func (env goEnv) String() string { 23062- var vars []string 23063- for govar, ptr := range env.vars() { 23064- vars = append(vars, fmt.Sprintf("%s=%s", govar, *ptr)) 23065- } 23066- sort.Strings(vars) 23067- return "[" + strings.Join(vars, ", ") + "]" 23068-} 23069- 23070-// vars returns a map from Go environment variable to field value containing it. 23071-func (env *goEnv) vars() map[string]*string { 23072- return map[string]*string{ 23073- "GOCACHE": &env.gocache, 23074- "GOPATH": &env.gopath, 23075- "GOROOT": &env.goroot, 23076- "GOPRIVATE": &env.goprivate, 23077- "GOMODCACHE": &env.gomodcache, 23078- "GO111MODULE": &env.go111module, 23079- "GOWORK": &env.gowork, 23080- "GOFLAGS": &env.goflags, 23081- } 23082-} 23083- 23084-// workspaceMode holds various flags defining how the gopls workspace should 23085-// behave. They may be derived from the environment, user configuration, or 23086-// depend on the Go version. 23087-// 23088-// TODO(rfindley): remove workspace mode, in favor of explicit checks. 23089-type workspaceMode int 23090- 23091-const ( 23092- moduleMode workspaceMode = 1 << iota 23093- 23094- // tempModfile indicates whether or not the -modfile flag should be used. 23095- tempModfile 23096-) 23097- 23098-func (v *View) ID() string { return v.id } 23099- 23100-// tempModFile creates a temporary go.mod file based on the contents 23101-// of the given go.mod file. On success, it is the caller's 23102-// responsibility to call the cleanup function when the file is no 23103-// longer needed. 23104-func tempModFile(modFh source.FileHandle, gosum []byte) (tmpURI span.URI, cleanup func(), err error) { 23105- filenameHash := source.Hashf("%s", modFh.URI().Filename()) 23106- tmpMod, err := ioutil.TempFile("", fmt.Sprintf("go.%s.*.mod", filenameHash)) 23107- if err != nil { 23108- return "", nil, err 23109- } 23110- defer tmpMod.Close() 23111- 23112- tmpURI = span.URIFromPath(tmpMod.Name()) 23113- tmpSumName := sumFilename(tmpURI) 23114- 23115- content, err := modFh.Read() 23116- if err != nil { 23117- return "", nil, err 23118- } 23119- 23120- if _, err := tmpMod.Write(content); err != nil { 23121- return "", nil, err 23122- } 23123- 23124- // We use a distinct name here to avoid subtlety around the fact 23125- // that both 'return' and 'defer' update the "cleanup" variable. 23126- doCleanup := func() { 23127- _ = os.Remove(tmpSumName) 23128- _ = os.Remove(tmpURI.Filename()) 23129- } 23130- 23131- // Be careful to clean up if we return an error from this function. 23132- defer func() { 23133- if err != nil { 23134- doCleanup() 23135- cleanup = nil 23136- } 23137- }() 23138- 23139- // Create an analogous go.sum, if one exists. 23140- if gosum != nil { 23141- if err := ioutil.WriteFile(tmpSumName, gosum, 0655); err != nil { 23142- return "", nil, err 23143- } 23144- } 23145- 23146- return tmpURI, doCleanup, nil 23147-} 23148- 23149-// Name returns the user visible name of this view. 23150-func (v *View) Name() string { 23151- return v.name 23152-} 23153- 23154-// Folder returns the folder at the base of this view. 23155-func (v *View) Folder() span.URI { 23156- return v.folder 23157-} 23158- 23159-func (v *View) Options() *source.Options { 23160- v.optionsMu.Lock() 23161- defer v.optionsMu.Unlock() 23162- return v.options 23163-} 23164- 23165-func (v *View) FileKind(fh source.FileHandle) source.FileKind { 23166- // The kind of an unsaved buffer comes from the 23167- // TextDocumentItem.LanguageID field in the didChange event, 23168- // not from the file name. They may differ. 23169- if o, ok := fh.(*Overlay); ok { 23170- if o.kind != source.UnknownKind { 23171- return o.kind 23172- } 23173- } 23174- 23175- fext := filepath.Ext(fh.URI().Filename()) 23176- switch fext { 23177- case ".go": 23178- return source.Go 23179- case ".mod": 23180- return source.Mod 23181- case ".sum": 23182- return source.Sum 23183- case ".work": 23184- return source.Work 23185- } 23186- exts := v.Options().TemplateExtensions 23187- for _, ext := range exts { 23188- if fext == ext || fext == "."+ext { 23189- return source.Tmpl 23190- } 23191- } 23192- // and now what? This should never happen, but it does for cgo before go1.15 23193- return source.Go 23194-} 23195- 23196-func minorOptionsChange(a, b *source.Options) bool { 23197- // Check if any of the settings that modify our understanding of files have 23198- // been changed. 23199- if !reflect.DeepEqual(a.Env, b.Env) { 23200- return false 23201- } 23202- if !reflect.DeepEqual(a.DirectoryFilters, b.DirectoryFilters) { 23203- return false 23204- } 23205- if !reflect.DeepEqual(a.StandaloneTags, b.StandaloneTags) { 23206- return false 23207- } 23208- if a.ExpandWorkspaceToModule != b.ExpandWorkspaceToModule { 23209- return false 23210- } 23211- if a.MemoryMode != b.MemoryMode { 23212- return false 23213- } 23214- aBuildFlags := make([]string, len(a.BuildFlags)) 23215- bBuildFlags := make([]string, len(b.BuildFlags)) 23216- copy(aBuildFlags, a.BuildFlags) 23217- copy(bBuildFlags, b.BuildFlags) 23218- sort.Strings(aBuildFlags) 23219- sort.Strings(bBuildFlags) 23220- // the rest of the options are benign 23221- return reflect.DeepEqual(aBuildFlags, bBuildFlags) 23222-} 23223- 23224-// SetViewOptions sets the options of the given view to new values. Calling 23225-// this may cause the view to be invalidated and a replacement view added to 23226-// the session. If so the new view will be returned, otherwise the original one 23227-// will be returned. 23228-func (s *Session) SetViewOptions(ctx context.Context, v *View, options *source.Options) (*View, error) { 23229- // no need to rebuild the view if the options were not materially changed 23230- v.optionsMu.Lock() 23231- if minorOptionsChange(v.options, options) { 23232- v.options = options 23233- v.optionsMu.Unlock() 23234- return v, nil 23235- } 23236- v.optionsMu.Unlock() 23237- newView, err := s.updateView(ctx, v, options) 23238- return newView, err 23239-} 23240- 23241-// viewEnv returns a string describing the environment of a newly created view. 23242-// 23243-// It must not be called concurrently with any other view methods. 23244-func viewEnv(v *View) string { 23245- env := v.options.EnvSlice() 23246- buildFlags := append([]string{}, v.options.BuildFlags...) 23247- 23248- var buf bytes.Buffer 23249- fmt.Fprintf(&buf, `go info for %v 23250-(go dir %s) 23251-(go version %s) 23252-(valid build configuration = %v) 23253-(build flags: %v) 23254-(selected go env: %v) 23255-`, 23256- v.folder.Filename(), 23257- v.workingDir().Filename(), 23258- strings.TrimRight(v.workspaceInformation.goversionOutput, "\n"), 23259- v.snapshot.ValidBuildConfiguration(), 23260- buildFlags, 23261- v.goEnv, 23262- ) 23263- 23264- for _, v := range env { 23265- s := strings.SplitN(v, "=", 2) 23266- if len(s) != 2 { 23267- continue 23268- } 23269- } 23270- 23271- return buf.String() 23272-} 23273- 23274-func (s *snapshot) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error { 23275- return s.view.importsState.runProcessEnvFunc(ctx, s, fn) 23276-} 23277- 23278-// separated out from its sole use in locateTemplateFiles for testability 23279-func fileHasExtension(path string, suffixes []string) bool { 23280- ext := filepath.Ext(path) 23281- if ext != "" && ext[0] == '.' { 23282- ext = ext[1:] 23283- } 23284- for _, s := range suffixes { 23285- if s != "" && ext == s { 23286- return true 23287- } 23288- } 23289- return false 23290-} 23291- 23292-// locateTemplateFiles ensures that the snapshot has mapped template files 23293-// within the workspace folder. 23294-func (s *snapshot) locateTemplateFiles(ctx context.Context) { 23295- if len(s.view.Options().TemplateExtensions) == 0 { 23296- return 23297- } 23298- suffixes := s.view.Options().TemplateExtensions 23299- 23300- searched := 0 23301- filterFunc := s.view.filterFunc() 23302- err := filepath.WalkDir(s.view.folder.Filename(), func(path string, entry os.DirEntry, err error) error { 23303- if err != nil { 23304- return err 23305- } 23306- if entry.IsDir() { 23307- return nil 23308- } 23309- if fileLimit > 0 && searched > fileLimit { 23310- return errExhausted 23311- } 23312- searched++ 23313- if !fileHasExtension(path, suffixes) { 23314- return nil 23315- } 23316- uri := span.URIFromPath(path) 23317- if filterFunc(uri) { 23318- return nil 23319- } 23320- // Get the file in order to include it in the snapshot. 23321- // TODO(golang/go#57558): it is fundamentally broken to track files in this 23322- // way; we may lose them if configuration or layout changes cause a view to 23323- // be recreated. 23324- // 23325- // Furthermore, this operation must ignore errors, including context 23326- // cancellation, or risk leaving the snapshot in an undefined state. 23327- s.GetFile(ctx, uri) 23328- return nil 23329- }) 23330- if err != nil { 23331- event.Error(ctx, "searching for template files failed", err) 23332- } 23333-} 23334- 23335-func (v *View) contains(uri span.URI) bool { 23336- // If we've expanded the go dir to a parent directory, consider if the 23337- // expanded dir contains the uri. 23338- // TODO(rfindley): should we ignore the root here? It is not provided by the 23339- // user. It would be better to explicitly consider the set of active modules 23340- // wherever relevant. 23341- inGoDir := false 23342- if source.InDir(v.workingDir().Filename(), v.folder.Filename()) { 23343- inGoDir = source.InDir(v.workingDir().Filename(), uri.Filename()) 23344- } 23345- inFolder := source.InDir(v.folder.Filename(), uri.Filename()) 23346- 23347- if !inGoDir && !inFolder { 23348- return false 23349- } 23350- 23351- return !v.filterFunc()(uri) 23352-} 23353- 23354-// filterFunc returns a func that reports whether uri is filtered by the currently configured 23355-// directoryFilters. 23356-func (v *View) filterFunc() func(span.URI) bool { 23357- filterer := buildFilterer(v.folder.Filename(), v.gomodcache, v.Options()) 23358- return func(uri span.URI) bool { 23359- // Only filter relative to the configured root directory. 23360- if source.InDir(v.folder.Filename(), uri.Filename()) { 23361- return pathExcludedByFilter(strings.TrimPrefix(uri.Filename(), v.folder.Filename()), filterer) 23362- } 23363- return false 23364- } 23365-} 23366- 23367-func (v *View) relevantChange(c source.FileModification) bool { 23368- // If the file is known to the view, the change is relevant. 23369- if v.knownFile(c.URI) { 23370- return true 23371- } 23372- // The go.work file may not be "known" because we first access it through the 23373- // session. As a result, treat changes to the view's go.work file as always 23374- // relevant, even if they are only on-disk changes. 23375- // 23376- // TODO(rfindley): Make sure the go.work files are always known 23377- // to the view. 23378- if c.URI == v.effectiveGOWORK() { 23379- return true 23380- } 23381- 23382- // Note: CL 219202 filtered out on-disk changes here that were not known to 23383- // the view, but this introduces a race when changes arrive before the view 23384- // is initialized (and therefore, before it knows about files). Since that CL 23385- // had neither test nor associated issue, and cited only emacs behavior, this 23386- // logic was deleted. 23387- 23388- return v.contains(c.URI) 23389-} 23390- 23391-func (v *View) markKnown(uri span.URI) { 23392- v.knownFilesMu.Lock() 23393- defer v.knownFilesMu.Unlock() 23394- if v.knownFiles == nil { 23395- v.knownFiles = make(map[span.URI]bool) 23396- } 23397- v.knownFiles[uri] = true 23398-} 23399- 23400-// knownFile reports whether the specified valid URI (or an alias) is known to the view. 23401-func (v *View) knownFile(uri span.URI) bool { 23402- v.knownFilesMu.Lock() 23403- defer v.knownFilesMu.Unlock() 23404- return v.knownFiles[uri] 23405-} 23406- 23407-// shutdown releases resources associated with the view, and waits for ongoing 23408-// work to complete. 23409-func (v *View) shutdown() { 23410- // Cancel the initial workspace load if it is still running. 23411- v.initCancelFirstAttempt() 23412- 23413- v.snapshotMu.Lock() 23414- if v.snapshot != nil { 23415- v.releaseSnapshot() 23416- v.destroy(v.snapshot, "View.shutdown") 23417- v.snapshot = nil 23418- v.releaseSnapshot = nil 23419- } 23420- v.snapshotMu.Unlock() 23421- 23422- v.snapshotWG.Wait() 23423-} 23424- 23425-func (s *snapshot) IgnoredFile(uri span.URI) bool { 23426- filename := uri.Filename() 23427- var prefixes []string 23428- if len(s.workspaceModFiles) == 0 { 23429- for _, entry := range filepath.SplitList(s.view.gopath) { 23430- prefixes = append(prefixes, filepath.Join(entry, "src")) 23431- } 23432- } else { 23433- prefixes = append(prefixes, s.view.gomodcache) 23434- for m := range s.workspaceModFiles { 23435- prefixes = append(prefixes, span.Dir(m).Filename()) 23436- } 23437- } 23438- for _, prefix := range prefixes { 23439- if strings.HasPrefix(filename, prefix) { 23440- return checkIgnored(filename[len(prefix):]) 23441- } 23442- } 23443- return false 23444-} 23445- 23446-// checkIgnored implements go list's exclusion rules. 23447-// Quoting “go help list”: 23448-// 23449-// Directory and file names that begin with "." or "_" are ignored 23450-// by the go tool, as are directories named "testdata". 23451-func checkIgnored(suffix string) bool { 23452- for _, component := range strings.Split(suffix, string(filepath.Separator)) { 23453- if len(component) == 0 { 23454- continue 23455- } 23456- if component[0] == '.' || component[0] == '_' || component == "testdata" { 23457- return true 23458- } 23459- } 23460- return false 23461-} 23462- 23463-func (v *View) Snapshot() (source.Snapshot, func(), error) { 23464- return v.getSnapshot() 23465-} 23466- 23467-func (v *View) getSnapshot() (*snapshot, func(), error) { 23468- v.snapshotMu.Lock() 23469- defer v.snapshotMu.Unlock() 23470- if v.snapshot == nil { 23471- return nil, nil, errors.New("view is shutdown") 23472- } 23473- return v.snapshot, v.snapshot.Acquire(), nil 23474-} 23475- 23476-func (s *snapshot) initialize(ctx context.Context, firstAttempt bool) { 23477- select { 23478- case <-ctx.Done(): 23479- return 23480- case s.view.initializationSema <- struct{}{}: 23481- } 23482- 23483- defer func() { 23484- <-s.view.initializationSema 23485- }() 23486- 23487- s.mu.Lock() 23488- initialized := s.initialized 23489- s.mu.Unlock() 23490- 23491- if initialized { 23492- return 23493- } 23494- 23495- s.loadWorkspace(ctx, firstAttempt) 23496- s.collectAllKnownSubdirs(ctx) 23497-} 23498- 23499-func (s *snapshot) loadWorkspace(ctx context.Context, firstAttempt bool) (loadErr error) { 23500- // A failure is retryable if it may have been due to context cancellation, 23501- // and this is not the initial workspace load (firstAttempt==true). 23502- // 23503- // The IWL runs on a detached context with a long (~10m) timeout, so 23504- // if the context was canceled we consider loading to have failed 23505- // permanently. 23506- retryableFailure := func() bool { 23507- return loadErr != nil && ctx.Err() != nil && !firstAttempt 23508- } 23509- defer func() { 23510- if !retryableFailure() { 23511- s.mu.Lock() 23512- s.initialized = true 23513- s.mu.Unlock() 23514- } 23515- if firstAttempt { 23516- close(s.view.initialWorkspaceLoad) 23517- } 23518- }() 23519- 23520- // TODO(rFindley): we should only locate template files on the first attempt, 23521- // or guard it via a different mechanism. 23522- s.locateTemplateFiles(ctx) 23523- 23524- // Collect module paths to load by parsing go.mod files. If a module fails to 23525- // parse, capture the parsing failure as a critical diagnostic. 23526- var scopes []loadScope // scopes to load 23527- var modDiagnostics []*source.Diagnostic // diagnostics for broken go.mod files 23528- addError := func(uri span.URI, err error) { 23529- modDiagnostics = append(modDiagnostics, &source.Diagnostic{ 23530- URI: uri, 23531- Severity: protocol.SeverityError, 23532- Source: source.ListError, 23533- Message: err.Error(), 23534- }) 23535- } 23536- 23537- if len(s.workspaceModFiles) > 0 { 23538- for modURI := range s.workspaceModFiles { 23539- // Be careful not to add context cancellation errors as critical module 23540- // errors. 23541- fh, err := s.GetFile(ctx, modURI) 23542- if err != nil { 23543- if ctx.Err() == nil { 23544- addError(modURI, err) 23545- } 23546- continue 23547- } 23548- parsed, err := s.ParseMod(ctx, fh) 23549- if err != nil { 23550- if ctx.Err() == nil { 23551- addError(modURI, err) 23552- } 23553- continue 23554- } 23555- if parsed.File == nil || parsed.File.Module == nil { 23556- addError(modURI, fmt.Errorf("no module path for %s", modURI)) 23557- continue 23558- } 23559- path := parsed.File.Module.Mod.Path 23560- scopes = append(scopes, moduleLoadScope(path)) 23561- } 23562- } else { 23563- scopes = append(scopes, viewLoadScope("LOAD_VIEW")) 23564- } 23565- 23566- // If we're loading anything, ensure we also load builtin, 23567- // since it provides fake definitions (and documentation) 23568- // for types like int that are used everywhere. 23569- if len(scopes) > 0 { 23570- scopes = append(scopes, packageLoadScope("builtin")) 23571- } 23572- loadErr = s.load(ctx, true, scopes...) 23573- 23574- if retryableFailure() { 23575- return loadErr 23576- } 23577- 23578- var criticalErr *source.CriticalError 23579- switch { 23580- case loadErr != nil && ctx.Err() != nil: 23581- event.Error(ctx, fmt.Sprintf("initial workspace load: %v", loadErr), loadErr) 23582- criticalErr = &source.CriticalError{ 23583- MainError: loadErr, 23584- } 23585- case loadErr != nil: 23586- event.Error(ctx, "initial workspace load failed", loadErr) 23587- extractedDiags := s.extractGoCommandErrors(ctx, loadErr) 23588- criticalErr = &source.CriticalError{ 23589- MainError: loadErr, 23590- Diagnostics: append(modDiagnostics, extractedDiags...), 23591- } 23592- case len(modDiagnostics) == 1: 23593- criticalErr = &source.CriticalError{ 23594- MainError: fmt.Errorf(modDiagnostics[0].Message), 23595- Diagnostics: modDiagnostics, 23596- } 23597- case len(modDiagnostics) > 1: 23598- criticalErr = &source.CriticalError{ 23599- MainError: fmt.Errorf("error loading module names"), 23600- Diagnostics: modDiagnostics, 23601- } 23602- } 23603- 23604- // Lock the snapshot when setting the initialized error. 23605- s.mu.Lock() 23606- defer s.mu.Unlock() 23607- s.initializedErr = criticalErr 23608- return loadErr 23609-} 23610- 23611-// invalidateContent invalidates the content of a Go file, 23612-// including any position and type information that depends on it. 23613-// 23614-// invalidateContent returns a non-nil snapshot for the new content, along with 23615-// a callback which the caller must invoke to release that snapshot. 23616-func (v *View) invalidateContent(ctx context.Context, changes map[span.URI]*fileChange, forceReloadMetadata bool) (*snapshot, func()) { 23617- // Detach the context so that content invalidation cannot be canceled. 23618- ctx = xcontext.Detach(ctx) 23619- 23620- // This should be the only time we hold the view's snapshot lock for any period of time. 23621- v.snapshotMu.Lock() 23622- defer v.snapshotMu.Unlock() 23623- 23624- prevSnapshot, prevReleaseSnapshot := v.snapshot, v.releaseSnapshot 23625- 23626- if prevSnapshot == nil { 23627- panic("invalidateContent called after shutdown") 23628- } 23629- 23630- // Cancel all still-running previous requests, since they would be 23631- // operating on stale data. 23632- prevSnapshot.cancel() 23633- 23634- // Do not clone a snapshot until its view has finished initializing. 23635- prevSnapshot.AwaitInitialized(ctx) 23636- 23637- // Save one lease of the cloned snapshot in the view. 23638- v.snapshot, v.releaseSnapshot = prevSnapshot.clone(ctx, v.baseCtx, changes, forceReloadMetadata) 23639- 23640- prevReleaseSnapshot() 23641- v.destroy(prevSnapshot, "View.invalidateContent") 23642- 23643- // Return a second lease to the caller. 23644- return v.snapshot, v.snapshot.Acquire() 23645-} 23646- 23647-func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI, options *source.Options) (workspaceInformation, error) { 23648- if err := checkPathCase(folder.Filename()); err != nil { 23649- return workspaceInformation{}, fmt.Errorf("invalid workspace folder path: %w; check that the casing of the configured workspace folder path agrees with the casing reported by the operating system", err) 23650- } 23651- var err error 23652- var info workspaceInformation 23653- inv := gocommand.Invocation{ 23654- WorkingDir: folder.Filename(), 23655- Env: options.EnvSlice(), 23656- } 23657- info.goversion, err = gocommand.GoVersion(ctx, inv, s.gocmdRunner) 23658- if err != nil { 23659- return info, err 23660- } 23661- info.goversionOutput, err = gocommand.GoVersionOutput(ctx, inv, s.gocmdRunner) 23662- if err != nil { 23663- return info, err 23664- } 23665- if err := info.goEnv.load(ctx, folder.Filename(), options.EnvSlice(), s.gocmdRunner); err != nil { 23666- return info, err 23667- } 23668- // The value of GOPACKAGESDRIVER is not returned through the go command. 23669- gopackagesdriver := os.Getenv("GOPACKAGESDRIVER") 23670- // A user may also have a gopackagesdriver binary on their machine, which 23671- // works the same way as setting GOPACKAGESDRIVER. 23672- tool, _ := exec.LookPath("gopackagesdriver") 23673- info.hasGopackagesDriver = gopackagesdriver != "off" && (gopackagesdriver != "" || tool != "") 23674- 23675- // filterFunc is the path filter function for this workspace folder. Notably, 23676- // it is relative to folder (which is specified by the user), not root. 23677- filterFunc := pathExcludedByFilterFunc(folder.Filename(), info.gomodcache, options) 23678- info.gomod, err = findWorkspaceModFile(ctx, folder, s, filterFunc) 23679- if err != nil { 23680- return info, err 23681- } 23682- 23683- return info, nil 23684-} 23685- 23686-// findWorkspaceModFile searches for a single go.mod file relative to the given 23687-// folder URI, using the following algorithm: 23688-// 1. if there is a go.mod file in a parent directory, return it 23689-// 2. else, if there is exactly one nested module, return it 23690-// 3. else, return "" 23691-func findWorkspaceModFile(ctx context.Context, folderURI span.URI, fs source.FileSource, excludePath func(string) bool) (span.URI, error) { 23692- folder := folderURI.Filename() 23693- match, err := findRootPattern(ctx, folder, "go.mod", fs) 23694- if err != nil { 23695- if ctxErr := ctx.Err(); ctxErr != nil { 23696- return "", ctxErr 23697- } 23698- return "", err 23699- } 23700- if match != "" { 23701- return span.URIFromPath(match), nil 23702- } 23703- 23704- // ...else we should check if there's exactly one nested module. 23705- all, err := findModules(folderURI, excludePath, 2) 23706- if err == errExhausted { 23707- // Fall-back behavior: if we don't find any modules after searching 10000 23708- // files, assume there are none. 23709- event.Log(ctx, fmt.Sprintf("stopped searching for modules after %d files", fileLimit)) 23710- return "", nil 23711- } 23712- if err != nil { 23713- return "", err 23714- } 23715- if len(all) == 1 { 23716- // range to access first element. 23717- for uri := range all { 23718- return uri, nil 23719- } 23720- } 23721- return "", nil 23722-} 23723- 23724-// workingDir returns the directory from which to run Go commands. 23725-// 23726-// The only case where this should matter is if we've narrowed the workspace to 23727-// a singular nested module. In that case, the go command won't be able to find 23728-// the module unless we tell it the nested directory. 23729-func (v *View) workingDir() span.URI { 23730- // Note: if gowork is in use, this will default to the workspace folder. In 23731- // the past, we would instead use the folder containing go.work. This should 23732- // not make a difference, and in fact may improve go list error messages. 23733- // 23734- // TODO(golang/go#57514): eliminate the expandWorkspaceToModule setting 23735- // entirely. 23736- if v.Options().ExpandWorkspaceToModule && v.gomod != "" { 23737- return span.Dir(v.gomod) 23738- } 23739- return v.folder 23740-} 23741- 23742-// findRootPattern looks for files with the given basename in dir or any parent 23743-// directory of dir, using the provided FileSource. It returns the first match, 23744-// starting from dir and search parents. 23745-// 23746-// The resulting string is either the file path of a matching file with the 23747-// given basename, or "" if none was found. 23748-func findRootPattern(ctx context.Context, dir, basename string, fs source.FileSource) (string, error) { 23749- for dir != "" { 23750- target := filepath.Join(dir, basename) 23751- exists, err := fileExists(ctx, span.URIFromPath(target), fs) 23752- if err != nil { 23753- return "", err // not readable or context cancelled 23754- } 23755- if exists { 23756- return target, nil 23757- } 23758- // Trailing separators must be trimmed, otherwise filepath.Split is a noop. 23759- next, _ := filepath.Split(strings.TrimRight(dir, string(filepath.Separator))) 23760- if next == dir { 23761- break 23762- } 23763- dir = next 23764- } 23765- return "", nil 23766-} 23767- 23768-// OS-specific path case check, for case-insensitive filesystems. 23769-var checkPathCase = defaultCheckPathCase 23770- 23771-func defaultCheckPathCase(path string) error { 23772- return nil 23773-} 23774- 23775-func (v *View) IsGoPrivatePath(target string) bool { 23776- return globsMatchPath(v.goprivate, target) 23777-} 23778- 23779-func (v *View) ModuleUpgrades(modfile span.URI) map[string]string { 23780- v.moduleUpgradesMu.Lock() 23781- defer v.moduleUpgradesMu.Unlock() 23782- 23783- upgrades := map[string]string{} 23784- for mod, ver := range v.moduleUpgrades[modfile] { 23785- upgrades[mod] = ver 23786- } 23787- return upgrades 23788-} 23789- 23790-func (v *View) RegisterModuleUpgrades(modfile span.URI, upgrades map[string]string) { 23791- // Return early if there are no upgrades. 23792- if len(upgrades) == 0 { 23793- return 23794- } 23795- 23796- v.moduleUpgradesMu.Lock() 23797- defer v.moduleUpgradesMu.Unlock() 23798- 23799- m := v.moduleUpgrades[modfile] 23800- if m == nil { 23801- m = make(map[string]string) 23802- v.moduleUpgrades[modfile] = m 23803- } 23804- for mod, ver := range upgrades { 23805- m[mod] = ver 23806- } 23807-} 23808- 23809-func (v *View) ClearModuleUpgrades(modfile span.URI) { 23810- v.moduleUpgradesMu.Lock() 23811- defer v.moduleUpgradesMu.Unlock() 23812- 23813- delete(v.moduleUpgrades, modfile) 23814-} 23815- 23816-const maxGovulncheckResultAge = 1 * time.Hour // Invalidate results older than this limit. 23817-var timeNow = time.Now // for testing 23818- 23819-func (v *View) Vulnerabilities(modfiles ...span.URI) map[span.URI]*govulncheck.Result { 23820- m := make(map[span.URI]*govulncheck.Result) 23821- now := timeNow() 23822- v.vulnsMu.Lock() 23823- defer v.vulnsMu.Unlock() 23824- 23825- if len(modfiles) == 0 { // empty means all modfiles 23826- for modfile := range v.vulns { 23827- modfiles = append(modfiles, modfile) 23828- } 23829- } 23830- for _, modfile := range modfiles { 23831- vuln := v.vulns[modfile] 23832- if vuln != nil && now.Sub(vuln.AsOf) > maxGovulncheckResultAge { 23833- v.vulns[modfile] = nil // same as SetVulnerabilities(modfile, nil) 23834- vuln = nil 23835- } 23836- m[modfile] = vuln 23837- } 23838- return m 23839-} 23840- 23841-func (v *View) SetVulnerabilities(modfile span.URI, vulns *govulncheck.Result) { 23842- v.vulnsMu.Lock() 23843- defer v.vulnsMu.Unlock() 23844- 23845- v.vulns[modfile] = vulns 23846-} 23847- 23848-func (v *View) GoVersion() int { 23849- return v.workspaceInformation.goversion 23850-} 23851- 23852-func (v *View) GoVersionString() string { 23853- return gocommand.ParseGoVersionOutput(v.workspaceInformation.goversionOutput) 23854-} 23855- 23856-// Copied from 23857-// https://cs.opensource.google/go/go/+/master:src/cmd/go/internal/str/path.go;l=58;drc=2910c5b4a01a573ebc97744890a07c1a3122c67a 23858-func globsMatchPath(globs, target string) bool { 23859- for globs != "" { 23860- // Extract next non-empty glob in comma-separated list. 23861- var glob string 23862- if i := strings.Index(globs, ","); i >= 0 { 23863- glob, globs = globs[:i], globs[i+1:] 23864- } else { 23865- glob, globs = globs, "" 23866- } 23867- if glob == "" { 23868- continue 23869- } 23870- 23871- // A glob with N+1 path elements (N slashes) needs to be matched 23872- // against the first N+1 path elements of target, 23873- // which end just before the N+1'th slash. 23874- n := strings.Count(glob, "/") 23875- prefix := target 23876- // Walk target, counting slashes, truncating at the N+1'th slash. 23877- for i := 0; i < len(target); i++ { 23878- if target[i] == '/' { 23879- if n == 0 { 23880- prefix = target[:i] 23881- break 23882- } 23883- n-- 23884- } 23885- } 23886- if n > 0 { 23887- // Not enough prefix elements. 23888- continue 23889- } 23890- matched, _ := path.Match(glob, prefix) 23891- if matched { 23892- return true 23893- } 23894- } 23895- return false 23896-} 23897- 23898-var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`) 23899- 23900-// TODO(rstambler): Consolidate modURI and modContent back into a FileHandle 23901-// after we have a version of the workspace go.mod file on disk. Getting a 23902-// FileHandle from the cache for temporary files is problematic, since we 23903-// cannot delete it. 23904-func (s *snapshot) vendorEnabled(ctx context.Context, modURI span.URI, modContent []byte) (bool, error) { 23905- // Legacy GOPATH workspace? 23906- if s.workspaceMode()&moduleMode == 0 { 23907- return false, nil 23908- } 23909- 23910- // Explicit -mod flag? 23911- matches := modFlagRegexp.FindStringSubmatch(s.view.goflags) 23912- if len(matches) != 0 { 23913- modFlag := matches[1] 23914- if modFlag != "" { 23915- // Don't override an explicit '-mod=vendor' argument. 23916- // We do want to override '-mod=readonly': it would break various module code lenses, 23917- // and on 1.16 we know -modfile is available, so we won't mess with go.mod anyway. 23918- return modFlag == "vendor", nil 23919- } 23920- } 23921- 23922- modFile, err := modfile.Parse(modURI.Filename(), modContent, nil) 23923- if err != nil { 23924- return false, err 23925- } 23926- 23927- // No vendor directory? 23928- // TODO(golang/go#57514): this is wrong if the working dir is not the module 23929- // root. 23930- if fi, err := os.Stat(filepath.Join(s.view.workingDir().Filename(), "vendor")); err != nil || !fi.IsDir() { 23931- return false, nil 23932- } 23933- 23934- // Vendoring enabled by default by go declaration in go.mod? 23935- vendorEnabled := modFile.Go != nil && modFile.Go.Version != "" && semver.Compare("v"+modFile.Go.Version, "v1.14") >= 0 23936- return vendorEnabled, nil 23937-} 23938- 23939-// TODO(rfindley): clean up the redundancy of allFilesExcluded, 23940-// pathExcludedByFilterFunc, pathExcludedByFilter, view.filterFunc... 23941-func allFilesExcluded(files []string, filterFunc func(span.URI) bool) bool { 23942- for _, f := range files { 23943- uri := span.URIFromPath(f) 23944- if !filterFunc(uri) { 23945- return false 23946- } 23947- } 23948- return true 23949-} 23950- 23951-func pathExcludedByFilterFunc(folder, gomodcache string, opts *source.Options) func(string) bool { 23952- filterer := buildFilterer(folder, gomodcache, opts) 23953- return func(path string) bool { 23954- return pathExcludedByFilter(path, filterer) 23955- } 23956-} 23957- 23958-// pathExcludedByFilter reports whether the path (relative to the workspace 23959-// folder) should be excluded by the configured directory filters. 23960-// 23961-// TODO(rfindley): passing root and gomodcache here makes it confusing whether 23962-// path should be absolute or relative, and has already caused at least one 23963-// bug. 23964-func pathExcludedByFilter(path string, filterer *source.Filterer) bool { 23965- path = strings.TrimPrefix(filepath.ToSlash(path), "/") 23966- return filterer.Disallow(path) 23967-} 23968- 23969-func buildFilterer(folder, gomodcache string, opts *source.Options) *source.Filterer { 23970- filters := opts.DirectoryFilters 23971- 23972- if pref := strings.TrimPrefix(gomodcache, folder); pref != gomodcache { 23973- modcacheFilter := "-" + strings.TrimPrefix(filepath.ToSlash(pref), "/") 23974- filters = append(filters, modcacheFilter) 23975- } 23976- return source.NewFilterer(filters) 23977-} 23978diff -urN a/gopls/internal/lsp/cache/view_test.go b/gopls/internal/lsp/cache/view_test.go 23979--- a/gopls/internal/lsp/cache/view_test.go 2000-01-01 00:00:00.000000000 -0000 23980+++ b/gopls/internal/lsp/cache/view_test.go 1970-01-01 00:00:00.000000000 +0000 23981@@ -1,278 +0,0 @@ 23982-// Copyright 2020 The Go Authors. All rights reserved. 23983-// Use of this source code is governed by a BSD-style 23984-// license that can be found in the LICENSE file. 23985-package cache 23986- 23987-import ( 23988- "context" 23989- "encoding/json" 23990- "io/ioutil" 23991- "os" 23992- "path/filepath" 23993- "testing" 23994- "time" 23995- 23996- "github.com/google/go-cmp/cmp" 23997- "golang.org/x/tools/gopls/internal/govulncheck" 23998- "golang.org/x/tools/gopls/internal/lsp/fake" 23999- "golang.org/x/tools/gopls/internal/lsp/source" 24000- "golang.org/x/tools/gopls/internal/span" 24001-) 24002- 24003-func TestCaseInsensitiveFilesystem(t *testing.T) { 24004- base, err := ioutil.TempDir("", t.Name()) 24005- if err != nil { 24006- t.Fatal(err) 24007- } 24008- 24009- inner := filepath.Join(base, "a/B/c/DEFgh") 24010- if err := os.MkdirAll(inner, 0777); err != nil { 24011- t.Fatal(err) 24012- } 24013- file := filepath.Join(inner, "f.go") 24014- if err := ioutil.WriteFile(file, []byte("hi"), 0777); err != nil { 24015- t.Fatal(err) 24016- } 24017- if _, err := os.Stat(filepath.Join(inner, "F.go")); err != nil { 24018- t.Skip("filesystem is case-sensitive") 24019- } 24020- 24021- tests := []struct { 24022- path string 24023- err bool 24024- }{ 24025- {file, false}, 24026- {filepath.Join(inner, "F.go"), true}, 24027- {filepath.Join(base, "a/b/c/defgh/f.go"), true}, 24028- } 24029- for _, tt := range tests { 24030- err := checkPathCase(tt.path) 24031- if err != nil != tt.err { 24032- t.Errorf("checkPathCase(%q) = %v, wanted error: %v", tt.path, err, tt.err) 24033- } 24034- } 24035-} 24036- 24037-func TestFindWorkspaceModFile(t *testing.T) { 24038- workspace := ` 24039--- a/go.mod -- 24040-module a 24041--- a/x/x.go 24042-package x 24043--- a/x/y/y.go 24044-package x 24045--- b/go.mod -- 24046-module b 24047--- b/c/go.mod -- 24048-module bc 24049--- d/gopls.mod -- 24050-module d-goplsworkspace 24051--- d/e/go.mod -- 24052-module de 24053--- f/g/go.mod -- 24054-module fg 24055-` 24056- dir, err := fake.Tempdir(fake.UnpackTxt(workspace)) 24057- if err != nil { 24058- t.Fatal(err) 24059- } 24060- defer os.RemoveAll(dir) 24061- 24062- tests := []struct { 24063- folder, want string 24064- }{ 24065- {"", ""}, // no module at root, and more than one nested module 24066- {"a", "a/go.mod"}, 24067- {"a/x", "a/go.mod"}, 24068- {"a/x/y", "a/go.mod"}, 24069- {"b/c", "b/c/go.mod"}, 24070- {"d", "d/e/go.mod"}, 24071- {"d/e", "d/e/go.mod"}, 24072- {"f", "f/g/go.mod"}, 24073- } 24074- 24075- for _, test := range tests { 24076- ctx := context.Background() 24077- rel := fake.RelativeTo(dir) 24078- folderURI := span.URIFromPath(rel.AbsPath(test.folder)) 24079- excludeNothing := func(string) bool { return false } 24080- got, err := findWorkspaceModFile(ctx, folderURI, New(nil), excludeNothing) 24081- if err != nil { 24082- t.Fatal(err) 24083- } 24084- want := span.URI("") 24085- if test.want != "" { 24086- want = span.URIFromPath(rel.AbsPath(test.want)) 24087- } 24088- if got != want { 24089- t.Errorf("findWorkspaceModFile(%q) = %q, want %q", test.folder, got, want) 24090- } 24091- } 24092-} 24093- 24094-func TestInVendor(t *testing.T) { 24095- for _, tt := range []struct { 24096- path string 24097- inVendor bool 24098- }{ 24099- {"foo/vendor/x.go", false}, 24100- {"foo/vendor/x/x.go", true}, 24101- {"foo/x.go", false}, 24102- {"foo/vendor/foo.txt", false}, 24103- {"foo/vendor/modules.txt", false}, 24104- } { 24105- if got := inVendor(span.URIFromPath(tt.path)); got != tt.inVendor { 24106- t.Errorf("expected %s inVendor %v, got %v", tt.path, tt.inVendor, got) 24107- } 24108- } 24109-} 24110- 24111-func TestFilters(t *testing.T) { 24112- tests := []struct { 24113- filters []string 24114- included []string 24115- excluded []string 24116- }{ 24117- { 24118- included: []string{"x"}, 24119- }, 24120- { 24121- filters: []string{"-"}, 24122- excluded: []string{"x", "x/a"}, 24123- }, 24124- { 24125- filters: []string{"-x", "+y"}, 24126- included: []string{"y", "y/a", "z"}, 24127- excluded: []string{"x", "x/a"}, 24128- }, 24129- { 24130- filters: []string{"-x", "+x/y", "-x/y/z"}, 24131- included: []string{"x/y", "x/y/a", "a"}, 24132- excluded: []string{"x", "x/a", "x/y/z/a"}, 24133- }, 24134- { 24135- filters: []string{"+foobar", "-foo"}, 24136- included: []string{"foobar", "foobar/a"}, 24137- excluded: []string{"foo", "foo/a"}, 24138- }, 24139- } 24140- 24141- for _, tt := range tests { 24142- filterer := source.NewFilterer(tt.filters) 24143- for _, inc := range tt.included { 24144- if pathExcludedByFilter(inc, filterer) { 24145- t.Errorf("filters %q excluded %v, wanted included", tt.filters, inc) 24146- } 24147- } 24148- for _, exc := range tt.excluded { 24149- if !pathExcludedByFilter(exc, filterer) { 24150- t.Errorf("filters %q included %v, wanted excluded", tt.filters, exc) 24151- } 24152- } 24153- } 24154-} 24155- 24156-func TestSuffixes(t *testing.T) { 24157- type file struct { 24158- path string 24159- want bool 24160- } 24161- type cases struct { 24162- option []string 24163- files []file 24164- } 24165- tests := []cases{ 24166- {[]string{"tmpl", "gotmpl"}, []file{ // default 24167- {"foo", false}, 24168- {"foo.tmpl", true}, 24169- {"foo.gotmpl", true}, 24170- {"tmpl", false}, 24171- {"tmpl.go", false}}, 24172- }, 24173- {[]string{"tmpl", "gotmpl", "html", "gohtml"}, []file{ 24174- {"foo.gotmpl", true}, 24175- {"foo.html", true}, 24176- {"foo.gohtml", true}, 24177- {"html", false}}, 24178- }, 24179- {[]string{"tmpl", "gotmpl", ""}, []file{ // possible user mistake 24180- {"foo.gotmpl", true}, 24181- {"foo.go", false}, 24182- {"foo", false}}, 24183- }, 24184- } 24185- for _, a := range tests { 24186- suffixes := a.option 24187- for _, b := range a.files { 24188- got := fileHasExtension(b.path, suffixes) 24189- if got != b.want { 24190- t.Errorf("got %v, want %v, option %q, file %q (%+v)", 24191- got, b.want, a.option, b.path, b) 24192- } 24193- } 24194- } 24195-} 24196- 24197-func TestView_Vulnerabilities(t *testing.T) { 24198- // TODO(hyangah): use t.Cleanup when we get rid of go1.13 legacy CI. 24199- defer func() { timeNow = time.Now }() 24200- 24201- now := time.Now() 24202- 24203- view := &View{ 24204- vulns: make(map[span.URI]*govulncheck.Result), 24205- } 24206- file1, file2 := span.URIFromPath("f1/go.mod"), span.URIFromPath("f2/go.mod") 24207- 24208- vuln1 := &govulncheck.Result{AsOf: now.Add(-(maxGovulncheckResultAge * 3) / 4)} // already ~3/4*maxGovulncheckResultAge old 24209- view.SetVulnerabilities(file1, vuln1) 24210- 24211- vuln2 := &govulncheck.Result{AsOf: now} // fresh. 24212- view.SetVulnerabilities(file2, vuln2) 24213- 24214- t.Run("fresh", func(t *testing.T) { 24215- got := view.Vulnerabilities() 24216- want := map[span.URI]*govulncheck.Result{ 24217- file1: vuln1, 24218- file2: vuln2, 24219- } 24220- 24221- if diff := cmp.Diff(toJSON(want), toJSON(got)); diff != "" { 24222- t.Errorf("view.Vulnerabilities() mismatch (-want +got):\n%s", diff) 24223- } 24224- }) 24225- 24226- // maxGovulncheckResultAge/2 later 24227- timeNow = func() time.Time { return now.Add(maxGovulncheckResultAge / 2) } 24228- t.Run("after30min", func(t *testing.T) { 24229- got := view.Vulnerabilities() 24230- want := map[span.URI]*govulncheck.Result{ 24231- file1: nil, // expired. 24232- file2: vuln2, 24233- } 24234- 24235- if diff := cmp.Diff(toJSON(want), toJSON(got)); diff != "" { 24236- t.Errorf("view.Vulnerabilities() mismatch (-want +got):\n%s", diff) 24237- } 24238- }) 24239- 24240- // maxGovulncheckResultAge later 24241- timeNow = func() time.Time { return now.Add(maxGovulncheckResultAge + time.Minute) } 24242- 24243- t.Run("after1hr", func(t *testing.T) { 24244- got := view.Vulnerabilities() 24245- want := map[span.URI]*govulncheck.Result{ 24246- file1: nil, 24247- file2: nil, 24248- } 24249- 24250- if diff := cmp.Diff(toJSON(want), toJSON(got)); diff != "" { 24251- t.Errorf("view.Vulnerabilities() mismatch (-want +got):\n%s", diff) 24252- } 24253- }) 24254-} 24255- 24256-func toJSON(x interface{}) string { 24257- b, _ := json.MarshalIndent(x, "", " ") 24258- return string(b) 24259-} 24260diff -urN a/gopls/internal/lsp/cache/workspace.go b/gopls/internal/lsp/cache/workspace.go 24261--- a/gopls/internal/lsp/cache/workspace.go 2000-01-01 00:00:00.000000000 -0000 24262+++ b/gopls/internal/lsp/cache/workspace.go 1970-01-01 00:00:00.000000000 +0000 24263@@ -1,177 +0,0 @@ 24264-// Copyright 2020 The Go Authors. All rights reserved. 24265-// Use of this source code is governed by a BSD-style 24266-// license that can be found in the LICENSE file. 24267- 24268-package cache 24269- 24270-import ( 24271- "context" 24272- "errors" 24273- "fmt" 24274- "os" 24275- "path/filepath" 24276- "sort" 24277- "strings" 24278- 24279- "golang.org/x/mod/modfile" 24280- "golang.org/x/tools/gopls/internal/lsp/source" 24281- "golang.org/x/tools/gopls/internal/span" 24282-) 24283- 24284-// TODO(rfindley): now that experimentalWorkspaceModule is gone, this file can 24285-// be massively cleaned up and/or removed. 24286- 24287-// computeWorkspaceModFiles computes the set of workspace mod files based on the 24288-// value of go.mod, go.work, and GO111MODULE. 24289-func computeWorkspaceModFiles(ctx context.Context, gomod, gowork span.URI, go111module go111module, fs source.FileSource) (map[span.URI]struct{}, error) { 24290- if go111module == off { 24291- return nil, nil 24292- } 24293- if gowork != "" { 24294- fh, err := fs.GetFile(ctx, gowork) 24295- if err != nil { 24296- return nil, err 24297- } 24298- content, err := fh.Read() 24299- if err != nil { 24300- return nil, err 24301- } 24302- filename := gowork.Filename() 24303- dir := filepath.Dir(filename) 24304- workFile, err := modfile.ParseWork(filename, content, nil) 24305- if err != nil { 24306- return nil, fmt.Errorf("parsing go.work: %w", err) 24307- } 24308- modFiles := make(map[span.URI]struct{}) 24309- for _, use := range workFile.Use { 24310- modDir := filepath.FromSlash(use.Path) 24311- if !filepath.IsAbs(modDir) { 24312- modDir = filepath.Join(dir, modDir) 24313- } 24314- modURI := span.URIFromPath(filepath.Join(modDir, "go.mod")) 24315- modFiles[modURI] = struct{}{} 24316- } 24317- return modFiles, nil 24318- } 24319- if gomod != "" { 24320- return map[span.URI]struct{}{gomod: {}}, nil 24321- } 24322- return nil, nil 24323-} 24324- 24325-// dirs returns the workspace directories for the loaded modules. 24326-// 24327-// A workspace directory is, roughly speaking, a directory for which we care 24328-// about file changes. This is used for the purpose of registering file 24329-// watching patterns, and expanding directory modifications to their adjacent 24330-// files. 24331-// 24332-// TODO(rfindley): move this to snapshot.go. 24333-// TODO(rfindley): can we make this abstraction simpler and/or more accurate? 24334-func (s *snapshot) dirs(ctx context.Context) []span.URI { 24335- dirSet := make(map[span.URI]struct{}) 24336- 24337- // Dirs should, at the very least, contain the working directory and folder. 24338- dirSet[s.view.workingDir()] = struct{}{} 24339- dirSet[s.view.folder] = struct{}{} 24340- 24341- // Additionally, if e.g. go.work indicates other workspace modules, we should 24342- // include their directories too. 24343- if s.workspaceModFilesErr == nil { 24344- for modFile := range s.workspaceModFiles { 24345- dir := filepath.Dir(modFile.Filename()) 24346- dirSet[span.URIFromPath(dir)] = struct{}{} 24347- } 24348- } 24349- var dirs []span.URI 24350- for d := range dirSet { 24351- dirs = append(dirs, d) 24352- } 24353- sort.Slice(dirs, func(i, j int) bool { return dirs[i] < dirs[j] }) 24354- return dirs 24355-} 24356- 24357-// isGoMod reports if uri is a go.mod file. 24358-func isGoMod(uri span.URI) bool { 24359- return filepath.Base(uri.Filename()) == "go.mod" 24360-} 24361- 24362-// isGoWork reports if uri is a go.work file. 24363-func isGoWork(uri span.URI) bool { 24364- return filepath.Base(uri.Filename()) == "go.work" 24365-} 24366- 24367-// fileExists reports if the file uri exists within source. 24368-func fileExists(ctx context.Context, uri span.URI, source source.FileSource) (bool, error) { 24369- fh, err := source.GetFile(ctx, uri) 24370- if err != nil { 24371- return false, err 24372- } 24373- return fileHandleExists(fh) 24374-} 24375- 24376-// fileHandleExists reports if the file underlying fh actually exits. 24377-func fileHandleExists(fh source.FileHandle) (bool, error) { 24378- _, err := fh.Read() 24379- if err == nil { 24380- return true, nil 24381- } 24382- if os.IsNotExist(err) { 24383- return false, nil 24384- } 24385- return false, err 24386-} 24387- 24388-// errExhausted is returned by findModules if the file scan limit is reached. 24389-var errExhausted = errors.New("exhausted") 24390- 24391-// Limit go.mod search to 1 million files. As a point of reference, 24392-// Kubernetes has 22K files (as of 2020-11-24). 24393-const fileLimit = 1000000 24394- 24395-// findModules recursively walks the root directory looking for go.mod files, 24396-// returning the set of modules it discovers. If modLimit is non-zero, 24397-// searching stops once modLimit modules have been found. 24398-// 24399-// TODO(rfindley): consider overlays. 24400-func findModules(root span.URI, excludePath func(string) bool, modLimit int) (map[span.URI]struct{}, error) { 24401- // Walk the view's folder to find all modules in the view. 24402- modFiles := make(map[span.URI]struct{}) 24403- searched := 0 24404- errDone := errors.New("done") 24405- err := filepath.Walk(root.Filename(), func(path string, info os.FileInfo, err error) error { 24406- if err != nil { 24407- // Probably a permission error. Keep looking. 24408- return filepath.SkipDir 24409- } 24410- // For any path that is not the workspace folder, check if the path 24411- // would be ignored by the go command. Vendor directories also do not 24412- // contain workspace modules. 24413- if info.IsDir() && path != root.Filename() { 24414- suffix := strings.TrimPrefix(path, root.Filename()) 24415- switch { 24416- case checkIgnored(suffix), 24417- strings.Contains(filepath.ToSlash(suffix), "/vendor/"), 24418- excludePath(suffix): 24419- return filepath.SkipDir 24420- } 24421- } 24422- // We're only interested in go.mod files. 24423- uri := span.URIFromPath(path) 24424- if isGoMod(uri) { 24425- modFiles[uri] = struct{}{} 24426- } 24427- if modLimit > 0 && len(modFiles) >= modLimit { 24428- return errDone 24429- } 24430- searched++ 24431- if fileLimit > 0 && searched >= fileLimit { 24432- return errExhausted 24433- } 24434- return nil 24435- }) 24436- if err == errDone { 24437- return modFiles, nil 24438- } 24439- return modFiles, err 24440-} 24441diff -urN a/gopls/internal/lsp/call_hierarchy.go b/gopls/internal/lsp/call_hierarchy.go 24442--- a/gopls/internal/lsp/call_hierarchy.go 2000-01-01 00:00:00.000000000 -0000 24443+++ b/gopls/internal/lsp/call_hierarchy.go 1970-01-01 00:00:00.000000000 +0000 24444@@ -1,42 +0,0 @@ 24445-// Copyright 2020 The Go Authors. All rights reserved. 24446-// Use of this source code is governed by a BSD-style 24447-// license that can be found in the LICENSE file. 24448- 24449-package lsp 24450- 24451-import ( 24452- "context" 24453- 24454- "golang.org/x/tools/gopls/internal/lsp/protocol" 24455- "golang.org/x/tools/gopls/internal/lsp/source" 24456-) 24457- 24458-func (s *Server) prepareCallHierarchy(ctx context.Context, params *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) { 24459- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 24460- defer release() 24461- if !ok { 24462- return nil, err 24463- } 24464- 24465- return source.PrepareCallHierarchy(ctx, snapshot, fh, params.Position) 24466-} 24467- 24468-func (s *Server) incomingCalls(ctx context.Context, params *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) { 24469- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.Item.URI, source.Go) 24470- defer release() 24471- if !ok { 24472- return nil, err 24473- } 24474- 24475- return source.IncomingCalls(ctx, snapshot, fh, params.Item.Range.Start) 24476-} 24477- 24478-func (s *Server) outgoingCalls(ctx context.Context, params *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) { 24479- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.Item.URI, source.Go) 24480- defer release() 24481- if !ok { 24482- return nil, err 24483- } 24484- 24485- return source.OutgoingCalls(ctx, snapshot, fh, params.Item.Range.Start) 24486-} 24487diff -urN a/gopls/internal/lsp/cmd/call_hierarchy.go b/gopls/internal/lsp/cmd/call_hierarchy.go 24488--- a/gopls/internal/lsp/cmd/call_hierarchy.go 2000-01-01 00:00:00.000000000 -0000 24489+++ b/gopls/internal/lsp/cmd/call_hierarchy.go 1970-01-01 00:00:00.000000000 +0000 24490@@ -1,142 +0,0 @@ 24491-// Copyright 2020 The Go Authors. All rights reserved. 24492-// Use of this source code is governed by a BSD-style 24493-// license that can be found in the LICENSE file. 24494- 24495-package cmd 24496- 24497-import ( 24498- "context" 24499- "flag" 24500- "fmt" 24501- "strings" 24502- 24503- "golang.org/x/tools/gopls/internal/lsp/protocol" 24504- "golang.org/x/tools/gopls/internal/span" 24505- "golang.org/x/tools/internal/tool" 24506-) 24507- 24508-// callHierarchy implements the callHierarchy verb for gopls. 24509-type callHierarchy struct { 24510- app *Application 24511-} 24512- 24513-func (c *callHierarchy) Name() string { return "call_hierarchy" } 24514-func (c *callHierarchy) Parent() string { return c.app.Name() } 24515-func (c *callHierarchy) Usage() string { return "<position>" } 24516-func (c *callHierarchy) ShortHelp() string { return "display selected identifier's call hierarchy" } 24517-func (c *callHierarchy) DetailedHelp(f *flag.FlagSet) { 24518- fmt.Fprint(f.Output(), ` 24519-Example: 24520- 24521- $ # 1-indexed location (:line:column or :#offset) of the target identifier 24522- $ gopls call_hierarchy helper/helper.go:8:6 24523- $ gopls call_hierarchy helper/helper.go:#53 24524-`) 24525- printFlagDefaults(f) 24526-} 24527- 24528-func (c *callHierarchy) Run(ctx context.Context, args ...string) error { 24529- if len(args) != 1 { 24530- return tool.CommandLineErrorf("call_hierarchy expects 1 argument (position)") 24531- } 24532- 24533- conn, err := c.app.connect(ctx) 24534- if err != nil { 24535- return err 24536- } 24537- defer conn.terminate(ctx) 24538- 24539- from := span.Parse(args[0]) 24540- file := conn.openFile(ctx, from.URI()) 24541- if file.err != nil { 24542- return file.err 24543- } 24544- 24545- loc, err := file.mapper.SpanLocation(from) 24546- if err != nil { 24547- return err 24548- } 24549- 24550- p := protocol.CallHierarchyPrepareParams{ 24551- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 24552- } 24553- 24554- callItems, err := conn.PrepareCallHierarchy(ctx, &p) 24555- if err != nil { 24556- return err 24557- } 24558- if len(callItems) == 0 { 24559- return fmt.Errorf("function declaration identifier not found at %v", args[0]) 24560- } 24561- 24562- for _, item := range callItems { 24563- incomingCalls, err := conn.IncomingCalls(ctx, &protocol.CallHierarchyIncomingCallsParams{Item: item}) 24564- if err != nil { 24565- return err 24566- } 24567- for i, call := range incomingCalls { 24568- // From the spec: CallHierarchyIncomingCall.FromRanges is relative to 24569- // the caller denoted by CallHierarchyIncomingCall.from. 24570- printString, err := callItemPrintString(ctx, conn, call.From, call.From.URI, call.FromRanges) 24571- if err != nil { 24572- return err 24573- } 24574- fmt.Printf("caller[%d]: %s\n", i, printString) 24575- } 24576- 24577- printString, err := callItemPrintString(ctx, conn, item, "", nil) 24578- if err != nil { 24579- return err 24580- } 24581- fmt.Printf("identifier: %s\n", printString) 24582- 24583- outgoingCalls, err := conn.OutgoingCalls(ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: item}) 24584- if err != nil { 24585- return err 24586- } 24587- for i, call := range outgoingCalls { 24588- // From the spec: CallHierarchyOutgoingCall.FromRanges is the range 24589- // relative to the caller, e.g the item passed to 24590- printString, err := callItemPrintString(ctx, conn, call.To, item.URI, call.FromRanges) 24591- if err != nil { 24592- return err 24593- } 24594- fmt.Printf("callee[%d]: %s\n", i, printString) 24595- } 24596- } 24597- 24598- return nil 24599-} 24600- 24601-// callItemPrintString returns a protocol.CallHierarchyItem object represented as a string. 24602-// item and call ranges (protocol.Range) are converted to user friendly spans (1-indexed). 24603-func callItemPrintString(ctx context.Context, conn *connection, item protocol.CallHierarchyItem, callsURI protocol.DocumentURI, calls []protocol.Range) (string, error) { 24604- itemFile := conn.openFile(ctx, item.URI.SpanURI()) 24605- if itemFile.err != nil { 24606- return "", itemFile.err 24607- } 24608- itemSpan, err := itemFile.mapper.LocationSpan(protocol.Location{URI: item.URI, Range: item.Range}) 24609- if err != nil { 24610- return "", err 24611- } 24612- 24613- callsFile := conn.openFile(ctx, callsURI.SpanURI()) 24614- if callsURI != "" && callsFile.err != nil { 24615- return "", callsFile.err 24616- } 24617- var callRanges []string 24618- for _, rng := range calls { 24619- call, err := callsFile.mapper.RangeSpan(rng) 24620- if err != nil { 24621- return "", err 24622- } 24623- callRange := fmt.Sprintf("%d:%d-%d", call.Start().Line(), call.Start().Column(), call.End().Column()) 24624- callRanges = append(callRanges, callRange) 24625- } 24626- 24627- printString := fmt.Sprintf("function %s in %v", item.Name, itemSpan) 24628- if len(calls) > 0 { 24629- printString = fmt.Sprintf("ranges %s in %s from/to %s", strings.Join(callRanges, ", "), callsURI.SpanURI().Filename(), printString) 24630- } 24631- return printString, nil 24632-} 24633diff -urN a/gopls/internal/lsp/cmd/capabilities_test.go b/gopls/internal/lsp/cmd/capabilities_test.go 24634--- a/gopls/internal/lsp/cmd/capabilities_test.go 2000-01-01 00:00:00.000000000 -0000 24635+++ b/gopls/internal/lsp/cmd/capabilities_test.go 1970-01-01 00:00:00.000000000 +0000 24636@@ -1,166 +0,0 @@ 24637-// Copyright 2019 The Go Authors. All rights reserved. 24638-// Use of this source code is governed by a BSD-style 24639-// license that can be found in the LICENSE file. 24640- 24641-package cmd 24642- 24643-import ( 24644- "context" 24645- "fmt" 24646- "io/ioutil" 24647- "os" 24648- "path/filepath" 24649- "testing" 24650- 24651- "golang.org/x/tools/gopls/internal/lsp" 24652- "golang.org/x/tools/gopls/internal/lsp/cache" 24653- "golang.org/x/tools/gopls/internal/lsp/protocol" 24654-) 24655- 24656-// TestCapabilities does some minimal validation of the server's adherence to the LSP. 24657-// The checks in the test are added as changes are made and errors noticed. 24658-func TestCapabilities(t *testing.T) { 24659- tmpDir, err := ioutil.TempDir("", "fake") 24660- if err != nil { 24661- t.Fatal(err) 24662- } 24663- tmpFile := filepath.Join(tmpDir, "fake.go") 24664- if err := ioutil.WriteFile(tmpFile, []byte(""), 0775); err != nil { 24665- t.Fatal(err) 24666- } 24667- if err := ioutil.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte("module fake\n\ngo 1.12\n"), 0775); err != nil { 24668- t.Fatal(err) 24669- } 24670- defer os.RemoveAll(tmpDir) 24671- 24672- app := New("gopls-test", tmpDir, os.Environ(), nil) 24673- c := newConnection(app) 24674- ctx := context.Background() 24675- defer c.terminate(ctx) 24676- 24677- params := &protocol.ParamInitialize{} 24678- params.RootURI = protocol.URIFromPath(c.Client.app.wd) 24679- params.Capabilities.Workspace.Configuration = true 24680- 24681- // Send an initialize request to the server. 24682- c.Server = lsp.NewServer(cache.NewSession(ctx, cache.New(nil), app.options), c.Client) 24683- result, err := c.Server.Initialize(ctx, params) 24684- if err != nil { 24685- t.Fatal(err) 24686- } 24687- // Validate initialization result. 24688- if err := validateCapabilities(result); err != nil { 24689- t.Error(err) 24690- } 24691- // Complete initialization of server. 24692- if err := c.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil { 24693- t.Fatal(err) 24694- } 24695- 24696- // Open the file on the server side. 24697- uri := protocol.URIFromPath(tmpFile) 24698- if err := c.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ 24699- TextDocument: protocol.TextDocumentItem{ 24700- URI: uri, 24701- LanguageID: "go", 24702- Version: 1, 24703- Text: `package main; func main() {};`, 24704- }, 24705- }); err != nil { 24706- t.Fatal(err) 24707- } 24708- 24709- // If we are sending a full text change, the change.Range must be nil. 24710- // It is not enough for the Change to be empty, as that is ambiguous. 24711- if err := c.Server.DidChange(ctx, &protocol.DidChangeTextDocumentParams{ 24712- TextDocument: protocol.VersionedTextDocumentIdentifier{ 24713- TextDocumentIdentifier: protocol.TextDocumentIdentifier{ 24714- URI: uri, 24715- }, 24716- Version: 2, 24717- }, 24718- ContentChanges: []protocol.TextDocumentContentChangeEvent{ 24719- { 24720- Range: nil, 24721- Text: `package main; func main() { fmt.Println("") }`, 24722- }, 24723- }, 24724- }); err != nil { 24725- t.Fatal(err) 24726- } 24727- 24728- // Send a code action request to validate expected types. 24729- actions, err := c.Server.CodeAction(ctx, &protocol.CodeActionParams{ 24730- TextDocument: protocol.TextDocumentIdentifier{ 24731- URI: uri, 24732- }, 24733- }) 24734- if err != nil { 24735- t.Fatal(err) 24736- } 24737- for _, action := range actions { 24738- // Validate that an empty command is sent along with import organization responses. 24739- if action.Kind == protocol.SourceOrganizeImports && action.Command != nil { 24740- t.Errorf("unexpected command for import organization") 24741- } 24742- } 24743- 24744- if err := c.Server.DidSave(ctx, &protocol.DidSaveTextDocumentParams{ 24745- TextDocument: protocol.TextDocumentIdentifier{ 24746- URI: uri, 24747- }, 24748- // LSP specifies that a file can be saved with optional text, so this field must be nil. 24749- Text: nil, 24750- }); err != nil { 24751- t.Fatal(err) 24752- } 24753- 24754- // Send a completion request to validate expected types. 24755- list, err := c.Server.Completion(ctx, &protocol.CompletionParams{ 24756- TextDocumentPositionParams: protocol.TextDocumentPositionParams{ 24757- TextDocument: protocol.TextDocumentIdentifier{ 24758- URI: uri, 24759- }, 24760- Position: protocol.Position{ 24761- Line: 0, 24762- Character: 28, 24763- }, 24764- }, 24765- }) 24766- if err != nil { 24767- t.Fatal(err) 24768- } 24769- for _, item := range list.Items { 24770- // All other completion items should have nil commands. 24771- // An empty command will be treated as a command with the name '' by VS Code. 24772- // This causes VS Code to report errors to users about invalid commands. 24773- if item.Command != nil { 24774- t.Errorf("unexpected command for completion item") 24775- } 24776- // The item's TextEdit must be a pointer, as VS Code considers TextEdits 24777- // that don't contain the cursor position to be invalid. 24778- var textEdit interface{} = item.TextEdit 24779- if _, ok := textEdit.(*protocol.TextEdit); !ok { 24780- t.Errorf("textEdit is not a *protocol.TextEdit, instead it is %T", textEdit) 24781- } 24782- } 24783- if err := c.Server.Shutdown(ctx); err != nil { 24784- t.Fatal(err) 24785- } 24786- if err := c.Server.Exit(ctx); err != nil { 24787- t.Fatal(err) 24788- } 24789-} 24790- 24791-func validateCapabilities(result *protocol.InitializeResult) error { 24792- // If the client sends "false" for RenameProvider.PrepareSupport, 24793- // the server must respond with a boolean. 24794- if v, ok := result.Capabilities.RenameProvider.(bool); !ok { 24795- return fmt.Errorf("RenameProvider must be a boolean if PrepareSupport is false (got %T)", v) 24796- } 24797- // The same goes for CodeActionKind.ValueSet. 24798- if v, ok := result.Capabilities.CodeActionProvider.(bool); !ok { 24799- return fmt.Errorf("CodeActionSupport must be a boolean if CodeActionKind.ValueSet has length 0 (got %T)", v) 24800- } 24801- return nil 24802-} 24803diff -urN a/gopls/internal/lsp/cmd/check.go b/gopls/internal/lsp/cmd/check.go 24804--- a/gopls/internal/lsp/cmd/check.go 2000-01-01 00:00:00.000000000 -0000 24805+++ b/gopls/internal/lsp/cmd/check.go 1970-01-01 00:00:00.000000000 +0000 24806@@ -1,73 +0,0 @@ 24807-// Copyright 2019 The Go Authors. All rights reserved. 24808-// Use of this source code is governed by a BSD-style 24809-// license that can be found in the LICENSE file. 24810- 24811-package cmd 24812- 24813-import ( 24814- "context" 24815- "flag" 24816- "fmt" 24817- 24818- "golang.org/x/tools/gopls/internal/span" 24819-) 24820- 24821-// check implements the check verb for gopls. 24822-type check struct { 24823- app *Application 24824-} 24825- 24826-func (c *check) Name() string { return "check" } 24827-func (c *check) Parent() string { return c.app.Name() } 24828-func (c *check) Usage() string { return "<filename>" } 24829-func (c *check) ShortHelp() string { return "show diagnostic results for the specified file" } 24830-func (c *check) DetailedHelp(f *flag.FlagSet) { 24831- fmt.Fprint(f.Output(), ` 24832-Example: show the diagnostic results of this file: 24833- 24834- $ gopls check internal/lsp/cmd/check.go 24835-`) 24836- printFlagDefaults(f) 24837-} 24838- 24839-// Run performs the check on the files specified by args and prints the 24840-// results to stdout. 24841-func (c *check) Run(ctx context.Context, args ...string) error { 24842- if len(args) == 0 { 24843- // no files, so no results 24844- return nil 24845- } 24846- checking := map[span.URI]*cmdFile{} 24847- var uris []span.URI 24848- // now we ready to kick things off 24849- conn, err := c.app.connect(ctx) 24850- if err != nil { 24851- return err 24852- } 24853- defer conn.terminate(ctx) 24854- for _, arg := range args { 24855- uri := span.URIFromPath(arg) 24856- uris = append(uris, uri) 24857- file := conn.openFile(ctx, uri) 24858- if file.err != nil { 24859- return file.err 24860- } 24861- checking[uri] = file 24862- } 24863- if err := conn.diagnoseFiles(ctx, uris); err != nil { 24864- return err 24865- } 24866- conn.Client.filesMu.Lock() 24867- defer conn.Client.filesMu.Unlock() 24868- 24869- for _, file := range checking { 24870- for _, d := range file.diagnostics { 24871- spn, err := file.mapper.RangeSpan(d.Range) 24872- if err != nil { 24873- return fmt.Errorf("Could not convert position %v for %q", d.Range, d.Message) 24874- } 24875- fmt.Printf("%v: %v\n", spn, d.Message) 24876- } 24877- } 24878- return nil 24879-} 24880diff -urN a/gopls/internal/lsp/cmd/cmd.go b/gopls/internal/lsp/cmd/cmd.go 24881--- a/gopls/internal/lsp/cmd/cmd.go 2000-01-01 00:00:00.000000000 -0000 24882+++ b/gopls/internal/lsp/cmd/cmd.go 1970-01-01 00:00:00.000000000 +0000 24883@@ -1,640 +0,0 @@ 24884-// Copyright 2018 The Go Authors. All rights reserved. 24885-// Use of this source code is governed by a BSD-style 24886-// license that can be found in the LICENSE file. 24887- 24888-// Package cmd handles the gopls command line. 24889-// It contains a handler for each of the modes, along with all the flag handling 24890-// and the command line output format. 24891-package cmd 24892- 24893-import ( 24894- "context" 24895- "flag" 24896- "fmt" 24897- "io/ioutil" 24898- "log" 24899- "os" 24900- "reflect" 24901- "sort" 24902- "strings" 24903- "sync" 24904- "text/tabwriter" 24905- "time" 24906- 24907- "golang.org/x/tools/gopls/internal/lsp" 24908- "golang.org/x/tools/gopls/internal/lsp/cache" 24909- "golang.org/x/tools/gopls/internal/lsp/debug" 24910- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 24911- "golang.org/x/tools/gopls/internal/lsp/protocol" 24912- "golang.org/x/tools/gopls/internal/lsp/source" 24913- "golang.org/x/tools/gopls/internal/span" 24914- "golang.org/x/tools/internal/jsonrpc2" 24915- "golang.org/x/tools/internal/tool" 24916- "golang.org/x/tools/internal/xcontext" 24917-) 24918- 24919-// Application is the main application as passed to tool.Main 24920-// It handles the main command line parsing and dispatch to the sub commands. 24921-type Application struct { 24922- // Core application flags 24923- 24924- // Embed the basic profiling flags supported by the tool package 24925- tool.Profile 24926- 24927- // We include the server configuration directly for now, so the flags work 24928- // even without the verb. 24929- // TODO: Remove this when we stop allowing the serve verb by default. 24930- Serve Serve 24931- 24932- // the options configuring function to invoke when building a server 24933- options func(*source.Options) 24934- 24935- // The name of the binary, used in help and telemetry. 24936- name string 24937- 24938- // The working directory to run commands in. 24939- wd string 24940- 24941- // The environment variables to use. 24942- env []string 24943- 24944- // Support for remote LSP server. 24945- Remote string `flag:"remote" help:"forward all commands to a remote lsp specified by this flag. With no special prefix, this is assumed to be a TCP address. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. If 'auto', or prefixed by 'auto;', the remote address is automatically resolved based on the executing environment."` 24946- 24947- // Verbose enables verbose logging. 24948- Verbose bool `flag:"v,verbose" help:"verbose output"` 24949- 24950- // VeryVerbose enables a higher level of verbosity in logging output. 24951- VeryVerbose bool `flag:"vv,veryverbose" help:"very verbose output"` 24952- 24953- // Control ocagent export of telemetry 24954- OCAgent string `flag:"ocagent" help:"the address of the ocagent (e.g. http://localhost:55678), or off"` 24955- 24956- // PrepareOptions is called to update the options when a new view is built. 24957- // It is primarily to allow the behavior of gopls to be modified by hooks. 24958- PrepareOptions func(*source.Options) 24959-} 24960- 24961-func (app *Application) verbose() bool { 24962- return app.Verbose || app.VeryVerbose 24963-} 24964- 24965-// New returns a new Application ready to run. 24966-func New(name, wd string, env []string, options func(*source.Options)) *Application { 24967- if wd == "" { 24968- wd, _ = os.Getwd() 24969- } 24970- app := &Application{ 24971- options: options, 24972- name: name, 24973- wd: wd, 24974- env: env, 24975- OCAgent: "off", //TODO: Remove this line to default the exporter to on 24976- 24977- Serve: Serve{ 24978- RemoteListenTimeout: 1 * time.Minute, 24979- }, 24980- } 24981- app.Serve.app = app 24982- return app 24983-} 24984- 24985-// Name implements tool.Application returning the binary name. 24986-func (app *Application) Name() string { return app.name } 24987- 24988-// Usage implements tool.Application returning empty extra argument usage. 24989-func (app *Application) Usage() string { return "" } 24990- 24991-// ShortHelp implements tool.Application returning the main binary help. 24992-func (app *Application) ShortHelp() string { 24993- return "" 24994-} 24995- 24996-// DetailedHelp implements tool.Application returning the main binary help. 24997-// This includes the short help for all the sub commands. 24998-func (app *Application) DetailedHelp(f *flag.FlagSet) { 24999- w := tabwriter.NewWriter(f.Output(), 0, 0, 2, ' ', 0) 25000- defer w.Flush() 25001- 25002- fmt.Fprint(w, ` 25003-gopls is a Go language server. 25004- 25005-It is typically used with an editor to provide language features. When no 25006-command is specified, gopls will default to the 'serve' command. The language 25007-features can also be accessed via the gopls command-line interface. 25008- 25009-Usage: 25010- gopls help [<subject>] 25011- 25012-Command: 25013-`) 25014- fmt.Fprint(w, "\nMain\t\n") 25015- for _, c := range app.mainCommands() { 25016- fmt.Fprintf(w, " %s\t%s\n", c.Name(), c.ShortHelp()) 25017- } 25018- fmt.Fprint(w, "\t\nFeatures\t\n") 25019- for _, c := range app.featureCommands() { 25020- fmt.Fprintf(w, " %s\t%s\n", c.Name(), c.ShortHelp()) 25021- } 25022- fmt.Fprint(w, "\nflags:\n") 25023- printFlagDefaults(f) 25024-} 25025- 25026-// this is a slightly modified version of flag.PrintDefaults to give us control 25027-func printFlagDefaults(s *flag.FlagSet) { 25028- var flags [][]*flag.Flag 25029- seen := map[flag.Value]int{} 25030- s.VisitAll(func(f *flag.Flag) { 25031- if i, ok := seen[f.Value]; !ok { 25032- seen[f.Value] = len(flags) 25033- flags = append(flags, []*flag.Flag{f}) 25034- } else { 25035- flags[i] = append(flags[i], f) 25036- } 25037- }) 25038- for _, entry := range flags { 25039- sort.SliceStable(entry, func(i, j int) bool { 25040- return len(entry[i].Name) < len(entry[j].Name) 25041- }) 25042- var b strings.Builder 25043- for i, f := range entry { 25044- switch i { 25045- case 0: 25046- b.WriteString(" -") 25047- default: 25048- b.WriteString(",-") 25049- } 25050- b.WriteString(f.Name) 25051- } 25052- 25053- f := entry[0] 25054- name, usage := flag.UnquoteUsage(f) 25055- if len(name) > 0 { 25056- b.WriteString("=") 25057- b.WriteString(name) 25058- } 25059- // Boolean flags of one ASCII letter are so common we 25060- // treat them specially, putting their usage on the same line. 25061- if b.Len() <= 4 { // space, space, '-', 'x'. 25062- b.WriteString("\t") 25063- } else { 25064- // Four spaces before the tab triggers good alignment 25065- // for both 4- and 8-space tab stops. 25066- b.WriteString("\n \t") 25067- } 25068- b.WriteString(strings.ReplaceAll(usage, "\n", "\n \t")) 25069- if !isZeroValue(f, f.DefValue) { 25070- if reflect.TypeOf(f.Value).Elem().Name() == "stringValue" { 25071- fmt.Fprintf(&b, " (default %q)", f.DefValue) 25072- } else { 25073- fmt.Fprintf(&b, " (default %v)", f.DefValue) 25074- } 25075- } 25076- fmt.Fprint(s.Output(), b.String(), "\n") 25077- } 25078-} 25079- 25080-// isZeroValue is copied from the flags package 25081-func isZeroValue(f *flag.Flag, value string) bool { 25082- // Build a zero value of the flag's Value type, and see if the 25083- // result of calling its String method equals the value passed in. 25084- // This works unless the Value type is itself an interface type. 25085- typ := reflect.TypeOf(f.Value) 25086- var z reflect.Value 25087- if typ.Kind() == reflect.Ptr { 25088- z = reflect.New(typ.Elem()) 25089- } else { 25090- z = reflect.Zero(typ) 25091- } 25092- return value == z.Interface().(flag.Value).String() 25093-} 25094- 25095-// Run takes the args after top level flag processing, and invokes the correct 25096-// sub command as specified by the first argument. 25097-// If no arguments are passed it will invoke the server sub command, as a 25098-// temporary measure for compatibility. 25099-func (app *Application) Run(ctx context.Context, args ...string) error { 25100- ctx = debug.WithInstance(ctx, app.wd, app.OCAgent) 25101- if len(args) == 0 { 25102- s := flag.NewFlagSet(app.Name(), flag.ExitOnError) 25103- return tool.Run(ctx, s, &app.Serve, args) 25104- } 25105- command, args := args[0], args[1:] 25106- for _, c := range app.Commands() { 25107- if c.Name() == command { 25108- s := flag.NewFlagSet(app.Name(), flag.ExitOnError) 25109- return tool.Run(ctx, s, c, args) 25110- } 25111- } 25112- return tool.CommandLineErrorf("Unknown command %v", command) 25113-} 25114- 25115-// Commands returns the set of commands supported by the gopls tool on the 25116-// command line. 25117-// The command is specified by the first non flag argument. 25118-func (app *Application) Commands() []tool.Application { 25119- var commands []tool.Application 25120- commands = append(commands, app.mainCommands()...) 25121- commands = append(commands, app.featureCommands()...) 25122- return commands 25123-} 25124- 25125-func (app *Application) mainCommands() []tool.Application { 25126- return []tool.Application{ 25127- &app.Serve, 25128- &version{app: app}, 25129- &bug{app: app}, 25130- &help{app: app}, 25131- &apiJSON{app: app}, 25132- &licenses{app: app}, 25133- } 25134-} 25135- 25136-func (app *Application) featureCommands() []tool.Application { 25137- return []tool.Application{ 25138- &callHierarchy{app: app}, 25139- &check{app: app}, 25140- &definition{app: app}, 25141- &foldingRanges{app: app}, 25142- &format{app: app}, 25143- &highlight{app: app}, 25144- &implementation{app: app}, 25145- &imports{app: app}, 25146- newRemote(app, ""), 25147- newRemote(app, "inspect"), 25148- &links{app: app}, 25149- &prepareRename{app: app}, 25150- &references{app: app}, 25151- &rename{app: app}, 25152- &semtok{app: app}, 25153- &signature{app: app}, 25154- &suggestedFix{app: app}, 25155- &symbols{app: app}, 25156- &workspaceSymbol{app: app}, 25157- &vulncheck{app: app}, 25158- } 25159-} 25160- 25161-var ( 25162- internalMu sync.Mutex 25163- internalConnections = make(map[string]*connection) 25164-) 25165- 25166-func (app *Application) connect(ctx context.Context) (*connection, error) { 25167- switch { 25168- case app.Remote == "": 25169- connection := newConnection(app) 25170- connection.Server = lsp.NewServer(cache.NewSession(ctx, cache.New(nil), app.options), connection.Client) 25171- ctx = protocol.WithClient(ctx, connection.Client) 25172- return connection, connection.initialize(ctx, app.options) 25173- case strings.HasPrefix(app.Remote, "internal@"): 25174- internalMu.Lock() 25175- defer internalMu.Unlock() 25176- opts := source.DefaultOptions().Clone() 25177- if app.options != nil { 25178- app.options(opts) 25179- } 25180- key := fmt.Sprintf("%s %v %v %v", app.wd, opts.PreferredContentFormat, opts.HierarchicalDocumentSymbolSupport, opts.SymbolMatcher) 25181- if c := internalConnections[key]; c != nil { 25182- return c, nil 25183- } 25184- remote := app.Remote[len("internal@"):] 25185- ctx := xcontext.Detach(ctx) //TODO:a way of shutting down the internal server 25186- connection, err := app.connectRemote(ctx, remote) 25187- if err != nil { 25188- return nil, err 25189- } 25190- internalConnections[key] = connection 25191- return connection, nil 25192- default: 25193- return app.connectRemote(ctx, app.Remote) 25194- } 25195-} 25196- 25197-// CloseTestConnections terminates shared connections used in command tests. It 25198-// should only be called from tests. 25199-func CloseTestConnections(ctx context.Context) { 25200- for _, c := range internalConnections { 25201- c.Shutdown(ctx) 25202- c.Exit(ctx) 25203- } 25204-} 25205- 25206-func (app *Application) connectRemote(ctx context.Context, remote string) (*connection, error) { 25207- connection := newConnection(app) 25208- conn, err := lsprpc.ConnectToRemote(ctx, remote) 25209- if err != nil { 25210- return nil, err 25211- } 25212- stream := jsonrpc2.NewHeaderStream(conn) 25213- cc := jsonrpc2.NewConn(stream) 25214- connection.Server = protocol.ServerDispatcher(cc) 25215- ctx = protocol.WithClient(ctx, connection.Client) 25216- cc.Go(ctx, 25217- protocol.Handlers( 25218- protocol.ClientHandler(connection.Client, 25219- jsonrpc2.MethodNotFound))) 25220- return connection, connection.initialize(ctx, app.options) 25221-} 25222- 25223-var matcherString = map[source.SymbolMatcher]string{ 25224- source.SymbolFuzzy: "fuzzy", 25225- source.SymbolCaseSensitive: "caseSensitive", 25226- source.SymbolCaseInsensitive: "caseInsensitive", 25227-} 25228- 25229-func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error { 25230- params := &protocol.ParamInitialize{} 25231- params.RootURI = protocol.URIFromPath(c.Client.app.wd) 25232- params.Capabilities.Workspace.Configuration = true 25233- 25234- // Make sure to respect configured options when sending initialize request. 25235- opts := source.DefaultOptions().Clone() 25236- if options != nil { 25237- options(opts) 25238- } 25239- // If you add an additional option here, you must update the map key in connect. 25240- params.Capabilities.TextDocument.Hover = &protocol.HoverClientCapabilities{ 25241- ContentFormat: []protocol.MarkupKind{opts.PreferredContentFormat}, 25242- } 25243- params.Capabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = opts.HierarchicalDocumentSymbolSupport 25244- params.Capabilities.TextDocument.SemanticTokens = protocol.SemanticTokensClientCapabilities{} 25245- params.Capabilities.TextDocument.SemanticTokens.Formats = []protocol.TokenFormat{"relative"} 25246- params.Capabilities.TextDocument.SemanticTokens.Requests.Range.Value = true 25247- params.Capabilities.TextDocument.SemanticTokens.Requests.Full.Value = true 25248- params.Capabilities.TextDocument.SemanticTokens.TokenTypes = lsp.SemanticTypes() 25249- params.Capabilities.TextDocument.SemanticTokens.TokenModifiers = lsp.SemanticModifiers() 25250- params.InitializationOptions = map[string]interface{}{ 25251- "symbolMatcher": matcherString[opts.SymbolMatcher], 25252- } 25253- if _, err := c.Server.Initialize(ctx, params); err != nil { 25254- return err 25255- } 25256- if err := c.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil { 25257- return err 25258- } 25259- return nil 25260-} 25261- 25262-type connection struct { 25263- protocol.Server 25264- Client *cmdClient 25265-} 25266- 25267-type cmdClient struct { 25268- protocol.Server 25269- app *Application 25270- 25271- diagnosticsMu sync.Mutex 25272- diagnosticsDone chan struct{} 25273- 25274- filesMu sync.Mutex 25275- files map[span.URI]*cmdFile 25276-} 25277- 25278-type cmdFile struct { 25279- uri span.URI 25280- mapper *protocol.Mapper 25281- err error 25282- open bool 25283- diagnostics []protocol.Diagnostic 25284-} 25285- 25286-func newConnection(app *Application) *connection { 25287- return &connection{ 25288- Client: &cmdClient{ 25289- app: app, 25290- files: make(map[span.URI]*cmdFile), 25291- }, 25292- } 25293-} 25294- 25295-// fileURI converts a DocumentURI to a file:// span.URI, panicking if it's not a file. 25296-func fileURI(uri protocol.DocumentURI) span.URI { 25297- sURI := uri.SpanURI() 25298- if !sURI.IsFile() { 25299- panic(fmt.Sprintf("%q is not a file URI", uri)) 25300- } 25301- return sURI 25302-} 25303- 25304-func (c *cmdClient) CodeLensRefresh(context.Context) error { return nil } 25305- 25306-func (c *cmdClient) LogTrace(context.Context, *protocol.LogTraceParams) error { return nil } 25307- 25308-func (c *cmdClient) ShowMessage(ctx context.Context, p *protocol.ShowMessageParams) error { return nil } 25309- 25310-func (c *cmdClient) ShowMessageRequest(ctx context.Context, p *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error) { 25311- return nil, nil 25312-} 25313- 25314-func (c *cmdClient) LogMessage(ctx context.Context, p *protocol.LogMessageParams) error { 25315- switch p.Type { 25316- case protocol.Error: 25317- log.Print("Error:", p.Message) 25318- case protocol.Warning: 25319- log.Print("Warning:", p.Message) 25320- case protocol.Info: 25321- if c.app.verbose() { 25322- log.Print("Info:", p.Message) 25323- } 25324- case protocol.Log: 25325- if c.app.verbose() { 25326- log.Print("Log:", p.Message) 25327- } 25328- default: 25329- if c.app.verbose() { 25330- log.Print(p.Message) 25331- } 25332- } 25333- return nil 25334-} 25335- 25336-func (c *cmdClient) Event(ctx context.Context, t *interface{}) error { return nil } 25337- 25338-func (c *cmdClient) RegisterCapability(ctx context.Context, p *protocol.RegistrationParams) error { 25339- return nil 25340-} 25341- 25342-func (c *cmdClient) UnregisterCapability(ctx context.Context, p *protocol.UnregistrationParams) error { 25343- return nil 25344-} 25345- 25346-func (c *cmdClient) WorkspaceFolders(ctx context.Context) ([]protocol.WorkspaceFolder, error) { 25347- return nil, nil 25348-} 25349- 25350-func (c *cmdClient) Configuration(ctx context.Context, p *protocol.ParamConfiguration) ([]interface{}, error) { 25351- results := make([]interface{}, len(p.Items)) 25352- for i, item := range p.Items { 25353- if item.Section != "gopls" { 25354- continue 25355- } 25356- env := map[string]interface{}{} 25357- for _, value := range c.app.env { 25358- l := strings.SplitN(value, "=", 2) 25359- if len(l) != 2 { 25360- continue 25361- } 25362- env[l[0]] = l[1] 25363- } 25364- m := map[string]interface{}{ 25365- "env": env, 25366- "analyses": map[string]bool{ 25367- "fillreturns": true, 25368- "nonewvars": true, 25369- "noresultvalues": true, 25370- "undeclaredname": true, 25371- }, 25372- } 25373- if c.app.VeryVerbose { 25374- m["verboseOutput"] = true 25375- } 25376- results[i] = m 25377- } 25378- return results, nil 25379-} 25380- 25381-func (c *cmdClient) ApplyEdit(ctx context.Context, p *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) { 25382- return &protocol.ApplyWorkspaceEditResult{Applied: false, FailureReason: "not implemented"}, nil 25383-} 25384- 25385-func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishDiagnosticsParams) error { 25386- if p.URI == "gopls://diagnostics-done" { 25387- close(c.diagnosticsDone) 25388- } 25389- // Don't worry about diagnostics without versions. 25390- if p.Version == 0 { 25391- return nil 25392- } 25393- 25394- c.filesMu.Lock() 25395- defer c.filesMu.Unlock() 25396- 25397- file := c.getFile(ctx, fileURI(p.URI)) 25398- file.diagnostics = p.Diagnostics 25399- return nil 25400-} 25401- 25402-func (c *cmdClient) Progress(context.Context, *protocol.ProgressParams) error { 25403- return nil 25404-} 25405- 25406-func (c *cmdClient) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) { 25407- return nil, nil 25408-} 25409- 25410-func (c *cmdClient) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error { 25411- return nil 25412-} 25413- 25414-func (c *cmdClient) DiagnosticRefresh(context.Context) error { 25415- return nil 25416-} 25417- 25418-func (c *cmdClient) InlayHintRefresh(context.Context) error { 25419- return nil 25420-} 25421- 25422-func (c *cmdClient) SemanticTokensRefresh(context.Context) error { 25423- return nil 25424-} 25425- 25426-func (c *cmdClient) InlineValueRefresh(context.Context) error { 25427- return nil 25428-} 25429- 25430-func (c *cmdClient) getFile(ctx context.Context, uri span.URI) *cmdFile { 25431- file, found := c.files[uri] 25432- if !found || file.err != nil { 25433- file = &cmdFile{ 25434- uri: uri, 25435- } 25436- c.files[uri] = file 25437- } 25438- if file.mapper == nil { 25439- content, err := ioutil.ReadFile(uri.Filename()) 25440- if err != nil { 25441- file.err = fmt.Errorf("getFile: %v: %v", uri, err) 25442- return file 25443- } 25444- file.mapper = protocol.NewMapper(uri, content) 25445- } 25446- return file 25447-} 25448- 25449-func (c *cmdClient) openFile(ctx context.Context, uri span.URI) *cmdFile { 25450- c.filesMu.Lock() 25451- defer c.filesMu.Unlock() 25452- 25453- file := c.getFile(ctx, uri) 25454- if file.err != nil || file.open { 25455- return file 25456- } 25457- file.open = true 25458- return file 25459-} 25460- 25461-func (c *connection) openFile(ctx context.Context, uri span.URI) *cmdFile { 25462- file := c.Client.openFile(ctx, uri) 25463- if file.err != nil { 25464- return file 25465- } 25466- 25467- p := &protocol.DidOpenTextDocumentParams{ 25468- TextDocument: protocol.TextDocumentItem{ 25469- URI: protocol.URIFromSpanURI(uri), 25470- LanguageID: "go", 25471- Version: 1, 25472- Text: string(file.mapper.Content), 25473- }, 25474- } 25475- if err := c.Server.DidOpen(ctx, p); err != nil { 25476- file.err = fmt.Errorf("%v: %v", uri, err) 25477- } 25478- return file 25479-} 25480- 25481-func (c *connection) semanticTokens(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) { 25482- // use range to avoid limits on full 25483- resp, err := c.Server.SemanticTokensRange(ctx, p) 25484- if err != nil { 25485- return nil, err 25486- } 25487- return resp, nil 25488-} 25489- 25490-func (c *connection) diagnoseFiles(ctx context.Context, files []span.URI) error { 25491- var untypedFiles []interface{} 25492- for _, file := range files { 25493- untypedFiles = append(untypedFiles, string(file)) 25494- } 25495- c.Client.diagnosticsMu.Lock() 25496- defer c.Client.diagnosticsMu.Unlock() 25497- 25498- c.Client.diagnosticsDone = make(chan struct{}) 25499- _, err := c.Server.NonstandardRequest(ctx, "gopls/diagnoseFiles", map[string]interface{}{"files": untypedFiles}) 25500- if err != nil { 25501- close(c.Client.diagnosticsDone) 25502- return err 25503- } 25504- 25505- <-c.Client.diagnosticsDone 25506- return nil 25507-} 25508- 25509-func (c *connection) terminate(ctx context.Context) { 25510- if strings.HasPrefix(c.Client.app.Remote, "internal@") { 25511- // internal connections need to be left alive for the next test 25512- return 25513- } 25514- //TODO: do we need to handle errors on these calls? 25515- c.Shutdown(ctx) 25516- //TODO: right now calling exit terminates the process, we should rethink that 25517- //server.Exit(ctx) 25518-} 25519- 25520-// Implement io.Closer. 25521-func (c *cmdClient) Close() error { 25522- return nil 25523-} 25524diff -urN a/gopls/internal/lsp/cmd/definition.go b/gopls/internal/lsp/cmd/definition.go 25525--- a/gopls/internal/lsp/cmd/definition.go 2000-01-01 00:00:00.000000000 -0000 25526+++ b/gopls/internal/lsp/cmd/definition.go 1970-01-01 00:00:00.000000000 +0000 25527@@ -1,132 +0,0 @@ 25528-// Copyright 2019 The Go Authors. All rights reserved. 25529-// Use of this source code is governed by a BSD-style 25530-// license that can be found in the LICENSE file. 25531- 25532-package cmd 25533- 25534-import ( 25535- "context" 25536- "encoding/json" 25537- "flag" 25538- "fmt" 25539- "os" 25540- "strings" 25541- 25542- "golang.org/x/tools/gopls/internal/lsp/protocol" 25543- "golang.org/x/tools/gopls/internal/lsp/source" 25544- "golang.org/x/tools/gopls/internal/span" 25545- "golang.org/x/tools/internal/tool" 25546-) 25547- 25548-// A Definition is the result of a 'definition' query. 25549-type Definition struct { 25550- Span span.Span `json:"span"` // span of the definition 25551- Description string `json:"description"` // description of the denoted object 25552-} 25553- 25554-// These constant is printed in the help, and then used in a test to verify the 25555-// help is still valid. 25556-// They refer to "Set" in "flag.FlagSet" from the DetailedHelp method below. 25557-const ( 25558- exampleLine = 44 25559- exampleColumn = 47 25560- exampleOffset = 1270 25561-) 25562- 25563-// definition implements the definition verb for gopls. 25564-type definition struct { 25565- app *Application 25566- 25567- JSON bool `flag:"json" help:"emit output in JSON format"` 25568- MarkdownSupported bool `flag:"markdown" help:"support markdown in responses"` 25569-} 25570- 25571-func (d *definition) Name() string { return "definition" } 25572-func (d *definition) Parent() string { return d.app.Name() } 25573-func (d *definition) Usage() string { return "[definition-flags] <position>" } 25574-func (d *definition) ShortHelp() string { return "show declaration of selected identifier" } 25575-func (d *definition) DetailedHelp(f *flag.FlagSet) { 25576- fmt.Fprintf(f.Output(), ` 25577-Example: show the definition of the identifier at syntax at offset %[1]v in this file (flag.FlagSet): 25578- 25579- $ gopls definition internal/lsp/cmd/definition.go:%[1]v:%[2]v 25580- $ gopls definition internal/lsp/cmd/definition.go:#%[3]v 25581- 25582-definition-flags: 25583-`, exampleLine, exampleColumn, exampleOffset) 25584- printFlagDefaults(f) 25585-} 25586- 25587-// Run performs the definition query as specified by args and prints the 25588-// results to stdout. 25589-func (d *definition) Run(ctx context.Context, args ...string) error { 25590- if len(args) != 1 { 25591- return tool.CommandLineErrorf("definition expects 1 argument") 25592- } 25593- // Plaintext makes more sense for the command line. 25594- opts := d.app.options 25595- d.app.options = func(o *source.Options) { 25596- if opts != nil { 25597- opts(o) 25598- } 25599- o.PreferredContentFormat = protocol.PlainText 25600- if d.MarkdownSupported { 25601- o.PreferredContentFormat = protocol.Markdown 25602- } 25603- } 25604- conn, err := d.app.connect(ctx) 25605- if err != nil { 25606- return err 25607- } 25608- defer conn.terminate(ctx) 25609- from := span.Parse(args[0]) 25610- file := conn.openFile(ctx, from.URI()) 25611- if file.err != nil { 25612- return file.err 25613- } 25614- loc, err := file.mapper.SpanLocation(from) 25615- if err != nil { 25616- return err 25617- } 25618- p := protocol.DefinitionParams{ 25619- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 25620- } 25621- locs, err := conn.Definition(ctx, &p) 25622- if err != nil { 25623- return fmt.Errorf("%v: %v", from, err) 25624- } 25625- 25626- if len(locs) == 0 { 25627- return fmt.Errorf("%v: not an identifier", from) 25628- } 25629- q := protocol.HoverParams{ 25630- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 25631- } 25632- hover, err := conn.Hover(ctx, &q) 25633- if err != nil { 25634- return fmt.Errorf("%v: %v", from, err) 25635- } 25636- if hover == nil { 25637- return fmt.Errorf("%v: not an identifier", from) 25638- } 25639- file = conn.openFile(ctx, fileURI(locs[0].URI)) 25640- if file.err != nil { 25641- return fmt.Errorf("%v: %v", from, file.err) 25642- } 25643- definition, err := file.mapper.LocationSpan(locs[0]) 25644- if err != nil { 25645- return fmt.Errorf("%v: %v", from, err) 25646- } 25647- description := strings.TrimSpace(hover.Contents.Value) 25648- result := &Definition{ 25649- Span: definition, 25650- Description: description, 25651- } 25652- if d.JSON { 25653- enc := json.NewEncoder(os.Stdout) 25654- enc.SetIndent("", "\t") 25655- return enc.Encode(result) 25656- } 25657- fmt.Printf("%v: defined here as %s", result.Span, result.Description) 25658- return nil 25659-} 25660diff -urN a/gopls/internal/lsp/cmd/folding_range.go b/gopls/internal/lsp/cmd/folding_range.go 25661--- a/gopls/internal/lsp/cmd/folding_range.go 2000-01-01 00:00:00.000000000 -0000 25662+++ b/gopls/internal/lsp/cmd/folding_range.go 1970-01-01 00:00:00.000000000 +0000 25663@@ -1,73 +0,0 @@ 25664-// Copyright 2019 The Go Authors. All rights reserved. 25665-// Use of this source code is governed by a BSD-style 25666-// license that can be found in the LICENSE file. 25667- 25668-package cmd 25669- 25670-import ( 25671- "context" 25672- "flag" 25673- "fmt" 25674- 25675- "golang.org/x/tools/gopls/internal/lsp/protocol" 25676- "golang.org/x/tools/gopls/internal/span" 25677- "golang.org/x/tools/internal/tool" 25678-) 25679- 25680-// foldingRanges implements the folding_ranges verb for gopls 25681-type foldingRanges struct { 25682- app *Application 25683-} 25684- 25685-func (r *foldingRanges) Name() string { return "folding_ranges" } 25686-func (r *foldingRanges) Parent() string { return r.app.Name() } 25687-func (r *foldingRanges) Usage() string { return "<file>" } 25688-func (r *foldingRanges) ShortHelp() string { return "display selected file's folding ranges" } 25689-func (r *foldingRanges) DetailedHelp(f *flag.FlagSet) { 25690- fmt.Fprint(f.Output(), ` 25691-Example: 25692- 25693- $ gopls folding_ranges helper/helper.go 25694-`) 25695- printFlagDefaults(f) 25696-} 25697- 25698-func (r *foldingRanges) Run(ctx context.Context, args ...string) error { 25699- if len(args) != 1 { 25700- return tool.CommandLineErrorf("folding_ranges expects 1 argument (file)") 25701- } 25702- 25703- conn, err := r.app.connect(ctx) 25704- if err != nil { 25705- return err 25706- } 25707- defer conn.terminate(ctx) 25708- 25709- from := span.Parse(args[0]) 25710- file := conn.openFile(ctx, from.URI()) 25711- if file.err != nil { 25712- return file.err 25713- } 25714- 25715- p := protocol.FoldingRangeParams{ 25716- TextDocument: protocol.TextDocumentIdentifier{ 25717- URI: protocol.URIFromSpanURI(from.URI()), 25718- }, 25719- } 25720- 25721- ranges, err := conn.FoldingRange(ctx, &p) 25722- if err != nil { 25723- return err 25724- } 25725- 25726- for _, r := range ranges { 25727- fmt.Printf("%v:%v-%v:%v\n", 25728- r.StartLine+1, 25729- r.StartCharacter+1, 25730- r.EndLine+1, 25731- r.EndCharacter+1, 25732- ) 25733- } 25734- 25735- return nil 25736-} 25737diff -urN a/gopls/internal/lsp/cmd/format.go b/gopls/internal/lsp/cmd/format.go 25738--- a/gopls/internal/lsp/cmd/format.go 2000-01-01 00:00:00.000000000 -0000 25739+++ b/gopls/internal/lsp/cmd/format.go 1970-01-01 00:00:00.000000000 +0000 25740@@ -1,110 +0,0 @@ 25741-// Copyright 2019 The Go Authors. All rights reserved. 25742-// Use of this source code is governed by a BSD-style 25743-// license that can be found in the LICENSE file. 25744- 25745-package cmd 25746- 25747-import ( 25748- "context" 25749- "flag" 25750- "fmt" 25751- "io/ioutil" 25752- "os" 25753- 25754- "golang.org/x/tools/gopls/internal/lsp/protocol" 25755- "golang.org/x/tools/gopls/internal/lsp/source" 25756- "golang.org/x/tools/gopls/internal/span" 25757- "golang.org/x/tools/internal/diff" 25758-) 25759- 25760-// format implements the format verb for gopls. 25761-type format struct { 25762- Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` 25763- Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` 25764- List bool `flag:"l,list" help:"list files whose formatting differs from gofmt's"` 25765- 25766- app *Application 25767-} 25768- 25769-func (c *format) Name() string { return "format" } 25770-func (c *format) Parent() string { return c.app.Name() } 25771-func (c *format) Usage() string { return "[format-flags] <filerange>" } 25772-func (c *format) ShortHelp() string { return "format the code according to the go standard" } 25773-func (c *format) DetailedHelp(f *flag.FlagSet) { 25774- fmt.Fprint(f.Output(), ` 25775-The arguments supplied may be simple file names, or ranges within files. 25776- 25777-Example: reformat this file: 25778- 25779- $ gopls format -w internal/lsp/cmd/check.go 25780- 25781-format-flags: 25782-`) 25783- printFlagDefaults(f) 25784-} 25785- 25786-// Run performs the check on the files specified by args and prints the 25787-// results to stdout. 25788-func (c *format) Run(ctx context.Context, args ...string) error { 25789- if len(args) == 0 { 25790- // no files, so no results 25791- return nil 25792- } 25793- // now we ready to kick things off 25794- conn, err := c.app.connect(ctx) 25795- if err != nil { 25796- return err 25797- } 25798- defer conn.terminate(ctx) 25799- for _, arg := range args { 25800- spn := span.Parse(arg) 25801- file := conn.openFile(ctx, spn.URI()) 25802- if file.err != nil { 25803- return file.err 25804- } 25805- filename := spn.URI().Filename() 25806- loc, err := file.mapper.SpanLocation(spn) 25807- if err != nil { 25808- return err 25809- } 25810- if loc.Range.Start != loc.Range.End { 25811- return fmt.Errorf("only full file formatting supported") 25812- } 25813- p := protocol.DocumentFormattingParams{ 25814- TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, 25815- } 25816- edits, err := conn.Formatting(ctx, &p) 25817- if err != nil { 25818- return fmt.Errorf("%v: %v", spn, err) 25819- } 25820- formatted, sedits, err := source.ApplyProtocolEdits(file.mapper, edits) 25821- if err != nil { 25822- return fmt.Errorf("%v: %v", spn, err) 25823- } 25824- printIt := true 25825- if c.List { 25826- printIt = false 25827- if len(edits) > 0 { 25828- fmt.Println(filename) 25829- } 25830- } 25831- if c.Write { 25832- printIt = false 25833- if len(edits) > 0 { 25834- ioutil.WriteFile(filename, formatted, 0644) 25835- } 25836- } 25837- if c.Diff { 25838- printIt = false 25839- unified, err := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) 25840- if err != nil { 25841- return err 25842- } 25843- fmt.Print(unified) 25844- } 25845- if printIt { 25846- os.Stdout.Write(formatted) 25847- } 25848- } 25849- return nil 25850-} 25851diff -urN a/gopls/internal/lsp/cmd/help_test.go b/gopls/internal/lsp/cmd/help_test.go 25852--- a/gopls/internal/lsp/cmd/help_test.go 2000-01-01 00:00:00.000000000 -0000 25853+++ b/gopls/internal/lsp/cmd/help_test.go 1970-01-01 00:00:00.000000000 +0000 25854@@ -1,58 +0,0 @@ 25855-// Copyright 2019 The Go Authors. All rights reserved. 25856-// Use of this source code is governed by a BSD-style 25857-// license that can be found in the LICENSE file. 25858- 25859-package cmd_test 25860- 25861-import ( 25862- "bytes" 25863- "context" 25864- "flag" 25865- "io/ioutil" 25866- "path/filepath" 25867- "testing" 25868- 25869- "github.com/google/go-cmp/cmp" 25870- "golang.org/x/tools/gopls/internal/lsp/cmd" 25871- "golang.org/x/tools/internal/testenv" 25872- "golang.org/x/tools/internal/tool" 25873-) 25874- 25875-//go:generate go test -run Help -update-help-files 25876- 25877-var updateHelpFiles = flag.Bool("update-help-files", false, "Write out the help files instead of checking them") 25878- 25879-const appName = "gopls" 25880- 25881-func TestHelpFiles(t *testing.T) { 25882- testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code. 25883- app := cmd.New(appName, "", nil, nil) 25884- ctx := context.Background() 25885- for _, page := range append(app.Commands(), app) { 25886- t.Run(page.Name(), func(t *testing.T) { 25887- var buf bytes.Buffer 25888- s := flag.NewFlagSet(page.Name(), flag.ContinueOnError) 25889- s.SetOutput(&buf) 25890- tool.Run(ctx, s, page, []string{"-h"}) 25891- name := page.Name() 25892- if name == appName { 25893- name = "usage" 25894- } 25895- helpFile := filepath.Join("usage", name+".hlp") 25896- got := buf.Bytes() 25897- if *updateHelpFiles { 25898- if err := ioutil.WriteFile(helpFile, got, 0666); err != nil { 25899- t.Errorf("Failed writing %v: %v", helpFile, err) 25900- } 25901- return 25902- } 25903- want, err := ioutil.ReadFile(helpFile) 25904- if err != nil { 25905- t.Fatalf("Missing help file %q", helpFile) 25906- } 25907- if diff := cmp.Diff(string(want), string(got)); diff != "" { 25908- t.Errorf("Help file %q did not match, run with -update-help-files to fix (-want +got)\n%s", helpFile, diff) 25909- } 25910- }) 25911- } 25912-} 25913diff -urN a/gopls/internal/lsp/cmd/highlight.go b/gopls/internal/lsp/cmd/highlight.go 25914--- a/gopls/internal/lsp/cmd/highlight.go 2000-01-01 00:00:00.000000000 -0000 25915+++ b/gopls/internal/lsp/cmd/highlight.go 1970-01-01 00:00:00.000000000 +0000 25916@@ -1,82 +0,0 @@ 25917-// Copyright 2019 The Go Authors. All rights reserved. 25918-// Use of this source code is governed by a BSD-style 25919-// license that can be found in the LICENSE file. 25920- 25921-package cmd 25922- 25923-import ( 25924- "context" 25925- "flag" 25926- "fmt" 25927- 25928- "golang.org/x/tools/gopls/internal/lsp/protocol" 25929- "golang.org/x/tools/gopls/internal/span" 25930- "golang.org/x/tools/internal/tool" 25931-) 25932- 25933-// highlight implements the highlight verb for gopls. 25934-type highlight struct { 25935- app *Application 25936-} 25937- 25938-func (r *highlight) Name() string { return "highlight" } 25939-func (r *highlight) Parent() string { return r.app.Name() } 25940-func (r *highlight) Usage() string { return "<position>" } 25941-func (r *highlight) ShortHelp() string { return "display selected identifier's highlights" } 25942-func (r *highlight) DetailedHelp(f *flag.FlagSet) { 25943- fmt.Fprint(f.Output(), ` 25944-Example: 25945- 25946- $ # 1-indexed location (:line:column or :#offset) of the target identifier 25947- $ gopls highlight helper/helper.go:8:6 25948- $ gopls highlight helper/helper.go:#53 25949-`) 25950- printFlagDefaults(f) 25951-} 25952- 25953-func (r *highlight) Run(ctx context.Context, args ...string) error { 25954- if len(args) != 1 { 25955- return tool.CommandLineErrorf("highlight expects 1 argument (position)") 25956- } 25957- 25958- conn, err := r.app.connect(ctx) 25959- if err != nil { 25960- return err 25961- } 25962- defer conn.terminate(ctx) 25963- 25964- from := span.Parse(args[0]) 25965- file := conn.openFile(ctx, from.URI()) 25966- if file.err != nil { 25967- return file.err 25968- } 25969- 25970- loc, err := file.mapper.SpanLocation(from) 25971- if err != nil { 25972- return err 25973- } 25974- 25975- p := protocol.DocumentHighlightParams{ 25976- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 25977- } 25978- highlights, err := conn.DocumentHighlight(ctx, &p) 25979- if err != nil { 25980- return err 25981- } 25982- 25983- var results []span.Span 25984- for _, h := range highlights { 25985- s, err := file.mapper.RangeSpan(h.Range) 25986- if err != nil { 25987- return err 25988- } 25989- results = append(results, s) 25990- } 25991- // Sort results to make tests deterministic since DocumentHighlight uses a map. 25992- span.SortSpans(results) 25993- 25994- for _, s := range results { 25995- fmt.Println(s) 25996- } 25997- return nil 25998-} 25999diff -urN a/gopls/internal/lsp/cmd/implementation.go b/gopls/internal/lsp/cmd/implementation.go 26000--- a/gopls/internal/lsp/cmd/implementation.go 2000-01-01 00:00:00.000000000 -0000 26001+++ b/gopls/internal/lsp/cmd/implementation.go 1970-01-01 00:00:00.000000000 +0000 26002@@ -1,84 +0,0 @@ 26003-// Copyright 2019 The Go Authors. All rights reserved. 26004-// Use of this source code is governed by a BSD-style 26005-// license that can be found in the LICENSE file. 26006- 26007-package cmd 26008- 26009-import ( 26010- "context" 26011- "flag" 26012- "fmt" 26013- "sort" 26014- 26015- "golang.org/x/tools/gopls/internal/lsp/protocol" 26016- "golang.org/x/tools/gopls/internal/span" 26017- "golang.org/x/tools/internal/tool" 26018-) 26019- 26020-// implementation implements the implementation verb for gopls 26021-type implementation struct { 26022- app *Application 26023-} 26024- 26025-func (i *implementation) Name() string { return "implementation" } 26026-func (i *implementation) Parent() string { return i.app.Name() } 26027-func (i *implementation) Usage() string { return "<position>" } 26028-func (i *implementation) ShortHelp() string { return "display selected identifier's implementation" } 26029-func (i *implementation) DetailedHelp(f *flag.FlagSet) { 26030- fmt.Fprint(f.Output(), ` 26031-Example: 26032- 26033- $ # 1-indexed location (:line:column or :#offset) of the target identifier 26034- $ gopls implementation helper/helper.go:8:6 26035- $ gopls implementation helper/helper.go:#53 26036-`) 26037- printFlagDefaults(f) 26038-} 26039- 26040-func (i *implementation) Run(ctx context.Context, args ...string) error { 26041- if len(args) != 1 { 26042- return tool.CommandLineErrorf("implementation expects 1 argument (position)") 26043- } 26044- 26045- conn, err := i.app.connect(ctx) 26046- if err != nil { 26047- return err 26048- } 26049- defer conn.terminate(ctx) 26050- 26051- from := span.Parse(args[0]) 26052- file := conn.openFile(ctx, from.URI()) 26053- if file.err != nil { 26054- return file.err 26055- } 26056- 26057- loc, err := file.mapper.SpanLocation(from) 26058- if err != nil { 26059- return err 26060- } 26061- 26062- p := protocol.ImplementationParams{ 26063- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 26064- } 26065- implementations, err := conn.Implementation(ctx, &p) 26066- if err != nil { 26067- return err 26068- } 26069- 26070- var spans []string 26071- for _, impl := range implementations { 26072- f := conn.openFile(ctx, fileURI(impl.URI)) 26073- span, err := f.mapper.LocationSpan(impl) 26074- if err != nil { 26075- return err 26076- } 26077- spans = append(spans, fmt.Sprint(span)) 26078- } 26079- sort.Strings(spans) 26080- 26081- for _, s := range spans { 26082- fmt.Println(s) 26083- } 26084- 26085- return nil 26086-} 26087diff -urN a/gopls/internal/lsp/cmd/imports.go b/gopls/internal/lsp/cmd/imports.go 26088--- a/gopls/internal/lsp/cmd/imports.go 2000-01-01 00:00:00.000000000 -0000 26089+++ b/gopls/internal/lsp/cmd/imports.go 1970-01-01 00:00:00.000000000 +0000 26090@@ -1,105 +0,0 @@ 26091-// Copyright 2019 The Go Authors. All rights reserved. 26092-// Use of this source code is governed by a BSD-style 26093-// license that can be found in the LICENSE file. 26094- 26095-package cmd 26096- 26097-import ( 26098- "context" 26099- "flag" 26100- "fmt" 26101- "io/ioutil" 26102- "os" 26103- 26104- "golang.org/x/tools/gopls/internal/lsp/protocol" 26105- "golang.org/x/tools/gopls/internal/lsp/source" 26106- "golang.org/x/tools/gopls/internal/span" 26107- "golang.org/x/tools/internal/diff" 26108- "golang.org/x/tools/internal/tool" 26109-) 26110- 26111-// imports implements the import verb for gopls. 26112-type imports struct { 26113- Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` 26114- Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` 26115- 26116- app *Application 26117-} 26118- 26119-func (t *imports) Name() string { return "imports" } 26120-func (t *imports) Parent() string { return t.app.Name() } 26121-func (t *imports) Usage() string { return "[imports-flags] <filename>" } 26122-func (t *imports) ShortHelp() string { return "updates import statements" } 26123-func (t *imports) DetailedHelp(f *flag.FlagSet) { 26124- fmt.Fprintf(f.Output(), ` 26125-Example: update imports statements in a file: 26126- 26127- $ gopls imports -w internal/lsp/cmd/check.go 26128- 26129-imports-flags: 26130-`) 26131- printFlagDefaults(f) 26132-} 26133- 26134-// Run performs diagnostic checks on the file specified and either; 26135-// - if -w is specified, updates the file in place; 26136-// - if -d is specified, prints out unified diffs of the changes; or 26137-// - otherwise, prints the new versions to stdout. 26138-func (t *imports) Run(ctx context.Context, args ...string) error { 26139- if len(args) != 1 { 26140- return tool.CommandLineErrorf("imports expects 1 argument") 26141- } 26142- conn, err := t.app.connect(ctx) 26143- if err != nil { 26144- return err 26145- } 26146- defer conn.terminate(ctx) 26147- 26148- from := span.Parse(args[0]) 26149- uri := from.URI() 26150- file := conn.openFile(ctx, uri) 26151- if file.err != nil { 26152- return file.err 26153- } 26154- actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{ 26155- TextDocument: protocol.TextDocumentIdentifier{ 26156- URI: protocol.URIFromSpanURI(uri), 26157- }, 26158- }) 26159- if err != nil { 26160- return fmt.Errorf("%v: %v", from, err) 26161- } 26162- var edits []protocol.TextEdit 26163- for _, a := range actions { 26164- if a.Title != "Organize Imports" { 26165- continue 26166- } 26167- for _, c := range a.Edit.DocumentChanges { 26168- if c.TextDocumentEdit != nil { 26169- if fileURI(c.TextDocumentEdit.TextDocument.URI) == uri { 26170- edits = append(edits, c.TextDocumentEdit.Edits...) 26171- } 26172- } 26173- } 26174- } 26175- newContent, sedits, err := source.ApplyProtocolEdits(file.mapper, edits) 26176- if err != nil { 26177- return fmt.Errorf("%v: %v", edits, err) 26178- } 26179- filename := file.uri.Filename() 26180- switch { 26181- case t.Write: 26182- if len(edits) > 0 { 26183- ioutil.WriteFile(filename, newContent, 0644) 26184- } 26185- case t.Diff: 26186- unified, err := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) 26187- if err != nil { 26188- return err 26189- } 26190- fmt.Print(unified) 26191- default: 26192- os.Stdout.Write(newContent) 26193- } 26194- return nil 26195-} 26196diff -urN a/gopls/internal/lsp/cmd/info.go b/gopls/internal/lsp/cmd/info.go 26197--- a/gopls/internal/lsp/cmd/info.go 2000-01-01 00:00:00.000000000 -0000 26198+++ b/gopls/internal/lsp/cmd/info.go 1970-01-01 00:00:00.000000000 +0000 26199@@ -1,246 +0,0 @@ 26200-// Copyright 2019 The Go Authors. All rights reserved. 26201-// Use of this source code is governed by a BSD-style 26202-// license that can be found in the LICENSE file. 26203- 26204-package cmd 26205- 26206-import ( 26207- "bytes" 26208- "context" 26209- "encoding/json" 26210- "flag" 26211- "fmt" 26212- "net/url" 26213- "os" 26214- "strings" 26215- 26216- "golang.org/x/tools/gopls/internal/lsp/browser" 26217- "golang.org/x/tools/gopls/internal/lsp/debug" 26218- "golang.org/x/tools/gopls/internal/lsp/source" 26219- "golang.org/x/tools/internal/tool" 26220-) 26221- 26222-// help implements the help command. 26223-type help struct { 26224- app *Application 26225-} 26226- 26227-func (h *help) Name() string { return "help" } 26228-func (h *help) Parent() string { return h.app.Name() } 26229-func (h *help) Usage() string { return "" } 26230-func (h *help) ShortHelp() string { return "print usage information for subcommands" } 26231-func (h *help) DetailedHelp(f *flag.FlagSet) { 26232- fmt.Fprint(f.Output(), ` 26233- 26234-Examples: 26235-$ gopls help # main gopls help message 26236-$ gopls help remote # help on 'remote' command 26237-$ gopls help remote sessions # help on 'remote sessions' subcommand 26238-`) 26239- printFlagDefaults(f) 26240-} 26241- 26242-// Run prints help information about a subcommand. 26243-func (h *help) Run(ctx context.Context, args ...string) error { 26244- find := func(cmds []tool.Application, name string) tool.Application { 26245- for _, cmd := range cmds { 26246- if cmd.Name() == name { 26247- return cmd 26248- } 26249- } 26250- return nil 26251- } 26252- 26253- // Find the subcommand denoted by args (empty => h.app). 26254- var cmd tool.Application = h.app 26255- for i, arg := range args { 26256- cmd = find(getSubcommands(cmd), arg) 26257- if cmd == nil { 26258- return tool.CommandLineErrorf( 26259- "no such subcommand: %s", strings.Join(args[:i+1], " ")) 26260- } 26261- } 26262- 26263- // 'gopls help cmd subcmd' is equivalent to 'gopls cmd subcmd -h'. 26264- // The flag package prints the usage information (defined by tool.Run) 26265- // when it sees the -h flag. 26266- fs := flag.NewFlagSet(cmd.Name(), flag.ExitOnError) 26267- return tool.Run(ctx, fs, h.app, append(args[:len(args):len(args)], "-h")) 26268-} 26269- 26270-// version implements the version command. 26271-type version struct { 26272- JSON bool `flag:"json" help:"outputs in json format."` 26273- 26274- app *Application 26275-} 26276- 26277-func (v *version) Name() string { return "version" } 26278-func (v *version) Parent() string { return v.app.Name() } 26279-func (v *version) Usage() string { return "" } 26280-func (v *version) ShortHelp() string { return "print the gopls version information" } 26281-func (v *version) DetailedHelp(f *flag.FlagSet) { 26282- fmt.Fprint(f.Output(), ``) 26283- printFlagDefaults(f) 26284-} 26285- 26286-// Run prints version information to stdout. 26287-func (v *version) Run(ctx context.Context, args ...string) error { 26288- var mode = debug.PlainText 26289- if v.JSON { 26290- mode = debug.JSON 26291- } 26292- 26293- return debug.PrintVersionInfo(ctx, os.Stdout, v.app.verbose(), mode) 26294-} 26295- 26296-// bug implements the bug command. 26297-type bug struct { 26298- app *Application 26299-} 26300- 26301-func (b *bug) Name() string { return "bug" } 26302-func (b *bug) Parent() string { return b.app.Name() } 26303-func (b *bug) Usage() string { return "" } 26304-func (b *bug) ShortHelp() string { return "report a bug in gopls" } 26305-func (b *bug) DetailedHelp(f *flag.FlagSet) { 26306- fmt.Fprint(f.Output(), ``) 26307- printFlagDefaults(f) 26308-} 26309- 26310-const goplsBugPrefix = "x/tools/gopls: <DESCRIBE THE PROBLEM>" 26311-const goplsBugHeader = `ATTENTION: Please answer these questions BEFORE submitting your issue. Thanks! 26312- 26313-#### What did you do? 26314-If possible, provide a recipe for reproducing the error. 26315-A complete runnable program is good. 26316-A link on play.golang.org is better. 26317-A failing unit test is the best. 26318- 26319-#### What did you expect to see? 26320- 26321- 26322-#### What did you see instead? 26323- 26324- 26325-` 26326- 26327-// Run collects some basic information and then prepares an issue ready to 26328-// be reported. 26329-func (b *bug) Run(ctx context.Context, args ...string) error { 26330- buf := &bytes.Buffer{} 26331- fmt.Fprint(buf, goplsBugHeader) 26332- debug.PrintVersionInfo(ctx, buf, true, debug.Markdown) 26333- body := buf.String() 26334- title := strings.Join(args, " ") 26335- if !strings.HasPrefix(title, goplsBugPrefix) { 26336- title = goplsBugPrefix + title 26337- } 26338- if !browser.Open("https://github.com/golang/go/issues/new?title=" + url.QueryEscape(title) + "&body=" + url.QueryEscape(body)) { 26339- fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n") 26340- fmt.Print(body) 26341- } 26342- return nil 26343-} 26344- 26345-type apiJSON struct { 26346- app *Application 26347-} 26348- 26349-func (j *apiJSON) Name() string { return "api-json" } 26350-func (j *apiJSON) Parent() string { return j.app.Name() } 26351-func (j *apiJSON) Usage() string { return "" } 26352-func (j *apiJSON) ShortHelp() string { return "print json describing gopls API" } 26353-func (j *apiJSON) DetailedHelp(f *flag.FlagSet) { 26354- fmt.Fprint(f.Output(), ``) 26355- printFlagDefaults(f) 26356-} 26357- 26358-func (j *apiJSON) Run(ctx context.Context, args ...string) error { 26359- js, err := json.MarshalIndent(source.GeneratedAPIJSON, "", "\t") 26360- if err != nil { 26361- return err 26362- } 26363- fmt.Fprint(os.Stdout, string(js)) 26364- return nil 26365-} 26366- 26367-type licenses struct { 26368- app *Application 26369-} 26370- 26371-func (l *licenses) Name() string { return "licenses" } 26372-func (l *licenses) Parent() string { return l.app.Name() } 26373-func (l *licenses) Usage() string { return "" } 26374-func (l *licenses) ShortHelp() string { return "print licenses of included software" } 26375-func (l *licenses) DetailedHelp(f *flag.FlagSet) { 26376- fmt.Fprint(f.Output(), ``) 26377- printFlagDefaults(f) 26378-} 26379- 26380-const licensePreamble = ` 26381-gopls is made available under the following BSD-style license: 26382- 26383-Copyright (c) 2009 The Go Authors. All rights reserved. 26384- 26385-Redistribution and use in source and binary forms, with or without 26386-modification, are permitted provided that the following conditions are 26387-met: 26388- 26389- * Redistributions of source code must retain the above copyright 26390-notice, this list of conditions and the following disclaimer. 26391- * Redistributions in binary form must reproduce the above 26392-copyright notice, this list of conditions and the following disclaimer 26393-in the documentation and/or other materials provided with the 26394-distribution. 26395- * Neither the name of Google Inc. nor the names of its 26396-contributors may be used to endorse or promote products derived from 26397-this software without specific prior written permission. 26398- 26399-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26400-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26401-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26402-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26403-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26404-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26405-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26406-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26407-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26408-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26409-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26410- 26411-gopls implements the LSP specification, which is made available under the following license: 26412- 26413-Copyright (c) Microsoft Corporation 26414- 26415-All rights reserved. 26416- 26417-MIT License 26418- 26419-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 26420-files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 26421-modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 26422-is furnished to do so, subject to the following conditions: 26423- 26424-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 26425- 26426-THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 26427-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 26428-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 26429-OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26430- 26431-gopls also includes software made available under these licenses: 26432-` 26433- 26434-func (l *licenses) Run(ctx context.Context, args ...string) error { 26435- opts := source.DefaultOptions() 26436- l.app.options(opts) 26437- txt := licensePreamble 26438- if opts.LicensesText == "" { 26439- txt += "(development gopls, license information not available)" 26440- } else { 26441- txt += opts.LicensesText 26442- } 26443- fmt.Fprint(os.Stdout, txt) 26444- return nil 26445-} 26446diff -urN a/gopls/internal/lsp/cmd/links.go b/gopls/internal/lsp/cmd/links.go 26447--- a/gopls/internal/lsp/cmd/links.go 2000-01-01 00:00:00.000000000 -0000 26448+++ b/gopls/internal/lsp/cmd/links.go 1970-01-01 00:00:00.000000000 +0000 26449@@ -1,77 +0,0 @@ 26450-// Copyright 2019 The Go Authors. All rights reserved. 26451-// Use of this source code is governed by a BSD-style 26452-// license that can be found in the LICENSE file. 26453- 26454-package cmd 26455- 26456-import ( 26457- "context" 26458- "encoding/json" 26459- "flag" 26460- "fmt" 26461- "os" 26462- 26463- "golang.org/x/tools/gopls/internal/lsp/protocol" 26464- "golang.org/x/tools/gopls/internal/span" 26465- "golang.org/x/tools/internal/tool" 26466-) 26467- 26468-// links implements the links verb for gopls. 26469-type links struct { 26470- JSON bool `flag:"json" help:"emit document links in JSON format"` 26471- 26472- app *Application 26473-} 26474- 26475-func (l *links) Name() string { return "links" } 26476-func (l *links) Parent() string { return l.app.Name() } 26477-func (l *links) Usage() string { return "[links-flags] <filename>" } 26478-func (l *links) ShortHelp() string { return "list links in a file" } 26479-func (l *links) DetailedHelp(f *flag.FlagSet) { 26480- fmt.Fprintf(f.Output(), ` 26481-Example: list links contained within a file: 26482- 26483- $ gopls links internal/lsp/cmd/check.go 26484- 26485-links-flags: 26486-`) 26487- printFlagDefaults(f) 26488-} 26489- 26490-// Run finds all the links within a document 26491-// - if -json is specified, outputs location range and uri 26492-// - otherwise, prints the a list of unique links 26493-func (l *links) Run(ctx context.Context, args ...string) error { 26494- if len(args) != 1 { 26495- return tool.CommandLineErrorf("links expects 1 argument") 26496- } 26497- conn, err := l.app.connect(ctx) 26498- if err != nil { 26499- return err 26500- } 26501- defer conn.terminate(ctx) 26502- 26503- from := span.Parse(args[0]) 26504- uri := from.URI() 26505- file := conn.openFile(ctx, uri) 26506- if file.err != nil { 26507- return file.err 26508- } 26509- results, err := conn.DocumentLink(ctx, &protocol.DocumentLinkParams{ 26510- TextDocument: protocol.TextDocumentIdentifier{ 26511- URI: protocol.URIFromSpanURI(uri), 26512- }, 26513- }) 26514- if err != nil { 26515- return fmt.Errorf("%v: %v", from, err) 26516- } 26517- if l.JSON { 26518- enc := json.NewEncoder(os.Stdout) 26519- enc.SetIndent("", "\t") 26520- return enc.Encode(results) 26521- } 26522- for _, v := range results { 26523- fmt.Println(v.Target) 26524- } 26525- return nil 26526-} 26527diff -urN a/gopls/internal/lsp/cmd/prepare_rename.go b/gopls/internal/lsp/cmd/prepare_rename.go 26528--- a/gopls/internal/lsp/cmd/prepare_rename.go 2000-01-01 00:00:00.000000000 -0000 26529+++ b/gopls/internal/lsp/cmd/prepare_rename.go 1970-01-01 00:00:00.000000000 +0000 26530@@ -1,80 +0,0 @@ 26531-// Copyright 2019 The Go Authors. All rights reserved. 26532-// Use of this source code is governed by a BSD-style 26533-// license that can be found in the LICENSE file. 26534- 26535-package cmd 26536- 26537-import ( 26538- "context" 26539- "errors" 26540- "flag" 26541- "fmt" 26542- 26543- "golang.org/x/tools/gopls/internal/lsp/protocol" 26544- "golang.org/x/tools/gopls/internal/span" 26545- "golang.org/x/tools/internal/tool" 26546-) 26547- 26548-// prepareRename implements the prepare_rename verb for gopls. 26549-type prepareRename struct { 26550- app *Application 26551-} 26552- 26553-func (r *prepareRename) Name() string { return "prepare_rename" } 26554-func (r *prepareRename) Parent() string { return r.app.Name() } 26555-func (r *prepareRename) Usage() string { return "<position>" } 26556-func (r *prepareRename) ShortHelp() string { return "test validity of a rename operation at location" } 26557-func (r *prepareRename) DetailedHelp(f *flag.FlagSet) { 26558- fmt.Fprint(f.Output(), ` 26559-Example: 26560- 26561- $ # 1-indexed location (:line:column or :#offset) of the target identifier 26562- $ gopls prepare_rename helper/helper.go:8:6 26563- $ gopls prepare_rename helper/helper.go:#53 26564-`) 26565- printFlagDefaults(f) 26566-} 26567- 26568-// ErrInvalidRenamePosition is returned when prepareRename is run at a position that 26569-// is not a candidate for renaming. 26570-var ErrInvalidRenamePosition = errors.New("request is not valid at the given position") 26571- 26572-func (r *prepareRename) Run(ctx context.Context, args ...string) error { 26573- if len(args) != 1 { 26574- return tool.CommandLineErrorf("prepare_rename expects 1 argument (file)") 26575- } 26576- 26577- conn, err := r.app.connect(ctx) 26578- if err != nil { 26579- return err 26580- } 26581- defer conn.terminate(ctx) 26582- 26583- from := span.Parse(args[0]) 26584- file := conn.openFile(ctx, from.URI()) 26585- if file.err != nil { 26586- return file.err 26587- } 26588- loc, err := file.mapper.SpanLocation(from) 26589- if err != nil { 26590- return err 26591- } 26592- p := protocol.PrepareRenameParams{ 26593- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 26594- } 26595- result, err := conn.PrepareRename(ctx, &p) 26596- if err != nil { 26597- return fmt.Errorf("prepare_rename failed: %w", err) 26598- } 26599- if result == nil { 26600- return ErrInvalidRenamePosition 26601- } 26602- 26603- s, err := file.mapper.RangeSpan(result.Range) 26604- if err != nil { 26605- return err 26606- } 26607- 26608- fmt.Println(s) 26609- return nil 26610-} 26611diff -urN a/gopls/internal/lsp/cmd/references.go b/gopls/internal/lsp/cmd/references.go 26612--- a/gopls/internal/lsp/cmd/references.go 2000-01-01 00:00:00.000000000 -0000 26613+++ b/gopls/internal/lsp/cmd/references.go 1970-01-01 00:00:00.000000000 +0000 26614@@ -1,89 +0,0 @@ 26615-// Copyright 2019 The Go Authors. All rights reserved. 26616-// Use of this source code is governed by a BSD-style 26617-// license that can be found in the LICENSE file. 26618- 26619-package cmd 26620- 26621-import ( 26622- "context" 26623- "flag" 26624- "fmt" 26625- "sort" 26626- 26627- "golang.org/x/tools/gopls/internal/lsp/protocol" 26628- "golang.org/x/tools/gopls/internal/span" 26629- "golang.org/x/tools/internal/tool" 26630-) 26631- 26632-// references implements the references verb for gopls 26633-type references struct { 26634- IncludeDeclaration bool `flag:"d,declaration" help:"include the declaration of the specified identifier in the results"` 26635- 26636- app *Application 26637-} 26638- 26639-func (r *references) Name() string { return "references" } 26640-func (r *references) Parent() string { return r.app.Name() } 26641-func (r *references) Usage() string { return "[references-flags] <position>" } 26642-func (r *references) ShortHelp() string { return "display selected identifier's references" } 26643-func (r *references) DetailedHelp(f *flag.FlagSet) { 26644- fmt.Fprint(f.Output(), ` 26645-Example: 26646- 26647- $ # 1-indexed location (:line:column or :#offset) of the target identifier 26648- $ gopls references helper/helper.go:8:6 26649- $ gopls references helper/helper.go:#53 26650- 26651-references-flags: 26652-`) 26653- printFlagDefaults(f) 26654-} 26655- 26656-func (r *references) Run(ctx context.Context, args ...string) error { 26657- if len(args) != 1 { 26658- return tool.CommandLineErrorf("references expects 1 argument (position)") 26659- } 26660- 26661- conn, err := r.app.connect(ctx) 26662- if err != nil { 26663- return err 26664- } 26665- defer conn.terminate(ctx) 26666- 26667- from := span.Parse(args[0]) 26668- file := conn.openFile(ctx, from.URI()) 26669- if file.err != nil { 26670- return file.err 26671- } 26672- loc, err := file.mapper.SpanLocation(from) 26673- if err != nil { 26674- return err 26675- } 26676- p := protocol.ReferenceParams{ 26677- Context: protocol.ReferenceContext{ 26678- IncludeDeclaration: r.IncludeDeclaration, 26679- }, 26680- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 26681- } 26682- locations, err := conn.References(ctx, &p) 26683- if err != nil { 26684- return err 26685- } 26686- var spans []string 26687- for _, l := range locations { 26688- f := conn.openFile(ctx, fileURI(l.URI)) 26689- // convert location to span for user-friendly 1-indexed line 26690- // and column numbers 26691- span, err := f.mapper.LocationSpan(l) 26692- if err != nil { 26693- return err 26694- } 26695- spans = append(spans, fmt.Sprint(span)) 26696- } 26697- 26698- sort.Strings(spans) 26699- for _, s := range spans { 26700- fmt.Println(s) 26701- } 26702- return nil 26703-} 26704diff -urN a/gopls/internal/lsp/cmd/remote.go b/gopls/internal/lsp/cmd/remote.go 26705--- a/gopls/internal/lsp/cmd/remote.go 2000-01-01 00:00:00.000000000 -0000 26706+++ b/gopls/internal/lsp/cmd/remote.go 1970-01-01 00:00:00.000000000 +0000 26707@@ -1,164 +0,0 @@ 26708-// Copyright 2020 The Go Authors. All rights reserved. 26709-// Use of this source code is governed by a BSD-style 26710-// license that can be found in the LICENSE file. 26711- 26712-package cmd 26713- 26714-import ( 26715- "context" 26716- "encoding/json" 26717- "errors" 26718- "flag" 26719- "fmt" 26720- "log" 26721- "os" 26722- 26723- "golang.org/x/tools/gopls/internal/lsp/command" 26724- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 26725-) 26726- 26727-type remote struct { 26728- app *Application 26729- subcommands 26730- 26731- // For backward compatibility, allow aliasing this command (it was previously 26732- // called 'inspect'). 26733- // 26734- // TODO(rFindley): delete this after allowing some transition time in case 26735- // there were any users of 'inspect' (I suspect not). 26736- alias string 26737-} 26738- 26739-func newRemote(app *Application, alias string) *remote { 26740- return &remote{ 26741- app: app, 26742- subcommands: subcommands{ 26743- &listSessions{app: app}, 26744- &startDebugging{app: app}, 26745- }, 26746- alias: alias, 26747- } 26748-} 26749- 26750-func (r *remote) Name() string { 26751- if r.alias != "" { 26752- return r.alias 26753- } 26754- return "remote" 26755-} 26756- 26757-func (r *remote) Parent() string { return r.app.Name() } 26758- 26759-func (r *remote) ShortHelp() string { 26760- short := "interact with the gopls daemon" 26761- if r.alias != "" { 26762- short += " (deprecated: use 'remote')" 26763- } 26764- return short 26765-} 26766- 26767-// listSessions is an inspect subcommand to list current sessions. 26768-type listSessions struct { 26769- app *Application 26770-} 26771- 26772-func (c *listSessions) Name() string { return "sessions" } 26773-func (c *listSessions) Parent() string { return c.app.Name() } 26774-func (c *listSessions) Usage() string { return "" } 26775-func (c *listSessions) ShortHelp() string { 26776- return "print information about current gopls sessions" 26777-} 26778- 26779-const listSessionsExamples = ` 26780-Examples: 26781- 26782-1) list sessions for the default daemon: 26783- 26784-$ gopls -remote=auto remote sessions 26785-or just 26786-$ gopls remote sessions 26787- 26788-2) list sessions for a specific daemon: 26789- 26790-$ gopls -remote=localhost:8082 remote sessions 26791-` 26792- 26793-func (c *listSessions) DetailedHelp(f *flag.FlagSet) { 26794- fmt.Fprint(f.Output(), listSessionsExamples) 26795- printFlagDefaults(f) 26796-} 26797- 26798-func (c *listSessions) Run(ctx context.Context, args ...string) error { 26799- remote := c.app.Remote 26800- if remote == "" { 26801- remote = "auto" 26802- } 26803- state, err := lsprpc.QueryServerState(ctx, remote) 26804- if err != nil { 26805- return err 26806- } 26807- v, err := json.MarshalIndent(state, "", "\t") 26808- if err != nil { 26809- log.Fatal(err) 26810- } 26811- os.Stdout.Write(v) 26812- return nil 26813-} 26814- 26815-type startDebugging struct { 26816- app *Application 26817-} 26818- 26819-func (c *startDebugging) Name() string { return "debug" } 26820-func (c *startDebugging) Usage() string { return "[host:port]" } 26821-func (c *startDebugging) ShortHelp() string { 26822- return "start the debug server" 26823-} 26824- 26825-const startDebuggingExamples = ` 26826-Examples: 26827- 26828-1) start a debug server for the default daemon, on an arbitrary port: 26829- 26830-$ gopls -remote=auto remote debug 26831-or just 26832-$ gopls remote debug 26833- 26834-2) start for a specific daemon, on a specific port: 26835- 26836-$ gopls -remote=localhost:8082 remote debug localhost:8083 26837-` 26838- 26839-func (c *startDebugging) DetailedHelp(f *flag.FlagSet) { 26840- fmt.Fprint(f.Output(), startDebuggingExamples) 26841- printFlagDefaults(f) 26842-} 26843- 26844-func (c *startDebugging) Run(ctx context.Context, args ...string) error { 26845- if len(args) > 1 { 26846- fmt.Fprintln(os.Stderr, c.Usage()) 26847- return errors.New("invalid usage") 26848- } 26849- remote := c.app.Remote 26850- if remote == "" { 26851- remote = "auto" 26852- } 26853- debugAddr := "" 26854- if len(args) > 0 { 26855- debugAddr = args[0] 26856- } 26857- debugArgs := command.DebuggingArgs{ 26858- Addr: debugAddr, 26859- } 26860- var result command.DebuggingResult 26861- if err := lsprpc.ExecuteCommand(ctx, remote, command.StartDebugging.ID(), debugArgs, &result); err != nil { 26862- return err 26863- } 26864- if len(result.URLs) == 0 { 26865- return errors.New("no debugging URLs") 26866- } 26867- for _, url := range result.URLs { 26868- fmt.Printf("debugging on %s\n", url) 26869- } 26870- return nil 26871-} 26872diff -urN a/gopls/internal/lsp/cmd/rename.go b/gopls/internal/lsp/cmd/rename.go 26873--- a/gopls/internal/lsp/cmd/rename.go 2000-01-01 00:00:00.000000000 -0000 26874+++ b/gopls/internal/lsp/cmd/rename.go 1970-01-01 00:00:00.000000000 +0000 26875@@ -1,130 +0,0 @@ 26876-// Copyright 2019 The Go Authors. All rights reserved. 26877-// Use of this source code is governed by a BSD-style 26878-// license that can be found in the LICENSE file. 26879- 26880-package cmd 26881- 26882-import ( 26883- "context" 26884- "flag" 26885- "fmt" 26886- "io/ioutil" 26887- "os" 26888- "path/filepath" 26889- "sort" 26890- 26891- "golang.org/x/tools/gopls/internal/lsp/protocol" 26892- "golang.org/x/tools/gopls/internal/lsp/source" 26893- "golang.org/x/tools/gopls/internal/span" 26894- "golang.org/x/tools/internal/diff" 26895- "golang.org/x/tools/internal/tool" 26896-) 26897- 26898-// rename implements the rename verb for gopls. 26899-type rename struct { 26900- Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` 26901- Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` 26902- Preserve bool `flag:"preserve" help:"preserve original files"` 26903- 26904- app *Application 26905-} 26906- 26907-func (r *rename) Name() string { return "rename" } 26908-func (r *rename) Parent() string { return r.app.Name() } 26909-func (r *rename) Usage() string { return "[rename-flags] <position> <name>" } 26910-func (r *rename) ShortHelp() string { return "rename selected identifier" } 26911-func (r *rename) DetailedHelp(f *flag.FlagSet) { 26912- fmt.Fprint(f.Output(), ` 26913-Example: 26914- 26915- $ # 1-based location (:line:column or :#position) of the thing to change 26916- $ gopls rename helper/helper.go:8:6 Foo 26917- $ gopls rename helper/helper.go:#53 Foo 26918- 26919-rename-flags: 26920-`) 26921- printFlagDefaults(f) 26922-} 26923- 26924-// Run renames the specified identifier and either; 26925-// - if -w is specified, updates the file(s) in place; 26926-// - if -d is specified, prints out unified diffs of the changes; or 26927-// - otherwise, prints the new versions to stdout. 26928-func (r *rename) Run(ctx context.Context, args ...string) error { 26929- if len(args) != 2 { 26930- return tool.CommandLineErrorf("definition expects 2 arguments (position, new name)") 26931- } 26932- conn, err := r.app.connect(ctx) 26933- if err != nil { 26934- return err 26935- } 26936- defer conn.terminate(ctx) 26937- 26938- from := span.Parse(args[0]) 26939- file := conn.openFile(ctx, from.URI()) 26940- if file.err != nil { 26941- return file.err 26942- } 26943- loc, err := file.mapper.SpanLocation(from) 26944- if err != nil { 26945- return err 26946- } 26947- p := protocol.RenameParams{ 26948- TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, 26949- Position: loc.Range.Start, 26950- NewName: args[1], 26951- } 26952- edit, err := conn.Rename(ctx, &p) 26953- if err != nil { 26954- return err 26955- } 26956- var orderedURIs []string 26957- edits := map[span.URI][]protocol.TextEdit{} 26958- for _, c := range edit.DocumentChanges { 26959- if c.TextDocumentEdit != nil { 26960- uri := fileURI(c.TextDocumentEdit.TextDocument.URI) 26961- edits[uri] = append(edits[uri], c.TextDocumentEdit.Edits...) 26962- orderedURIs = append(orderedURIs, string(uri)) 26963- } 26964- } 26965- sort.Strings(orderedURIs) 26966- changeCount := len(orderedURIs) 26967- 26968- for _, u := range orderedURIs { 26969- uri := span.URIFromURI(u) 26970- cmdFile := conn.openFile(ctx, uri) 26971- filename := cmdFile.uri.Filename() 26972- 26973- newContent, renameEdits, err := source.ApplyProtocolEdits(cmdFile.mapper, edits[uri]) 26974- if err != nil { 26975- return fmt.Errorf("%v: %v", edits, err) 26976- } 26977- 26978- switch { 26979- case r.Write: 26980- fmt.Fprintln(os.Stderr, filename) 26981- if r.Preserve { 26982- if err := os.Rename(filename, filename+".orig"); err != nil { 26983- return fmt.Errorf("%v: %v", edits, err) 26984- } 26985- } 26986- ioutil.WriteFile(filename, newContent, 0644) 26987- case r.Diff: 26988- unified, err := diff.ToUnified(filename+".orig", filename, string(cmdFile.mapper.Content), renameEdits) 26989- if err != nil { 26990- return err 26991- } 26992- fmt.Print(unified) 26993- default: 26994- if len(orderedURIs) > 1 { 26995- fmt.Printf("%s:\n", filepath.Base(filename)) 26996- } 26997- os.Stdout.Write(newContent) 26998- if changeCount > 1 { // if this wasn't last change, print newline 26999- fmt.Println() 27000- } 27001- changeCount -= 1 27002- } 27003- } 27004- return nil 27005-} 27006diff -urN a/gopls/internal/lsp/cmd/semantictokens.go b/gopls/internal/lsp/cmd/semantictokens.go 27007--- a/gopls/internal/lsp/cmd/semantictokens.go 2000-01-01 00:00:00.000000000 -0000 27008+++ b/gopls/internal/lsp/cmd/semantictokens.go 1970-01-01 00:00:00.000000000 +0000 27009@@ -1,225 +0,0 @@ 27010-// Copyright 2020 The Go Authors. All rights reserved. 27011-// Use of this source code is governed by a BSD-style 27012-// license that can be found in the LICENSE file. 27013- 27014-package cmd 27015- 27016-import ( 27017- "bytes" 27018- "context" 27019- "flag" 27020- "fmt" 27021- "go/parser" 27022- "go/token" 27023- "io/ioutil" 27024- "log" 27025- "os" 27026- "unicode/utf8" 27027- 27028- "golang.org/x/tools/gopls/internal/lsp" 27029- "golang.org/x/tools/gopls/internal/lsp/protocol" 27030- "golang.org/x/tools/gopls/internal/lsp/source" 27031- "golang.org/x/tools/gopls/internal/span" 27032-) 27033- 27034-// generate semantic tokens and interpolate them in the file 27035- 27036-// The output is the input file decorated with comments showing the 27037-// syntactic tokens. The comments are stylized: 27038-// /*<arrow><length>,<token type>,[<modifiers]*/ 27039-// For most occurrences, the comment comes just before the token it 27040-// describes, and arrow is a right arrow. If the token is inside a string 27041-// the comment comes just after the string, and the arrow is a left arrow. 27042-// <length> is the length of the token in runes, <token type> is one 27043-// of the supported semantic token types, and <modifiers. is a 27044-// (possibly empty) list of token type modifiers. 27045- 27046-// There are 3 coordinate systems for lines and character offsets in lines 27047-// LSP (what's returned from semanticTokens()): 27048-// 0-based: the first line is line 0, the first character of a line 27049-// is character 0, and characters are counted as UTF-16 code points 27050-// gopls (and Go error messages): 27051-// 1-based: the first line is line1, the first character of a line 27052-// is character 0, and characters are counted as bytes 27053-// internal (as used in marks, and lines:=bytes.Split(buf, '\n')) 27054-// 0-based: lines and character positions are 1 less than in 27055-// the gopls coordinate system 27056- 27057-type semtok struct { 27058- app *Application 27059-} 27060- 27061-var colmap *protocol.Mapper 27062- 27063-func (c *semtok) Name() string { return "semtok" } 27064-func (c *semtok) Parent() string { return c.app.Name() } 27065-func (c *semtok) Usage() string { return "<filename>" } 27066-func (c *semtok) ShortHelp() string { return "show semantic tokens for the specified file" } 27067-func (c *semtok) DetailedHelp(f *flag.FlagSet) { 27068- fmt.Fprint(f.Output(), ` 27069-Example: show the semantic tokens for this file: 27070- 27071- $ gopls semtok internal/lsp/cmd/semtok.go 27072-`) 27073- printFlagDefaults(f) 27074-} 27075- 27076-// Run performs the semtok on the files specified by args and prints the 27077-// results to stdout in the format described above. 27078-func (c *semtok) Run(ctx context.Context, args ...string) error { 27079- if len(args) != 1 { 27080- return fmt.Errorf("expected one file name, got %d", len(args)) 27081- } 27082- // perhaps simpler if app had just had a FlagSet member 27083- origOptions := c.app.options 27084- c.app.options = func(opts *source.Options) { 27085- origOptions(opts) 27086- opts.SemanticTokens = true 27087- } 27088- conn, err := c.app.connect(ctx) 27089- if err != nil { 27090- return err 27091- } 27092- defer conn.terminate(ctx) 27093- uri := span.URIFromPath(args[0]) 27094- file := conn.openFile(ctx, uri) 27095- if file.err != nil { 27096- return file.err 27097- } 27098- 27099- buf, err := ioutil.ReadFile(args[0]) 27100- if err != nil { 27101- return err 27102- } 27103- lines := bytes.Split(buf, []byte{'\n'}) 27104- p := &protocol.SemanticTokensRangeParams{ 27105- TextDocument: protocol.TextDocumentIdentifier{ 27106- URI: protocol.URIFromSpanURI(uri), 27107- }, 27108- Range: protocol.Range{Start: protocol.Position{Line: 0, Character: 0}, 27109- End: protocol.Position{ 27110- Line: uint32(len(lines) - 1), 27111- Character: uint32(len(lines[len(lines)-1]))}, 27112- }, 27113- } 27114- resp, err := conn.semanticTokens(ctx, p) 27115- if err != nil { 27116- return err 27117- } 27118- fset := token.NewFileSet() 27119- f, err := parser.ParseFile(fset, args[0], buf, 0) 27120- if err != nil { 27121- log.Printf("parsing %s failed %v", args[0], err) 27122- return err 27123- } 27124- tok := fset.File(f.Pos()) 27125- if tok == nil { 27126- // can't happen; just parsed this file 27127- return fmt.Errorf("can't find %s in fset", args[0]) 27128- } 27129- colmap = protocol.NewMapper(uri, buf) 27130- err = decorate(file.uri.Filename(), resp.Data) 27131- if err != nil { 27132- return err 27133- } 27134- return nil 27135-} 27136- 27137-type mark struct { 27138- line, offset int // 1-based, from RangeSpan 27139- len int // bytes, not runes 27140- typ string 27141- mods []string 27142-} 27143- 27144-// prefixes for semantic token comments 27145-const ( 27146- SemanticLeft = "/*⇐" 27147- SemanticRight = "/*⇒" 27148-) 27149- 27150-func markLine(m mark, lines [][]byte) { 27151- l := lines[m.line-1] // mx is 1-based 27152- length := utf8.RuneCount(l[m.offset-1 : m.offset-1+m.len]) 27153- splitAt := m.offset - 1 27154- insert := "" 27155- if m.typ == "namespace" && m.offset-1+m.len < len(l) && l[m.offset-1+m.len] == '"' { 27156- // it is the last component of an import spec 27157- // cannot put a comment inside a string 27158- insert = fmt.Sprintf("%s%d,namespace,[]*/", SemanticLeft, length) 27159- splitAt = m.offset + m.len 27160- } else { 27161- // be careful not to generate //* 27162- spacer := "" 27163- if splitAt-1 >= 0 && l[splitAt-1] == '/' { 27164- spacer = " " 27165- } 27166- insert = fmt.Sprintf("%s%s%d,%s,%v*/", spacer, SemanticRight, length, m.typ, m.mods) 27167- } 27168- x := append([]byte(insert), l[splitAt:]...) 27169- l = append(l[:splitAt], x...) 27170- lines[m.line-1] = l 27171-} 27172- 27173-func decorate(file string, result []uint32) error { 27174- buf, err := ioutil.ReadFile(file) 27175- if err != nil { 27176- return err 27177- } 27178- marks := newMarks(result) 27179- if len(marks) == 0 { 27180- return nil 27181- } 27182- lines := bytes.Split(buf, []byte{'\n'}) 27183- for i := len(marks) - 1; i >= 0; i-- { 27184- mx := marks[i] 27185- markLine(mx, lines) 27186- } 27187- os.Stdout.Write(bytes.Join(lines, []byte{'\n'})) 27188- return nil 27189-} 27190- 27191-func newMarks(d []uint32) []mark { 27192- ans := []mark{} 27193- // the following two loops could be merged, at the cost 27194- // of making the logic slightly more complicated to understand 27195- // first, convert from deltas to absolute, in LSP coordinates 27196- lspLine := make([]uint32, len(d)/5) 27197- lspChar := make([]uint32, len(d)/5) 27198- var line, char uint32 27199- for i := 0; 5*i < len(d); i++ { 27200- lspLine[i] = line + d[5*i+0] 27201- if d[5*i+0] > 0 { 27202- char = 0 27203- } 27204- lspChar[i] = char + d[5*i+1] 27205- char = lspChar[i] 27206- line = lspLine[i] 27207- } 27208- // second, convert to gopls coordinates 27209- for i := 0; 5*i < len(d); i++ { 27210- pr := protocol.Range{ 27211- Start: protocol.Position{ 27212- Line: lspLine[i], 27213- Character: lspChar[i], 27214- }, 27215- End: protocol.Position{ 27216- Line: lspLine[i], 27217- Character: lspChar[i] + d[5*i+2], 27218- }, 27219- } 27220- spn, err := colmap.RangeSpan(pr) 27221- if err != nil { 27222- log.Fatal(err) 27223- } 27224- m := mark{ 27225- line: spn.Start().Line(), 27226- offset: spn.Start().Column(), 27227- len: spn.End().Column() - spn.Start().Column(), 27228- typ: lsp.SemType(int(d[5*i+3])), 27229- mods: lsp.SemMods(int(d[5*i+4])), 27230- } 27231- ans = append(ans, m) 27232- } 27233- return ans 27234-} 27235diff -urN a/gopls/internal/lsp/cmd/serve.go b/gopls/internal/lsp/cmd/serve.go 27236--- a/gopls/internal/lsp/cmd/serve.go 2000-01-01 00:00:00.000000000 -0000 27237+++ b/gopls/internal/lsp/cmd/serve.go 1970-01-01 00:00:00.000000000 +0000 27238@@ -1,130 +0,0 @@ 27239-// Copyright 2018 The Go Authors. All rights reserved. 27240-// Use of this source code is governed by a BSD-style 27241-// license that can be found in the LICENSE file. 27242- 27243-package cmd 27244- 27245-import ( 27246- "context" 27247- "errors" 27248- "flag" 27249- "fmt" 27250- "io" 27251- "log" 27252- "os" 27253- "time" 27254- 27255- "golang.org/x/tools/gopls/internal/lsp/cache" 27256- "golang.org/x/tools/gopls/internal/lsp/debug" 27257- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 27258- "golang.org/x/tools/gopls/internal/lsp/protocol" 27259- "golang.org/x/tools/internal/fakenet" 27260- "golang.org/x/tools/internal/jsonrpc2" 27261- "golang.org/x/tools/internal/tool" 27262-) 27263- 27264-// Serve is a struct that exposes the configurable parts of the LSP server as 27265-// flags, in the right form for tool.Main to consume. 27266-type Serve struct { 27267- Logfile string `flag:"logfile" help:"filename to log to. if value is \"auto\", then logging to a default output file is enabled"` 27268- Mode string `flag:"mode" help:"no effect"` 27269- Port int `flag:"port" help:"port on which to run gopls for debugging purposes"` 27270- Address string `flag:"listen" help:"address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used."` 27271- IdleTimeout time.Duration `flag:"listen.timeout" help:"when used with -listen, shut down the server when there are no connected clients for this duration"` 27272- Trace bool `flag:"rpc.trace" help:"print the full rpc trace in lsp inspector format"` 27273- Debug string `flag:"debug" help:"serve debug information on the supplied address"` 27274- 27275- RemoteListenTimeout time.Duration `flag:"remote.listen.timeout" help:"when used with -remote=auto, the -listen.timeout value used to start the daemon"` 27276- RemoteDebug string `flag:"remote.debug" help:"when used with -remote=auto, the -debug value used to start the daemon"` 27277- RemoteLogfile string `flag:"remote.logfile" help:"when used with -remote=auto, the -logfile value used to start the daemon"` 27278- 27279- app *Application 27280-} 27281- 27282-func (s *Serve) Name() string { return "serve" } 27283-func (s *Serve) Parent() string { return s.app.Name() } 27284-func (s *Serve) Usage() string { return "[server-flags]" } 27285-func (s *Serve) ShortHelp() string { 27286- return "run a server for Go code using the Language Server Protocol" 27287-} 27288-func (s *Serve) DetailedHelp(f *flag.FlagSet) { 27289- fmt.Fprint(f.Output(), ` gopls [flags] [server-flags] 27290- 27291-The server communicates using JSONRPC2 on stdin and stdout, and is intended to be run directly as 27292-a child of an editor process. 27293- 27294-server-flags: 27295-`) 27296- printFlagDefaults(f) 27297-} 27298- 27299-func (s *Serve) remoteArgs(network, address string) []string { 27300- args := []string{"serve", 27301- "-listen", fmt.Sprintf(`%s;%s`, network, address), 27302- } 27303- if s.RemoteDebug != "" { 27304- args = append(args, "-debug", s.RemoteDebug) 27305- } 27306- if s.RemoteListenTimeout != 0 { 27307- args = append(args, "-listen.timeout", s.RemoteListenTimeout.String()) 27308- } 27309- if s.RemoteLogfile != "" { 27310- args = append(args, "-logfile", s.RemoteLogfile) 27311- } 27312- return args 27313-} 27314- 27315-// Run configures a server based on the flags, and then runs it. 27316-// It blocks until the server shuts down. 27317-func (s *Serve) Run(ctx context.Context, args ...string) error { 27318- if len(args) > 0 { 27319- return tool.CommandLineErrorf("server does not take arguments, got %v", args) 27320- } 27321- 27322- di := debug.GetInstance(ctx) 27323- isDaemon := s.Address != "" || s.Port != 0 27324- if di != nil { 27325- closeLog, err := di.SetLogFile(s.Logfile, isDaemon) 27326- if err != nil { 27327- return err 27328- } 27329- defer closeLog() 27330- di.ServerAddress = s.Address 27331- di.MonitorMemory(ctx) 27332- di.Serve(ctx, s.Debug) 27333- } 27334- var ss jsonrpc2.StreamServer 27335- if s.app.Remote != "" { 27336- var err error 27337- ss, err = lsprpc.NewForwarder(s.app.Remote, s.remoteArgs) 27338- if err != nil { 27339- return fmt.Errorf("creating forwarder: %w", err) 27340- } 27341- } else { 27342- ss = lsprpc.NewStreamServer(cache.New(nil), isDaemon, s.app.options) 27343- } 27344- 27345- var network, addr string 27346- if s.Address != "" { 27347- network, addr = lsprpc.ParseAddr(s.Address) 27348- } 27349- if s.Port != 0 { 27350- network = "tcp" 27351- addr = fmt.Sprintf(":%v", s.Port) 27352- } 27353- if addr != "" { 27354- log.Printf("Gopls daemon: listening on %s network, address %s...", network, addr) 27355- defer log.Printf("Gopls daemon: exiting") 27356- return jsonrpc2.ListenAndServe(ctx, network, addr, ss, s.IdleTimeout) 27357- } 27358- stream := jsonrpc2.NewHeaderStream(fakenet.NewConn("stdio", os.Stdin, os.Stdout)) 27359- if s.Trace && di != nil { 27360- stream = protocol.LoggingStream(stream, di.LogWriter) 27361- } 27362- conn := jsonrpc2.NewConn(stream) 27363- err := ss.ServeStream(ctx, conn) 27364- if errors.Is(err, io.EOF) { 27365- return nil 27366- } 27367- return err 27368-} 27369diff -urN a/gopls/internal/lsp/cmd/signature.go b/gopls/internal/lsp/cmd/signature.go 27370--- a/gopls/internal/lsp/cmd/signature.go 2000-01-01 00:00:00.000000000 -0000 27371+++ b/gopls/internal/lsp/cmd/signature.go 1970-01-01 00:00:00.000000000 +0000 27372@@ -1,88 +0,0 @@ 27373-// Copyright 2019 The Go Authors. All rights reserved. 27374-// Use of this source code is governed by a BSD-style 27375-// license that can be found in the LICENSE file. 27376- 27377-package cmd 27378- 27379-import ( 27380- "context" 27381- "flag" 27382- "fmt" 27383- 27384- "golang.org/x/tools/gopls/internal/lsp/protocol" 27385- "golang.org/x/tools/gopls/internal/span" 27386- "golang.org/x/tools/internal/tool" 27387-) 27388- 27389-// signature implements the signature verb for gopls 27390-type signature struct { 27391- app *Application 27392-} 27393- 27394-func (r *signature) Name() string { return "signature" } 27395-func (r *signature) Parent() string { return r.app.Name() } 27396-func (r *signature) Usage() string { return "<position>" } 27397-func (r *signature) ShortHelp() string { return "display selected identifier's signature" } 27398-func (r *signature) DetailedHelp(f *flag.FlagSet) { 27399- fmt.Fprint(f.Output(), ` 27400-Example: 27401- 27402- $ # 1-indexed location (:line:column or :#offset) of the target identifier 27403- $ gopls signature helper/helper.go:8:6 27404- $ gopls signature helper/helper.go:#53 27405-`) 27406- printFlagDefaults(f) 27407-} 27408- 27409-func (r *signature) Run(ctx context.Context, args ...string) error { 27410- if len(args) != 1 { 27411- return tool.CommandLineErrorf("signature expects 1 argument (position)") 27412- } 27413- 27414- conn, err := r.app.connect(ctx) 27415- if err != nil { 27416- return err 27417- } 27418- defer conn.terminate(ctx) 27419- 27420- from := span.Parse(args[0]) 27421- file := conn.openFile(ctx, from.URI()) 27422- if file.err != nil { 27423- return file.err 27424- } 27425- 27426- loc, err := file.mapper.SpanLocation(from) 27427- if err != nil { 27428- return err 27429- } 27430- 27431- p := protocol.SignatureHelpParams{ 27432- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 27433- } 27434- 27435- s, err := conn.SignatureHelp(ctx, &p) 27436- if err != nil { 27437- return err 27438- } 27439- 27440- if s == nil || len(s.Signatures) == 0 { 27441- return tool.CommandLineErrorf("%v: not a function", from) 27442- } 27443- 27444- // there is only ever one possible signature, 27445- // see toProtocolSignatureHelp in lsp/signature_help.go 27446- signature := s.Signatures[0] 27447- fmt.Printf("%s\n", signature.Label) 27448- switch x := signature.Documentation.Value.(type) { 27449- case string: 27450- if x != "" { 27451- fmt.Printf("\n%s\n", x) 27452- } 27453- case protocol.MarkupContent: 27454- if x.Value != "" { 27455- fmt.Printf("\n%s\n", x.Value) 27456- } 27457- } 27458- 27459- return nil 27460-} 27461diff -urN a/gopls/internal/lsp/cmd/subcommands.go b/gopls/internal/lsp/cmd/subcommands.go 27462--- a/gopls/internal/lsp/cmd/subcommands.go 2000-01-01 00:00:00.000000000 -0000 27463+++ b/gopls/internal/lsp/cmd/subcommands.go 1970-01-01 00:00:00.000000000 +0000 27464@@ -1,59 +0,0 @@ 27465-// Copyright 2021 The Go Authors. All rights reserved. 27466-// Use of this source code is governed by a BSD-style 27467-// license that can be found in the LICENSE file. 27468- 27469-package cmd 27470- 27471-import ( 27472- "context" 27473- "flag" 27474- "fmt" 27475- "text/tabwriter" 27476- 27477- "golang.org/x/tools/internal/tool" 27478-) 27479- 27480-// subcommands is a helper that may be embedded for commands that delegate to 27481-// subcommands. 27482-type subcommands []tool.Application 27483- 27484-func (s subcommands) DetailedHelp(f *flag.FlagSet) { 27485- w := tabwriter.NewWriter(f.Output(), 0, 0, 2, ' ', 0) 27486- defer w.Flush() 27487- fmt.Fprint(w, "\nSubcommand:\n") 27488- for _, c := range s { 27489- fmt.Fprintf(w, " %s\t%s\n", c.Name(), c.ShortHelp()) 27490- } 27491- printFlagDefaults(f) 27492-} 27493- 27494-func (s subcommands) Usage() string { return "<subcommand> [arg]..." } 27495- 27496-func (s subcommands) Run(ctx context.Context, args ...string) error { 27497- if len(args) == 0 { 27498- return tool.CommandLineErrorf("must provide subcommand") 27499- } 27500- command, args := args[0], args[1:] 27501- for _, c := range s { 27502- if c.Name() == command { 27503- s := flag.NewFlagSet(c.Name(), flag.ExitOnError) 27504- return tool.Run(ctx, s, c, args) 27505- } 27506- } 27507- return tool.CommandLineErrorf("unknown subcommand %v", command) 27508-} 27509- 27510-func (s subcommands) Commands() []tool.Application { return s } 27511- 27512-// getSubcommands returns the subcommands of a given Application. 27513-func getSubcommands(a tool.Application) []tool.Application { 27514- // This interface is satisfied both by tool.Applications 27515- // that embed subcommands, and by *cmd.Application. 27516- type hasCommands interface { 27517- Commands() []tool.Application 27518- } 27519- if sub, ok := a.(hasCommands); ok { 27520- return sub.Commands() 27521- } 27522- return nil 27523-} 27524diff -urN a/gopls/internal/lsp/cmd/suggested_fix.go b/gopls/internal/lsp/cmd/suggested_fix.go 27525--- a/gopls/internal/lsp/cmd/suggested_fix.go 2000-01-01 00:00:00.000000000 -0000 27526+++ b/gopls/internal/lsp/cmd/suggested_fix.go 1970-01-01 00:00:00.000000000 +0000 27527@@ -1,167 +0,0 @@ 27528-// Copyright 2019 The Go Authors. All rights reserved. 27529-// Use of this source code is governed by a BSD-style 27530-// license that can be found in the LICENSE file. 27531- 27532-package cmd 27533- 27534-import ( 27535- "context" 27536- "flag" 27537- "fmt" 27538- "io/ioutil" 27539- "os" 27540- 27541- "golang.org/x/tools/gopls/internal/lsp/protocol" 27542- "golang.org/x/tools/gopls/internal/lsp/source" 27543- "golang.org/x/tools/gopls/internal/span" 27544- "golang.org/x/tools/internal/diff" 27545- "golang.org/x/tools/internal/tool" 27546-) 27547- 27548-// suggestedFix implements the fix verb for gopls. 27549-type suggestedFix struct { 27550- Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` 27551- Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` 27552- All bool `flag:"a,all" help:"apply all fixes, not just preferred fixes"` 27553- 27554- app *Application 27555-} 27556- 27557-func (s *suggestedFix) Name() string { return "fix" } 27558-func (s *suggestedFix) Parent() string { return s.app.Name() } 27559-func (s *suggestedFix) Usage() string { return "[fix-flags] <filename>" } 27560-func (s *suggestedFix) ShortHelp() string { return "apply suggested fixes" } 27561-func (s *suggestedFix) DetailedHelp(f *flag.FlagSet) { 27562- fmt.Fprintf(f.Output(), ` 27563-Example: apply suggested fixes for this file 27564- $ gopls fix -w internal/lsp/cmd/check.go 27565- 27566-fix-flags: 27567-`) 27568- printFlagDefaults(f) 27569-} 27570- 27571-// Run performs diagnostic checks on the file specified and either; 27572-// - if -w is specified, updates the file in place; 27573-// - if -d is specified, prints out unified diffs of the changes; or 27574-// - otherwise, prints the new versions to stdout. 27575-func (s *suggestedFix) Run(ctx context.Context, args ...string) error { 27576- if len(args) < 1 { 27577- return tool.CommandLineErrorf("fix expects at least 1 argument") 27578- } 27579- conn, err := s.app.connect(ctx) 27580- if err != nil { 27581- return err 27582- } 27583- defer conn.terminate(ctx) 27584- 27585- from := span.Parse(args[0]) 27586- uri := from.URI() 27587- file := conn.openFile(ctx, uri) 27588- if file.err != nil { 27589- return file.err 27590- } 27591- 27592- if err := conn.diagnoseFiles(ctx, []span.URI{uri}); err != nil { 27593- return err 27594- } 27595- conn.Client.filesMu.Lock() 27596- defer conn.Client.filesMu.Unlock() 27597- 27598- codeActionKinds := []protocol.CodeActionKind{protocol.QuickFix} 27599- if len(args) > 1 { 27600- codeActionKinds = []protocol.CodeActionKind{} 27601- for _, k := range args[1:] { 27602- codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k)) 27603- } 27604- } 27605- 27606- rng, err := file.mapper.SpanRange(from) 27607- if err != nil { 27608- return err 27609- } 27610- p := protocol.CodeActionParams{ 27611- TextDocument: protocol.TextDocumentIdentifier{ 27612- URI: protocol.URIFromSpanURI(uri), 27613- }, 27614- Context: protocol.CodeActionContext{ 27615- Only: codeActionKinds, 27616- Diagnostics: file.diagnostics, 27617- }, 27618- Range: rng, 27619- } 27620- actions, err := conn.CodeAction(ctx, &p) 27621- if err != nil { 27622- return fmt.Errorf("%v: %v", from, err) 27623- } 27624- var edits []protocol.TextEdit 27625- for _, a := range actions { 27626- if a.Command != nil { 27627- return fmt.Errorf("ExecuteCommand is not yet supported on the command line") 27628- } 27629- if !a.IsPreferred && !s.All { 27630- continue 27631- } 27632- if !from.HasPosition() { 27633- for _, c := range a.Edit.DocumentChanges { 27634- if c.TextDocumentEdit != nil { 27635- if fileURI(c.TextDocumentEdit.TextDocument.URI) == uri { 27636- edits = append(edits, c.TextDocumentEdit.Edits...) 27637- } 27638- } 27639- } 27640- continue 27641- } 27642- // If the span passed in has a position, then we need to find 27643- // the codeaction that has the same range as the passed in span. 27644- for _, diag := range a.Diagnostics { 27645- spn, err := file.mapper.RangeSpan(diag.Range) 27646- if err != nil { 27647- continue 27648- } 27649- if span.ComparePoint(from.Start(), spn.Start()) == 0 { 27650- for _, c := range a.Edit.DocumentChanges { 27651- if c.TextDocumentEdit != nil { 27652- if fileURI(c.TextDocumentEdit.TextDocument.URI) == uri { 27653- edits = append(edits, c.TextDocumentEdit.Edits...) 27654- } 27655- } 27656- } 27657- break 27658- } 27659- } 27660- 27661- // If suggested fix is not a diagnostic, still must collect edits. 27662- if len(a.Diagnostics) == 0 { 27663- for _, c := range a.Edit.DocumentChanges { 27664- if c.TextDocumentEdit != nil { 27665- if fileURI(c.TextDocumentEdit.TextDocument.URI) == uri { 27666- edits = append(edits, c.TextDocumentEdit.Edits...) 27667- } 27668- } 27669- } 27670- } 27671- } 27672- 27673- newContent, sedits, err := source.ApplyProtocolEdits(file.mapper, edits) 27674- if err != nil { 27675- return fmt.Errorf("%v: %v", edits, err) 27676- } 27677- 27678- filename := file.uri.Filename() 27679- switch { 27680- case s.Write: 27681- if len(edits) > 0 { 27682- ioutil.WriteFile(filename, newContent, 0644) 27683- } 27684- case s.Diff: 27685- diffs, err := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) 27686- if err != nil { 27687- return err 27688- } 27689- fmt.Print(diffs) 27690- default: 27691- os.Stdout.Write(newContent) 27692- } 27693- return nil 27694-} 27695diff -urN a/gopls/internal/lsp/cmd/symbols.go b/gopls/internal/lsp/cmd/symbols.go 27696--- a/gopls/internal/lsp/cmd/symbols.go 2000-01-01 00:00:00.000000000 -0000 27697+++ b/gopls/internal/lsp/cmd/symbols.go 1970-01-01 00:00:00.000000000 +0000 27698@@ -1,116 +0,0 @@ 27699-// Copyright 2019 The Go Authors. All rights reserved. 27700-// Use of this source code is governed by a BSD-style 27701-// license that can be found in the LICENSE file. 27702- 27703-package cmd 27704- 27705-import ( 27706- "context" 27707- "encoding/json" 27708- "flag" 27709- "fmt" 27710- "sort" 27711- 27712- "golang.org/x/tools/gopls/internal/lsp/protocol" 27713- "golang.org/x/tools/gopls/internal/span" 27714- "golang.org/x/tools/internal/tool" 27715-) 27716- 27717-// symbols implements the symbols verb for gopls 27718-type symbols struct { 27719- app *Application 27720-} 27721- 27722-func (r *symbols) Name() string { return "symbols" } 27723-func (r *symbols) Parent() string { return r.app.Name() } 27724-func (r *symbols) Usage() string { return "<file>" } 27725-func (r *symbols) ShortHelp() string { return "display selected file's symbols" } 27726-func (r *symbols) DetailedHelp(f *flag.FlagSet) { 27727- fmt.Fprint(f.Output(), ` 27728-Example: 27729- $ gopls symbols helper/helper.go 27730-`) 27731- printFlagDefaults(f) 27732-} 27733-func (r *symbols) Run(ctx context.Context, args ...string) error { 27734- if len(args) != 1 { 27735- return tool.CommandLineErrorf("symbols expects 1 argument (position)") 27736- } 27737- 27738- conn, err := r.app.connect(ctx) 27739- if err != nil { 27740- return err 27741- } 27742- defer conn.terminate(ctx) 27743- 27744- from := span.Parse(args[0]) 27745- p := protocol.DocumentSymbolParams{ 27746- TextDocument: protocol.TextDocumentIdentifier{ 27747- URI: protocol.URIFromSpanURI(from.URI()), 27748- }, 27749- } 27750- symbols, err := conn.DocumentSymbol(ctx, &p) 27751- if err != nil { 27752- return err 27753- } 27754- for _, s := range symbols { 27755- if m, ok := s.(map[string]interface{}); ok { 27756- s, err = mapToSymbol(m) 27757- if err != nil { 27758- return err 27759- } 27760- } 27761- switch t := s.(type) { 27762- case protocol.DocumentSymbol: 27763- printDocumentSymbol(t) 27764- case protocol.SymbolInformation: 27765- printSymbolInformation(t) 27766- } 27767- } 27768- return nil 27769-} 27770- 27771-func mapToSymbol(m map[string]interface{}) (interface{}, error) { 27772- b, err := json.Marshal(m) 27773- if err != nil { 27774- return nil, err 27775- } 27776- 27777- if _, ok := m["selectionRange"]; ok { 27778- var s protocol.DocumentSymbol 27779- if err := json.Unmarshal(b, &s); err != nil { 27780- return nil, err 27781- } 27782- return s, nil 27783- } 27784- 27785- var s protocol.SymbolInformation 27786- if err := json.Unmarshal(b, &s); err != nil { 27787- return nil, err 27788- } 27789- return s, nil 27790-} 27791- 27792-func printDocumentSymbol(s protocol.DocumentSymbol) { 27793- fmt.Printf("%s %s %s\n", s.Name, s.Kind, positionToString(s.SelectionRange)) 27794- // Sort children for consistency 27795- sort.Slice(s.Children, func(i, j int) bool { 27796- return s.Children[i].Name < s.Children[j].Name 27797- }) 27798- for _, c := range s.Children { 27799- fmt.Printf("\t%s %s %s\n", c.Name, c.Kind, positionToString(c.SelectionRange)) 27800- } 27801-} 27802- 27803-func printSymbolInformation(s protocol.SymbolInformation) { 27804- fmt.Printf("%s %s %s\n", s.Name, s.Kind, positionToString(s.Location.Range)) 27805-} 27806- 27807-func positionToString(r protocol.Range) string { 27808- return fmt.Sprintf("%v:%v-%v:%v", 27809- r.Start.Line+1, 27810- r.Start.Character+1, 27811- r.End.Line+1, 27812- r.End.Character+1, 27813- ) 27814-} 27815diff -urN a/gopls/internal/lsp/cmd/test/cmdtest.go b/gopls/internal/lsp/cmd/test/cmdtest.go 27816--- a/gopls/internal/lsp/cmd/test/cmdtest.go 2000-01-01 00:00:00.000000000 -0000 27817+++ b/gopls/internal/lsp/cmd/test/cmdtest.go 1970-01-01 00:00:00.000000000 +0000 27818@@ -1,6 +0,0 @@ 27819-// Copyright 2023 The Go Authors. All rights reserved. 27820-// Use of this source code is governed by a BSD-style 27821-// license that can be found in the LICENSE file. 27822- 27823-// Package cmdtest contains the test suite for the command line behavior of gopls. 27824-package cmdtest 27825diff -urN a/gopls/internal/lsp/cmd/test/integration_test.go b/gopls/internal/lsp/cmd/test/integration_test.go 27826--- a/gopls/internal/lsp/cmd/test/integration_test.go 2000-01-01 00:00:00.000000000 -0000 27827+++ b/gopls/internal/lsp/cmd/test/integration_test.go 1970-01-01 00:00:00.000000000 +0000 27828@@ -1,898 +0,0 @@ 27829-// Copyright 2023 The Go Authors. All rights reserved. 27830-// Use of this source code is governed by a BSD-style 27831-// license that can be found in the LICENSE file. 27832-package cmdtest 27833- 27834-// This file defines integration tests of each gopls subcommand that 27835-// fork+exec the command in a separate process. 27836-// 27837-// (Rather than execute 'go build gopls' during the test, we reproduce 27838-// the main entrypoint in the test executable.) 27839-// 27840-// The purpose of this test is to exercise client-side logic such as 27841-// argument parsing and formatting of LSP RPC responses, not server 27842-// behavior; see lsp_test for that. 27843-// 27844-// All tests run in parallel. 27845-// 27846-// TODO(adonovan): 27847-// - Use markers to represent positions in the input and in assertions. 27848-// - Coverage of cross-cutting things like cwd, enviro, span parsing, etc. 27849-// - Subcommands that accept -write and -diff flags should implement 27850-// them consistently wrt the default behavior; factor their tests. 27851-// - Add missing test for 'vulncheck' subcommand. 27852-// - Add tests for client-only commands: serve, bug, help, api-json, licenses. 27853- 27854-import ( 27855- "bytes" 27856- "context" 27857- "encoding/json" 27858- "fmt" 27859- "os" 27860- "path/filepath" 27861- "regexp" 27862- "strings" 27863- "testing" 27864- 27865- exec "golang.org/x/sys/execabs" 27866- "golang.org/x/tools/gopls/internal/hooks" 27867- "golang.org/x/tools/gopls/internal/lsp/cmd" 27868- "golang.org/x/tools/gopls/internal/lsp/debug" 27869- "golang.org/x/tools/gopls/internal/lsp/protocol" 27870- "golang.org/x/tools/internal/bug" 27871- "golang.org/x/tools/internal/testenv" 27872- "golang.org/x/tools/internal/tool" 27873- "golang.org/x/tools/txtar" 27874-) 27875- 27876-// TestVersion tests the 'version' subcommand (../info.go). 27877-func TestVersion(t *testing.T) { 27878- t.Parallel() 27879- 27880- tree := writeTree(t, "") 27881- 27882- // There's not much we can robustly assert about the actual version. 27883- const want = debug.Version // e.g. "master" 27884- 27885- // basic 27886- { 27887- res := gopls(t, tree, "version") 27888- res.checkExit(true) 27889- res.checkStdout(want) 27890- } 27891- 27892- // -json flag 27893- { 27894- res := gopls(t, tree, "version", "-json") 27895- res.checkExit(true) 27896- var v debug.ServerVersion 27897- if res.toJSON(&v) { 27898- if v.Version != want { 27899- t.Errorf("expected Version %q, got %q (%v)", want, v.Version, res) 27900- } 27901- } 27902- } 27903-} 27904- 27905-// TestCheck tests the 'check' subcommand (../check.go). 27906-func TestCheck(t *testing.T) { 27907- t.Parallel() 27908- 27909- tree := writeTree(t, ` 27910--- go.mod -- 27911-module example.com 27912-go 1.18 27913- 27914--- a.go -- 27915-package a 27916-import "fmt" 27917-var _ = fmt.Sprintf("%s", 123) 27918- 27919--- b.go -- 27920-package a 27921-import "fmt" 27922-var _ = fmt.Sprintf("%d", "123") 27923-`) 27924- 27925- // no files 27926- { 27927- res := gopls(t, tree, "check") 27928- res.checkExit(true) 27929- if res.stdout != "" { 27930- t.Errorf("unexpected output: %v", res) 27931- } 27932- } 27933- 27934- // one file 27935- { 27936- res := gopls(t, tree, "check", "./a.go") 27937- res.checkExit(true) 27938- res.checkStdout("fmt.Sprintf format %s has arg 123 of wrong type int") 27939- } 27940- 27941- // two files 27942- { 27943- res := gopls(t, tree, "check", "./a.go", "./b.go") 27944- res.checkExit(true) 27945- res.checkStdout(`a.go:.* fmt.Sprintf format %s has arg 123 of wrong type int`) 27946- res.checkStdout(`b.go:.* fmt.Sprintf format %d has arg "123" of wrong type string`) 27947- } 27948-} 27949- 27950-// TestCallHierarchy tests the 'call_hierarchy' subcommand (../call_hierarchy.go). 27951-func TestCallHierarchy(t *testing.T) { 27952- t.Parallel() 27953- 27954- tree := writeTree(t, ` 27955--- go.mod -- 27956-module example.com 27957-go 1.18 27958- 27959--- a.go -- 27960-package a 27961-func f() {} 27962-func g() { 27963- f() 27964-} 27965-func h() { 27966- f() 27967- f() 27968-} 27969-`) 27970- // missing position 27971- { 27972- res := gopls(t, tree, "call_hierarchy") 27973- res.checkExit(false) 27974- res.checkStderr("expects 1 argument") 27975- } 27976- // wrong place 27977- { 27978- res := gopls(t, tree, "call_hierarchy", "a.go:1") 27979- res.checkExit(false) 27980- res.checkStderr("identifier not found") 27981- } 27982- // f is called once from g and twice from h. 27983- { 27984- res := gopls(t, tree, "call_hierarchy", "a.go:2:6") 27985- res.checkExit(true) 27986- // We use regexp '.' as an OS-agnostic path separator. 27987- res.checkStdout("ranges 7:2-3, 8:2-3 in ..a.go from/to function h in ..a.go:6:6-7") 27988- res.checkStdout("ranges 4:2-3 in ..a.go from/to function g in ..a.go:3:6-7") 27989- res.checkStdout("identifier: function f in ..a.go:2:6-7") 27990- } 27991-} 27992- 27993-// TestDefinition tests the 'definition' subcommand (../definition.go). 27994-func TestDefinition(t *testing.T) { 27995- t.Parallel() 27996- 27997- tree := writeTree(t, ` 27998--- go.mod -- 27999-module example.com 28000-go 1.18 28001- 28002--- a.go -- 28003-package a 28004-import "fmt" 28005-func f() { 28006- fmt.Println() 28007-} 28008-func g() { 28009- f() 28010-} 28011-`) 28012- // missing position 28013- { 28014- res := gopls(t, tree, "definition") 28015- res.checkExit(false) 28016- res.checkStderr("expects 1 argument") 28017- } 28018- // intra-package 28019- { 28020- res := gopls(t, tree, "definition", "a.go:7:2") // "f()" 28021- res.checkExit(true) 28022- res.checkStdout("a.go:3:6-7: defined here as func f") 28023- } 28024- // cross-package 28025- { 28026- res := gopls(t, tree, "definition", "a.go:4:7") // "Println" 28027- res.checkExit(true) 28028- res.checkStdout("print.go.* defined here as func fmt.Println") 28029- res.checkStdout("Println formats using the default formats for its operands") 28030- } 28031- // -json and -markdown 28032- { 28033- res := gopls(t, tree, "definition", "-json", "-markdown", "a.go:4:7") 28034- res.checkExit(true) 28035- var defn cmd.Definition 28036- if res.toJSON(&defn) { 28037- if !strings.HasPrefix(defn.Description, "```go\nfunc fmt.Println") { 28038- t.Errorf("Description does not start with markdown code block. Got: %s", defn.Description) 28039- } 28040- } 28041- } 28042-} 28043- 28044-// TestFoldingRanges tests the 'folding_ranges' subcommand (../folding_range.go). 28045-func TestFoldingRanges(t *testing.T) { 28046- t.Parallel() 28047- 28048- tree := writeTree(t, ` 28049--- go.mod -- 28050-module example.com 28051-go 1.18 28052- 28053--- a.go -- 28054-package a 28055-func f(x int) { 28056- // hello 28057-} 28058-`) 28059- // missing filename 28060- { 28061- res := gopls(t, tree, "folding_ranges") 28062- res.checkExit(false) 28063- res.checkStderr("expects 1 argument") 28064- } 28065- // success 28066- { 28067- res := gopls(t, tree, "folding_ranges", "a.go") 28068- res.checkExit(true) 28069- res.checkStdout("2:8-2:13") // params (x int) 28070- res.checkStdout("2:16-4:1") // body { ... } 28071- } 28072-} 28073- 28074-// TestFormat tests the 'format' subcommand (../format.go). 28075-func TestFormat(t *testing.T) { 28076- t.Parallel() 28077- 28078- tree := writeTree(t, ` 28079--- a.go -- 28080-package a ; func f ( ) { } 28081-`) 28082- const want = `package a 28083- 28084-func f() {} 28085-` 28086- 28087- // no files => nop 28088- { 28089- res := gopls(t, tree, "format") 28090- res.checkExit(true) 28091- } 28092- // default => print formatted result 28093- { 28094- res := gopls(t, tree, "format", "a.go") 28095- res.checkExit(true) 28096- if res.stdout != want { 28097- t.Errorf("format: got <<%s>>, want <<%s>>", res.stdout, want) 28098- } 28099- } 28100- // start/end position not supported (unless equal to start/end of file) 28101- { 28102- res := gopls(t, tree, "format", "a.go:1-2") 28103- res.checkExit(false) 28104- res.checkStderr("only full file formatting supported") 28105- } 28106- // -list: show only file names 28107- { 28108- res := gopls(t, tree, "format", "-list", "a.go") 28109- res.checkExit(true) 28110- res.checkStdout("a.go") 28111- } 28112- // -diff prints a unified diff 28113- { 28114- res := gopls(t, tree, "format", "-diff", "a.go") 28115- res.checkExit(true) 28116- // We omit the filenames as they vary by OS. 28117- want := ` 28118--package a ; func f ( ) { } 28119-+package a 28120-+ 28121-+func f() {} 28122-` 28123- res.checkStdout(regexp.QuoteMeta(want)) 28124- } 28125- // -write updates the file 28126- { 28127- res := gopls(t, tree, "format", "-write", "a.go") 28128- res.checkExit(true) 28129- res.checkStdout("^$") // empty 28130- checkContent(t, filepath.Join(tree, "a.go"), want) 28131- } 28132-} 28133- 28134-// TestHighlight tests the 'highlight' subcommand (../highlight.go). 28135-func TestHighlight(t *testing.T) { 28136- t.Parallel() 28137- 28138- tree := writeTree(t, ` 28139--- a.go -- 28140-package a 28141-import "fmt" 28142-func f() { 28143- fmt.Println() 28144- fmt.Println() 28145-} 28146-`) 28147- 28148- // no arguments 28149- { 28150- res := gopls(t, tree, "highlight") 28151- res.checkExit(false) 28152- res.checkStderr("expects 1 argument") 28153- } 28154- // all occurrences of Println 28155- { 28156- res := gopls(t, tree, "highlight", "a.go:4:7") 28157- res.checkExit(true) 28158- res.checkStdout("a.go:4:6-13") 28159- res.checkStdout("a.go:5:6-13") 28160- } 28161-} 28162- 28163-// TestImplementations tests the 'implementation' subcommand (../implementation.go). 28164-func TestImplementations(t *testing.T) { 28165- t.Parallel() 28166- 28167- tree := writeTree(t, ` 28168--- a.go -- 28169-package a 28170-import "fmt" 28171-type T int 28172-func (T) String() string { return "" } 28173-`) 28174- 28175- // no arguments 28176- { 28177- res := gopls(t, tree, "implementation") 28178- res.checkExit(false) 28179- res.checkStderr("expects 1 argument") 28180- } 28181- // T.String 28182- { 28183- res := gopls(t, tree, "implementation", "a.go:4:10") 28184- res.checkExit(true) 28185- // TODO(adonovan): extract and check the content of the reported ranges? 28186- // We use regexp '.' as an OS-agnostic path separator. 28187- res.checkStdout("fmt.print.go:") // fmt.Stringer.String 28188- res.checkStdout("runtime.error.go:") // runtime.stringer.String 28189- } 28190-} 28191- 28192-// TestImports tests the 'imports' subcommand (../imports.go). 28193-func TestImports(t *testing.T) { 28194- t.Parallel() 28195- 28196- tree := writeTree(t, ` 28197--- a.go -- 28198-package a 28199-func _() { 28200- fmt.Println() 28201-} 28202-`) 28203- 28204- want := ` 28205-package a 28206- 28207-import "fmt" 28208-func _() { 28209- fmt.Println() 28210-} 28211-`[1:] 28212- 28213- // no arguments 28214- { 28215- res := gopls(t, tree, "imports") 28216- res.checkExit(false) 28217- res.checkStderr("expects 1 argument") 28218- } 28219- // default: print with imports 28220- { 28221- res := gopls(t, tree, "imports", "a.go") 28222- res.checkExit(true) 28223- if res.stdout != want { 28224- t.Errorf("format: got <<%s>>, want <<%s>>", res.stdout, want) 28225- } 28226- } 28227- // -diff: show a unified diff 28228- { 28229- res := gopls(t, tree, "imports", "-diff", "a.go") 28230- res.checkExit(true) 28231- res.checkStdout(regexp.QuoteMeta(`+import "fmt"`)) 28232- } 28233- // -write: update file 28234- { 28235- res := gopls(t, tree, "imports", "-write", "a.go") 28236- res.checkExit(true) 28237- checkContent(t, filepath.Join(tree, "a.go"), want) 28238- } 28239-} 28240- 28241-// TestLinks tests the 'links' subcommand (../links.go). 28242-func TestLinks(t *testing.T) { 28243- t.Parallel() 28244- 28245- tree := writeTree(t, ` 28246--- a.go -- 28247-// Link in package doc: https://pkg.go.dev/ 28248-package a 28249- 28250-// Link in internal comment: https://go.dev/cl 28251- 28252-// Doc comment link: https://blog.go.dev/ 28253-func f() {} 28254-`) 28255- // no arguments 28256- { 28257- res := gopls(t, tree, "links") 28258- res.checkExit(false) 28259- res.checkStderr("expects 1 argument") 28260- } 28261- // success 28262- { 28263- res := gopls(t, tree, "links", "a.go") 28264- res.checkExit(true) 28265- res.checkStdout("https://go.dev/cl") 28266- res.checkStdout("https://pkg.go.dev") 28267- res.checkStdout("https://blog.go.dev/") 28268- } 28269- // -json 28270- { 28271- res := gopls(t, tree, "links", "-json", "a.go") 28272- res.checkExit(true) 28273- res.checkStdout("https://pkg.go.dev") 28274- res.checkStdout("https://go.dev/cl") 28275- res.checkStdout("https://blog.go.dev/") // at 5:21-5:41 28276- var links []protocol.DocumentLink 28277- if res.toJSON(&links) { 28278- // Check just one of the three locations. 28279- if got, want := fmt.Sprint(links[2].Range), "5:21-5:41"; got != want { 28280- t.Errorf("wrong link location: got %v, want %v", got, want) 28281- } 28282- } 28283- } 28284-} 28285- 28286-// TestReferences tests the 'references' subcommand (../references.go). 28287-func TestReferences(t *testing.T) { 28288- t.Parallel() 28289- 28290- tree := writeTree(t, ` 28291--- go.mod -- 28292-module example.com 28293-go 1.18 28294- 28295--- a.go -- 28296-package a 28297-import "fmt" 28298-func f() { 28299- fmt.Println() 28300-} 28301- 28302--- b.go -- 28303-package a 28304-import "fmt" 28305-func g() { 28306- fmt.Println() 28307-} 28308-`) 28309- // no arguments 28310- { 28311- res := gopls(t, tree, "references") 28312- res.checkExit(false) 28313- res.checkStderr("expects 1 argument") 28314- } 28315- // fmt.Println 28316- { 28317- res := gopls(t, tree, "references", "a.go:4:10") 28318- res.checkExit(true) 28319- res.checkStdout("a.go:4:6-13") 28320- res.checkStdout("b.go:4:6-13") 28321- } 28322-} 28323- 28324-// TestSignature tests the 'signature' subcommand (../signature.go). 28325-func TestSignature(t *testing.T) { 28326- t.Parallel() 28327- 28328- tree := writeTree(t, ` 28329--- go.mod -- 28330-module example.com 28331-go 1.18 28332- 28333--- a.go -- 28334-package a 28335-import "fmt" 28336-func f() { 28337- fmt.Println(123) 28338-} 28339-`) 28340- // no arguments 28341- { 28342- res := gopls(t, tree, "signature") 28343- res.checkExit(false) 28344- res.checkStderr("expects 1 argument") 28345- } 28346- // at 123 inside fmt.Println() call 28347- { 28348- res := gopls(t, tree, "signature", "a.go:4:15") 28349- res.checkExit(true) 28350- res.checkStdout("Println\\(a ...") 28351- res.checkStdout("Println formats using the default formats...") 28352- } 28353-} 28354- 28355-// TestPrepareRename tests the 'prepare_rename' subcommand (../prepare_rename.go). 28356-func TestPrepareRename(t *testing.T) { 28357- t.Parallel() 28358- 28359- tree := writeTree(t, ` 28360--- go.mod -- 28361-module example.com 28362-go 1.18 28363- 28364--- a.go -- 28365-package a 28366-func oldname() {} 28367-`) 28368- // no arguments 28369- { 28370- res := gopls(t, tree, "prepare_rename") 28371- res.checkExit(false) 28372- res.checkStderr("expects 1 argument") 28373- } 28374- // in 'package' keyword 28375- { 28376- res := gopls(t, tree, "prepare_rename", "a.go:1:3") 28377- res.checkExit(false) 28378- res.checkStderr("request is not valid at the given position") 28379- } 28380- // in 'package' identifier (not supported by client) 28381- { 28382- res := gopls(t, tree, "prepare_rename", "a.go:1:9") 28383- res.checkExit(false) 28384- res.checkStderr("can't rename package") 28385- } 28386- // in func oldname 28387- { 28388- res := gopls(t, tree, "prepare_rename", "a.go:2:9") 28389- res.checkExit(true) 28390- res.checkStdout("a.go:2:6-13") // all of "oldname" 28391- } 28392-} 28393- 28394-// TestRename tests the 'rename' subcommand (../rename.go). 28395-func TestRename(t *testing.T) { 28396- t.Parallel() 28397- 28398- tree := writeTree(t, ` 28399--- go.mod -- 28400-module example.com 28401-go 1.18 28402- 28403--- a.go -- 28404-package a 28405-func oldname() {} 28406-`) 28407- // no arguments 28408- { 28409- res := gopls(t, tree, "rename") 28410- res.checkExit(false) 28411- res.checkStderr("expects 2 arguments") 28412- } 28413- // missing newname 28414- { 28415- res := gopls(t, tree, "rename", "a.go:1:3") 28416- res.checkExit(false) 28417- res.checkStderr("expects 2 arguments") 28418- } 28419- // in 'package' keyword 28420- { 28421- res := gopls(t, tree, "rename", "a.go:1:3", "newname") 28422- res.checkExit(false) 28423- res.checkStderr("no identifier found") 28424- } 28425- // in 'package' identifier 28426- { 28427- res := gopls(t, tree, "rename", "a.go:1:9", "newname") 28428- res.checkExit(false) 28429- res.checkStderr(`cannot rename package: module path .* same as the package path, so .* no effect`) 28430- } 28431- // success, func oldname (and -diff) 28432- { 28433- res := gopls(t, tree, "rename", "-diff", "a.go:2:9", "newname") 28434- res.checkExit(true) 28435- res.checkStdout(regexp.QuoteMeta("-func oldname() {}")) 28436- res.checkStdout(regexp.QuoteMeta("+func newname() {}")) 28437- } 28438-} 28439- 28440-// TestSymbols tests the 'symbols' subcommand (../symbols.go). 28441-func TestSymbols(t *testing.T) { 28442- t.Parallel() 28443- 28444- tree := writeTree(t, ` 28445--- go.mod -- 28446-module example.com 28447-go 1.18 28448- 28449--- a.go -- 28450-package a 28451-func f() 28452-var v int 28453-const c = 0 28454-`) 28455- // no files 28456- { 28457- res := gopls(t, tree, "symbols") 28458- res.checkExit(false) 28459- res.checkStderr("expects 1 argument") 28460- } 28461- // success 28462- { 28463- res := gopls(t, tree, "symbols", "a.go:123:456") // (line/col ignored) 28464- res.checkExit(true) 28465- res.checkStdout("f Function 2:6-2:7") 28466- res.checkStdout("v Variable 3:5-3:6") 28467- res.checkStdout("c Constant 4:7-4:8") 28468- } 28469-} 28470- 28471-// TestSemtok tests the 'semtok' subcommand (../semantictokens.go). 28472-func TestSemtok(t *testing.T) { 28473- t.Parallel() 28474- 28475- tree := writeTree(t, ` 28476--- go.mod -- 28477-module example.com 28478-go 1.18 28479- 28480--- a.go -- 28481-package a 28482-func f() 28483-var v int 28484-const c = 0 28485-`) 28486- // no files 28487- { 28488- res := gopls(t, tree, "semtok") 28489- res.checkExit(false) 28490- res.checkStderr("expected one file name") 28491- } 28492- // success 28493- { 28494- res := gopls(t, tree, "semtok", "a.go") 28495- res.checkExit(true) 28496- got := res.stdout 28497- want := ` 28498-/*⇒7,keyword,[]*/package /*⇒1,namespace,[]*/a 28499-/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/f() 28500-/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/v /*⇒3,type,[defaultLibrary]*/int 28501-/*⇒5,keyword,[]*/const /*⇒1,variable,[definition readonly]*/c = /*⇒1,number,[]*/0 28502-`[1:] 28503- if got != want { 28504- t.Errorf("semtok: got <<%s>>, want <<%s>>", got, want) 28505- } 28506- } 28507-} 28508- 28509-// TestFix tests the 'fix' subcommand (../suggested_fix.go). 28510-func TestFix(t *testing.T) { 28511- t.Parallel() 28512- 28513- tree := writeTree(t, ` 28514--- go.mod -- 28515-module example.com 28516-go 1.18 28517- 28518--- a.go -- 28519-package a 28520-var _ error = T(0) 28521-type T int 28522-func f() (int, string) { return } 28523-`) 28524- want := ` 28525-package a 28526-var _ error = T(0) 28527-type T int 28528-func f() (int, string) { return 0, "" } 28529-`[1:] 28530- 28531- // no arguments 28532- { 28533- res := gopls(t, tree, "fix") 28534- res.checkExit(false) 28535- res.checkStderr("expects at least 1 argument") 28536- } 28537- // success (-a enables fillreturns) 28538- { 28539- res := gopls(t, tree, "fix", "-a", "a.go") 28540- res.checkExit(true) 28541- got := res.stdout 28542- if got != want { 28543- t.Errorf("fix: got <<%s>>, want <<%s>>", got, want) 28544- } 28545- } 28546- // TODO(adonovan): more tests: 28547- // - -write, -diff: factor with imports, format, rename. 28548- // - without -all flag 28549- // - args[2:] is an optional list of protocol.CodeActionKind enum values. 28550- // - a span argument with a range causes filtering. 28551-} 28552- 28553-// TestWorkspaceSymbol tests the 'workspace_symbol' subcommand (../workspace_symbol.go). 28554-func TestWorkspaceSymbol(t *testing.T) { 28555- t.Parallel() 28556- 28557- tree := writeTree(t, ` 28558--- go.mod -- 28559-module example.com 28560-go 1.18 28561- 28562--- a.go -- 28563-package a 28564-func someFunctionName() 28565-`) 28566- // no files 28567- { 28568- res := gopls(t, tree, "workspace_symbol") 28569- res.checkExit(false) 28570- res.checkStderr("expects 1 argument") 28571- } 28572- // success 28573- { 28574- res := gopls(t, tree, "workspace_symbol", "meFun") 28575- res.checkExit(true) 28576- res.checkStdout("a.go:2:6-22 someFunctionName Function") 28577- } 28578-} 28579- 28580-// -- test framework -- 28581- 28582-func TestMain(m *testing.M) { 28583- switch os.Getenv("ENTRYPOINT") { 28584- case "goplsMain": 28585- goplsMain() 28586- default: 28587- os.Exit(m.Run()) 28588- } 28589-} 28590- 28591-// This function is a stand-in for gopls.main in ../../../../main.go. 28592-func goplsMain() { 28593- bug.PanicOnBugs = true // (not in the production command) 28594- tool.Main(context.Background(), cmd.New("gopls", "", nil, hooks.Options), os.Args[1:]) 28595-} 28596- 28597-// writeTree extracts a txtar archive into a new directory and returns its path. 28598-func writeTree(t *testing.T, archive string) string { 28599- root := t.TempDir() 28600- 28601- // This unfortunate step is required because gopls output 28602- // expands symbolic links it its input file names (arguably it 28603- // should not), and on macOS the temp dir is in /var -> private/var. 28604- root, err := filepath.EvalSymlinks(root) 28605- if err != nil { 28606- t.Fatal(err) 28607- } 28608- 28609- for _, f := range txtar.Parse([]byte(archive)).Files { 28610- filename := filepath.Join(root, f.Name) 28611- if err := os.MkdirAll(filepath.Dir(filename), 0777); err != nil { 28612- t.Fatal(err) 28613- } 28614- if err := os.WriteFile(filename, f.Data, 0666); err != nil { 28615- t.Fatal(err) 28616- } 28617- } 28618- return root 28619-} 28620- 28621-// gopls executes gopls in a child process. 28622-func gopls(t *testing.T, dir string, args ...string) *result { 28623- testenv.NeedsTool(t, "go") 28624- 28625- // Catch inadvertent use of dir=".", which would make 28626- // the ReplaceAll below unpredictable. 28627- if !filepath.IsAbs(dir) { 28628- t.Fatalf("dir is not absolute: %s", dir) 28629- } 28630- 28631- cmd := exec.Command(os.Args[0], args...) 28632- cmd.Env = append(os.Environ(), "ENTRYPOINT=goplsMain") 28633- cmd.Dir = dir 28634- cmd.Stdout = new(bytes.Buffer) 28635- cmd.Stderr = new(bytes.Buffer) 28636- 28637- cmdErr := cmd.Run() 28638- 28639- stdout := strings.ReplaceAll(fmt.Sprint(cmd.Stdout), dir, ".") 28640- stderr := strings.ReplaceAll(fmt.Sprint(cmd.Stderr), dir, ".") 28641- exitcode := 0 28642- if cmdErr != nil { 28643- if exitErr, ok := cmdErr.(*exec.ExitError); ok { 28644- exitcode = exitErr.ExitCode() 28645- } else { 28646- stderr = cmdErr.Error() // (execve failure) 28647- exitcode = -1 28648- } 28649- } 28650- res := &result{ 28651- t: t, 28652- command: "gopls " + strings.Join(args, " "), 28653- exitcode: exitcode, 28654- stdout: stdout, 28655- stderr: stderr, 28656- } 28657- if false { 28658- t.Log(res) 28659- } 28660- return res 28661-} 28662- 28663-// A result holds the result of a gopls invocation, and provides assertion helpers. 28664-type result struct { 28665- t *testing.T 28666- command string 28667- exitcode int 28668- stdout, stderr string 28669-} 28670- 28671-func (res *result) String() string { 28672- return fmt.Sprintf("%s: exit=%d stdout=<<%s>> stderr=<<%s>>", 28673- res.command, res.exitcode, res.stdout, res.stderr) 28674-} 28675- 28676-// checkExit asserts that gopls returned the expected exit code. 28677-func (res *result) checkExit(success bool) { 28678- res.t.Helper() 28679- if (res.exitcode == 0) != success { 28680- res.t.Errorf("%s: exited with code %d, want success: %t (%s)", 28681- res.command, res.exitcode, success, res) 28682- } 28683-} 28684- 28685-// checkStdout asserts that the gopls standard output matches the pattern. 28686-func (res *result) checkStdout(pattern string) { 28687- res.t.Helper() 28688- res.checkOutput(pattern, "stdout", res.stdout) 28689-} 28690- 28691-// checkStderr asserts that the gopls standard error matches the pattern. 28692-func (res *result) checkStderr(pattern string) { 28693- res.t.Helper() 28694- res.checkOutput(pattern, "stderr", res.stderr) 28695-} 28696- 28697-func (res *result) checkOutput(pattern, name, content string) { 28698- res.t.Helper() 28699- if match, err := regexp.MatchString(pattern, content); err != nil { 28700- res.t.Errorf("invalid regexp: %v", err) 28701- } else if !match { 28702- res.t.Errorf("%s: %s does not match [%s]; got <<%s>>", 28703- res.command, name, pattern, content) 28704- } 28705-} 28706- 28707-// toJSON decodes res.stdout as JSON into to *ptr and reports its success. 28708-func (res *result) toJSON(ptr interface{}) bool { 28709- if err := json.Unmarshal([]byte(res.stdout), ptr); err != nil { 28710- res.t.Errorf("invalid JSON %v", err) 28711- return false 28712- } 28713- return true 28714-} 28715- 28716-// checkContent checks that the contents of the file are as expected. 28717-func checkContent(t *testing.T, filename, want string) { 28718- data, err := os.ReadFile(filename) 28719- if err != nil { 28720- t.Error(err) 28721- return 28722- } 28723- if got := string(data); got != want { 28724- t.Errorf("content of %s is <<%s>>, want <<%s>>", filename, got, want) 28725- } 28726-} 28727diff -urN a/gopls/internal/lsp/cmd/usage/api-json.hlp b/gopls/internal/lsp/cmd/usage/api-json.hlp 28728--- a/gopls/internal/lsp/cmd/usage/api-json.hlp 2000-01-01 00:00:00.000000000 -0000 28729+++ b/gopls/internal/lsp/cmd/usage/api-json.hlp 1970-01-01 00:00:00.000000000 +0000 28730@@ -1,4 +0,0 @@ 28731-print json describing gopls API 28732- 28733-Usage: 28734- gopls [flags] api-json 28735diff -urN a/gopls/internal/lsp/cmd/usage/bug.hlp b/gopls/internal/lsp/cmd/usage/bug.hlp 28736--- a/gopls/internal/lsp/cmd/usage/bug.hlp 2000-01-01 00:00:00.000000000 -0000 28737+++ b/gopls/internal/lsp/cmd/usage/bug.hlp 1970-01-01 00:00:00.000000000 +0000 28738@@ -1,4 +0,0 @@ 28739-report a bug in gopls 28740- 28741-Usage: 28742- gopls [flags] bug 28743diff -urN a/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp b/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp 28744--- a/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp 2000-01-01 00:00:00.000000000 -0000 28745+++ b/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp 1970-01-01 00:00:00.000000000 +0000 28746@@ -1,10 +0,0 @@ 28747-display selected identifier's call hierarchy 28748- 28749-Usage: 28750- gopls [flags] call_hierarchy <position> 28751- 28752-Example: 28753- 28754- $ # 1-indexed location (:line:column or :#offset) of the target identifier 28755- $ gopls call_hierarchy helper/helper.go:8:6 28756- $ gopls call_hierarchy helper/helper.go:#53 28757diff -urN a/gopls/internal/lsp/cmd/usage/check.hlp b/gopls/internal/lsp/cmd/usage/check.hlp 28758--- a/gopls/internal/lsp/cmd/usage/check.hlp 2000-01-01 00:00:00.000000000 -0000 28759+++ b/gopls/internal/lsp/cmd/usage/check.hlp 1970-01-01 00:00:00.000000000 +0000 28760@@ -1,8 +0,0 @@ 28761-show diagnostic results for the specified file 28762- 28763-Usage: 28764- gopls [flags] check <filename> 28765- 28766-Example: show the diagnostic results of this file: 28767- 28768- $ gopls check internal/lsp/cmd/check.go 28769diff -urN a/gopls/internal/lsp/cmd/usage/definition.hlp b/gopls/internal/lsp/cmd/usage/definition.hlp 28770--- a/gopls/internal/lsp/cmd/usage/definition.hlp 2000-01-01 00:00:00.000000000 -0000 28771+++ b/gopls/internal/lsp/cmd/usage/definition.hlp 1970-01-01 00:00:00.000000000 +0000 28772@@ -1,15 +0,0 @@ 28773-show declaration of selected identifier 28774- 28775-Usage: 28776- gopls [flags] definition [definition-flags] <position> 28777- 28778-Example: show the definition of the identifier at syntax at offset 44 in this file (flag.FlagSet): 28779- 28780- $ gopls definition internal/lsp/cmd/definition.go:44:47 28781- $ gopls definition internal/lsp/cmd/definition.go:#1270 28782- 28783-definition-flags: 28784- -json 28785- emit output in JSON format 28786- -markdown 28787- support markdown in responses 28788diff -urN a/gopls/internal/lsp/cmd/usage/fix.hlp b/gopls/internal/lsp/cmd/usage/fix.hlp 28789--- a/gopls/internal/lsp/cmd/usage/fix.hlp 2000-01-01 00:00:00.000000000 -0000 28790+++ b/gopls/internal/lsp/cmd/usage/fix.hlp 1970-01-01 00:00:00.000000000 +0000 28791@@ -1,15 +0,0 @@ 28792-apply suggested fixes 28793- 28794-Usage: 28795- gopls [flags] fix [fix-flags] <filename> 28796- 28797-Example: apply suggested fixes for this file 28798- $ gopls fix -w internal/lsp/cmd/check.go 28799- 28800-fix-flags: 28801- -a,-all 28802- apply all fixes, not just preferred fixes 28803- -d,-diff 28804- display diffs instead of rewriting files 28805- -w,-write 28806- write result to (source) file instead of stdout 28807diff -urN a/gopls/internal/lsp/cmd/usage/folding_ranges.hlp b/gopls/internal/lsp/cmd/usage/folding_ranges.hlp 28808--- a/gopls/internal/lsp/cmd/usage/folding_ranges.hlp 2000-01-01 00:00:00.000000000 -0000 28809+++ b/gopls/internal/lsp/cmd/usage/folding_ranges.hlp 1970-01-01 00:00:00.000000000 +0000 28810@@ -1,8 +0,0 @@ 28811-display selected file's folding ranges 28812- 28813-Usage: 28814- gopls [flags] folding_ranges <file> 28815- 28816-Example: 28817- 28818- $ gopls folding_ranges helper/helper.go 28819diff -urN a/gopls/internal/lsp/cmd/usage/format.hlp b/gopls/internal/lsp/cmd/usage/format.hlp 28820--- a/gopls/internal/lsp/cmd/usage/format.hlp 2000-01-01 00:00:00.000000000 -0000 28821+++ b/gopls/internal/lsp/cmd/usage/format.hlp 1970-01-01 00:00:00.000000000 +0000 28822@@ -1,18 +0,0 @@ 28823-format the code according to the go standard 28824- 28825-Usage: 28826- gopls [flags] format [format-flags] <filerange> 28827- 28828-The arguments supplied may be simple file names, or ranges within files. 28829- 28830-Example: reformat this file: 28831- 28832- $ gopls format -w internal/lsp/cmd/check.go 28833- 28834-format-flags: 28835- -d,-diff 28836- display diffs instead of rewriting files 28837- -l,-list 28838- list files whose formatting differs from gofmt's 28839- -w,-write 28840- write result to (source) file instead of stdout 28841diff -urN a/gopls/internal/lsp/cmd/usage/help.hlp b/gopls/internal/lsp/cmd/usage/help.hlp 28842--- a/gopls/internal/lsp/cmd/usage/help.hlp 2000-01-01 00:00:00.000000000 -0000 28843+++ b/gopls/internal/lsp/cmd/usage/help.hlp 1970-01-01 00:00:00.000000000 +0000 28844@@ -1,10 +0,0 @@ 28845-print usage information for subcommands 28846- 28847-Usage: 28848- gopls [flags] help 28849- 28850- 28851-Examples: 28852-$ gopls help # main gopls help message 28853-$ gopls help remote # help on 'remote' command 28854-$ gopls help remote sessions # help on 'remote sessions' subcommand 28855diff -urN a/gopls/internal/lsp/cmd/usage/highlight.hlp b/gopls/internal/lsp/cmd/usage/highlight.hlp 28856--- a/gopls/internal/lsp/cmd/usage/highlight.hlp 2000-01-01 00:00:00.000000000 -0000 28857+++ b/gopls/internal/lsp/cmd/usage/highlight.hlp 1970-01-01 00:00:00.000000000 +0000 28858@@ -1,10 +0,0 @@ 28859-display selected identifier's highlights 28860- 28861-Usage: 28862- gopls [flags] highlight <position> 28863- 28864-Example: 28865- 28866- $ # 1-indexed location (:line:column or :#offset) of the target identifier 28867- $ gopls highlight helper/helper.go:8:6 28868- $ gopls highlight helper/helper.go:#53 28869diff -urN a/gopls/internal/lsp/cmd/usage/implementation.hlp b/gopls/internal/lsp/cmd/usage/implementation.hlp 28870--- a/gopls/internal/lsp/cmd/usage/implementation.hlp 2000-01-01 00:00:00.000000000 -0000 28871+++ b/gopls/internal/lsp/cmd/usage/implementation.hlp 1970-01-01 00:00:00.000000000 +0000 28872@@ -1,10 +0,0 @@ 28873-display selected identifier's implementation 28874- 28875-Usage: 28876- gopls [flags] implementation <position> 28877- 28878-Example: 28879- 28880- $ # 1-indexed location (:line:column or :#offset) of the target identifier 28881- $ gopls implementation helper/helper.go:8:6 28882- $ gopls implementation helper/helper.go:#53 28883diff -urN a/gopls/internal/lsp/cmd/usage/imports.hlp b/gopls/internal/lsp/cmd/usage/imports.hlp 28884--- a/gopls/internal/lsp/cmd/usage/imports.hlp 2000-01-01 00:00:00.000000000 -0000 28885+++ b/gopls/internal/lsp/cmd/usage/imports.hlp 1970-01-01 00:00:00.000000000 +0000 28886@@ -1,14 +0,0 @@ 28887-updates import statements 28888- 28889-Usage: 28890- gopls [flags] imports [imports-flags] <filename> 28891- 28892-Example: update imports statements in a file: 28893- 28894- $ gopls imports -w internal/lsp/cmd/check.go 28895- 28896-imports-flags: 28897- -d,-diff 28898- display diffs instead of rewriting files 28899- -w,-write 28900- write result to (source) file instead of stdout 28901diff -urN a/gopls/internal/lsp/cmd/usage/inspect.hlp b/gopls/internal/lsp/cmd/usage/inspect.hlp 28902--- a/gopls/internal/lsp/cmd/usage/inspect.hlp 2000-01-01 00:00:00.000000000 -0000 28903+++ b/gopls/internal/lsp/cmd/usage/inspect.hlp 1970-01-01 00:00:00.000000000 +0000 28904@@ -1,8 +0,0 @@ 28905-interact with the gopls daemon (deprecated: use 'remote') 28906- 28907-Usage: 28908- gopls [flags] inspect <subcommand> [arg]... 28909- 28910-Subcommand: 28911- sessions print information about current gopls sessions 28912- debug start the debug server 28913diff -urN a/gopls/internal/lsp/cmd/usage/licenses.hlp b/gopls/internal/lsp/cmd/usage/licenses.hlp 28914--- a/gopls/internal/lsp/cmd/usage/licenses.hlp 2000-01-01 00:00:00.000000000 -0000 28915+++ b/gopls/internal/lsp/cmd/usage/licenses.hlp 1970-01-01 00:00:00.000000000 +0000 28916@@ -1,4 +0,0 @@ 28917-print licenses of included software 28918- 28919-Usage: 28920- gopls [flags] licenses 28921diff -urN a/gopls/internal/lsp/cmd/usage/links.hlp b/gopls/internal/lsp/cmd/usage/links.hlp 28922--- a/gopls/internal/lsp/cmd/usage/links.hlp 2000-01-01 00:00:00.000000000 -0000 28923+++ b/gopls/internal/lsp/cmd/usage/links.hlp 1970-01-01 00:00:00.000000000 +0000 28924@@ -1,12 +0,0 @@ 28925-list links in a file 28926- 28927-Usage: 28928- gopls [flags] links [links-flags] <filename> 28929- 28930-Example: list links contained within a file: 28931- 28932- $ gopls links internal/lsp/cmd/check.go 28933- 28934-links-flags: 28935- -json 28936- emit document links in JSON format 28937diff -urN a/gopls/internal/lsp/cmd/usage/prepare_rename.hlp b/gopls/internal/lsp/cmd/usage/prepare_rename.hlp 28938--- a/gopls/internal/lsp/cmd/usage/prepare_rename.hlp 2000-01-01 00:00:00.000000000 -0000 28939+++ b/gopls/internal/lsp/cmd/usage/prepare_rename.hlp 1970-01-01 00:00:00.000000000 +0000 28940@@ -1,10 +0,0 @@ 28941-test validity of a rename operation at location 28942- 28943-Usage: 28944- gopls [flags] prepare_rename <position> 28945- 28946-Example: 28947- 28948- $ # 1-indexed location (:line:column or :#offset) of the target identifier 28949- $ gopls prepare_rename helper/helper.go:8:6 28950- $ gopls prepare_rename helper/helper.go:#53 28951diff -urN a/gopls/internal/lsp/cmd/usage/references.hlp b/gopls/internal/lsp/cmd/usage/references.hlp 28952--- a/gopls/internal/lsp/cmd/usage/references.hlp 2000-01-01 00:00:00.000000000 -0000 28953+++ b/gopls/internal/lsp/cmd/usage/references.hlp 1970-01-01 00:00:00.000000000 +0000 28954@@ -1,14 +0,0 @@ 28955-display selected identifier's references 28956- 28957-Usage: 28958- gopls [flags] references [references-flags] <position> 28959- 28960-Example: 28961- 28962- $ # 1-indexed location (:line:column or :#offset) of the target identifier 28963- $ gopls references helper/helper.go:8:6 28964- $ gopls references helper/helper.go:#53 28965- 28966-references-flags: 28967- -d,-declaration 28968- include the declaration of the specified identifier in the results 28969diff -urN a/gopls/internal/lsp/cmd/usage/remote.hlp b/gopls/internal/lsp/cmd/usage/remote.hlp 28970--- a/gopls/internal/lsp/cmd/usage/remote.hlp 2000-01-01 00:00:00.000000000 -0000 28971+++ b/gopls/internal/lsp/cmd/usage/remote.hlp 1970-01-01 00:00:00.000000000 +0000 28972@@ -1,8 +0,0 @@ 28973-interact with the gopls daemon 28974- 28975-Usage: 28976- gopls [flags] remote <subcommand> [arg]... 28977- 28978-Subcommand: 28979- sessions print information about current gopls sessions 28980- debug start the debug server 28981diff -urN a/gopls/internal/lsp/cmd/usage/rename.hlp b/gopls/internal/lsp/cmd/usage/rename.hlp 28982--- a/gopls/internal/lsp/cmd/usage/rename.hlp 2000-01-01 00:00:00.000000000 -0000 28983+++ b/gopls/internal/lsp/cmd/usage/rename.hlp 1970-01-01 00:00:00.000000000 +0000 28984@@ -1,18 +0,0 @@ 28985-rename selected identifier 28986- 28987-Usage: 28988- gopls [flags] rename [rename-flags] <position> <name> 28989- 28990-Example: 28991- 28992- $ # 1-based location (:line:column or :#position) of the thing to change 28993- $ gopls rename helper/helper.go:8:6 Foo 28994- $ gopls rename helper/helper.go:#53 Foo 28995- 28996-rename-flags: 28997- -d,-diff 28998- display diffs instead of rewriting files 28999- -preserve 29000- preserve original files 29001- -w,-write 29002- write result to (source) file instead of stdout 29003diff -urN a/gopls/internal/lsp/cmd/usage/semtok.hlp b/gopls/internal/lsp/cmd/usage/semtok.hlp 29004--- a/gopls/internal/lsp/cmd/usage/semtok.hlp 2000-01-01 00:00:00.000000000 -0000 29005+++ b/gopls/internal/lsp/cmd/usage/semtok.hlp 1970-01-01 00:00:00.000000000 +0000 29006@@ -1,8 +0,0 @@ 29007-show semantic tokens for the specified file 29008- 29009-Usage: 29010- gopls [flags] semtok <filename> 29011- 29012-Example: show the semantic tokens for this file: 29013- 29014- $ gopls semtok internal/lsp/cmd/semtok.go 29015diff -urN a/gopls/internal/lsp/cmd/usage/serve.hlp b/gopls/internal/lsp/cmd/usage/serve.hlp 29016--- a/gopls/internal/lsp/cmd/usage/serve.hlp 2000-01-01 00:00:00.000000000 -0000 29017+++ b/gopls/internal/lsp/cmd/usage/serve.hlp 1970-01-01 00:00:00.000000000 +0000 29018@@ -1,30 +0,0 @@ 29019-run a server for Go code using the Language Server Protocol 29020- 29021-Usage: 29022- gopls [flags] serve [server-flags] 29023- gopls [flags] [server-flags] 29024- 29025-The server communicates using JSONRPC2 on stdin and stdout, and is intended to be run directly as 29026-a child of an editor process. 29027- 29028-server-flags: 29029- -debug=string 29030- serve debug information on the supplied address 29031- -listen=string 29032- address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used. 29033- -listen.timeout=duration 29034- when used with -listen, shut down the server when there are no connected clients for this duration 29035- -logfile=string 29036- filename to log to. if value is "auto", then logging to a default output file is enabled 29037- -mode=string 29038- no effect 29039- -port=int 29040- port on which to run gopls for debugging purposes 29041- -remote.debug=string 29042- when used with -remote=auto, the -debug value used to start the daemon 29043- -remote.listen.timeout=duration 29044- when used with -remote=auto, the -listen.timeout value used to start the daemon (default 1m0s) 29045- -remote.logfile=string 29046- when used with -remote=auto, the -logfile value used to start the daemon 29047- -rpc.trace 29048- print the full rpc trace in lsp inspector format 29049diff -urN a/gopls/internal/lsp/cmd/usage/signature.hlp b/gopls/internal/lsp/cmd/usage/signature.hlp 29050--- a/gopls/internal/lsp/cmd/usage/signature.hlp 2000-01-01 00:00:00.000000000 -0000 29051+++ b/gopls/internal/lsp/cmd/usage/signature.hlp 1970-01-01 00:00:00.000000000 +0000 29052@@ -1,10 +0,0 @@ 29053-display selected identifier's signature 29054- 29055-Usage: 29056- gopls [flags] signature <position> 29057- 29058-Example: 29059- 29060- $ # 1-indexed location (:line:column or :#offset) of the target identifier 29061- $ gopls signature helper/helper.go:8:6 29062- $ gopls signature helper/helper.go:#53 29063diff -urN a/gopls/internal/lsp/cmd/usage/symbols.hlp b/gopls/internal/lsp/cmd/usage/symbols.hlp 29064--- a/gopls/internal/lsp/cmd/usage/symbols.hlp 2000-01-01 00:00:00.000000000 -0000 29065+++ b/gopls/internal/lsp/cmd/usage/symbols.hlp 1970-01-01 00:00:00.000000000 +0000 29066@@ -1,7 +0,0 @@ 29067-display selected file's symbols 29068- 29069-Usage: 29070- gopls [flags] symbols <file> 29071- 29072-Example: 29073- $ gopls symbols helper/helper.go 29074diff -urN a/gopls/internal/lsp/cmd/usage/usage.hlp b/gopls/internal/lsp/cmd/usage/usage.hlp 29075--- a/gopls/internal/lsp/cmd/usage/usage.hlp 2000-01-01 00:00:00.000000000 -0000 29076+++ b/gopls/internal/lsp/cmd/usage/usage.hlp 1970-01-01 00:00:00.000000000 +0000 29077@@ -1,77 +0,0 @@ 29078- 29079-gopls is a Go language server. 29080- 29081-It is typically used with an editor to provide language features. When no 29082-command is specified, gopls will default to the 'serve' command. The language 29083-features can also be accessed via the gopls command-line interface. 29084- 29085-Usage: 29086- gopls help [<subject>] 29087- 29088-Command: 29089- 29090-Main 29091- serve run a server for Go code using the Language Server Protocol 29092- version print the gopls version information 29093- bug report a bug in gopls 29094- help print usage information for subcommands 29095- api-json print json describing gopls API 29096- licenses print licenses of included software 29097- 29098-Features 29099- call_hierarchy display selected identifier's call hierarchy 29100- check show diagnostic results for the specified file 29101- definition show declaration of selected identifier 29102- folding_ranges display selected file's folding ranges 29103- format format the code according to the go standard 29104- highlight display selected identifier's highlights 29105- implementation display selected identifier's implementation 29106- imports updates import statements 29107- remote interact with the gopls daemon 29108- inspect interact with the gopls daemon (deprecated: use 'remote') 29109- links list links in a file 29110- prepare_rename test validity of a rename operation at location 29111- references display selected identifier's references 29112- rename rename selected identifier 29113- semtok show semantic tokens for the specified file 29114- signature display selected identifier's signature 29115- fix apply suggested fixes 29116- symbols display selected file's symbols 29117- workspace_symbol search symbols in workspace 29118- vulncheck run experimental vulncheck analysis (experimental: under development) 29119- 29120-flags: 29121- -debug=string 29122- serve debug information on the supplied address 29123- -listen=string 29124- address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used. 29125- -listen.timeout=duration 29126- when used with -listen, shut down the server when there are no connected clients for this duration 29127- -logfile=string 29128- filename to log to. if value is "auto", then logging to a default output file is enabled 29129- -mode=string 29130- no effect 29131- -ocagent=string 29132- the address of the ocagent (e.g. http://localhost:55678), or off (default "off") 29133- -port=int 29134- port on which to run gopls for debugging purposes 29135- -profile.cpu=string 29136- write CPU profile to this file 29137- -profile.mem=string 29138- write memory profile to this file 29139- -profile.trace=string 29140- write trace log to this file 29141- -remote=string 29142- forward all commands to a remote lsp specified by this flag. With no special prefix, this is assumed to be a TCP address. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. If 'auto', or prefixed by 'auto;', the remote address is automatically resolved based on the executing environment. 29143- -remote.debug=string 29144- when used with -remote=auto, the -debug value used to start the daemon 29145- -remote.listen.timeout=duration 29146- when used with -remote=auto, the -listen.timeout value used to start the daemon (default 1m0s) 29147- -remote.logfile=string 29148- when used with -remote=auto, the -logfile value used to start the daemon 29149- -rpc.trace 29150- print the full rpc trace in lsp inspector format 29151- -v,-verbose 29152- verbose output 29153- -vv,-veryverbose 29154- very verbose output 29155diff -urN a/gopls/internal/lsp/cmd/usage/version.hlp b/gopls/internal/lsp/cmd/usage/version.hlp 29156--- a/gopls/internal/lsp/cmd/usage/version.hlp 2000-01-01 00:00:00.000000000 -0000 29157+++ b/gopls/internal/lsp/cmd/usage/version.hlp 1970-01-01 00:00:00.000000000 +0000 29158@@ -1,6 +0,0 @@ 29159-print the gopls version information 29160- 29161-Usage: 29162- gopls [flags] version 29163- -json 29164- outputs in json format. 29165diff -urN a/gopls/internal/lsp/cmd/usage/vulncheck.hlp b/gopls/internal/lsp/cmd/usage/vulncheck.hlp 29166--- a/gopls/internal/lsp/cmd/usage/vulncheck.hlp 2000-01-01 00:00:00.000000000 -0000 29167+++ b/gopls/internal/lsp/cmd/usage/vulncheck.hlp 1970-01-01 00:00:00.000000000 +0000 29168@@ -1,17 +0,0 @@ 29169-run experimental vulncheck analysis (experimental: under development) 29170- 29171-Usage: 29172- gopls [flags] vulncheck 29173- 29174- WARNING: this command is experimental. 29175- 29176- By default, the command outputs a JSON-encoded 29177- golang.org/x/tools/gopls/internal/lsp/command.VulncheckResult 29178- message. 29179- Example: 29180- $ gopls vulncheck <packages> 29181- 29182- -config 29183- If true, the command reads a JSON-encoded package load configuration from stdin 29184- -summary 29185- If true, outputs a JSON-encoded govulnchecklib.Summary JSON 29186diff -urN a/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp b/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp 29187--- a/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp 2000-01-01 00:00:00.000000000 -0000 29188+++ b/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp 1970-01-01 00:00:00.000000000 +0000 29189@@ -1,13 +0,0 @@ 29190-search symbols in workspace 29191- 29192-Usage: 29193- gopls [flags] workspace_symbol [workspace_symbol-flags] <query> 29194- 29195-Example: 29196- 29197- $ gopls workspace_symbol -matcher fuzzy 'wsymbols' 29198- 29199-workspace_symbol-flags: 29200- -matcher=string 29201- specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive. 29202- The default is caseInsensitive. 29203diff -urN a/gopls/internal/lsp/cmd/vulncheck.go b/gopls/internal/lsp/cmd/vulncheck.go 29204--- a/gopls/internal/lsp/cmd/vulncheck.go 2000-01-01 00:00:00.000000000 -0000 29205+++ b/gopls/internal/lsp/cmd/vulncheck.go 1970-01-01 00:00:00.000000000 +0000 29206@@ -1,84 +0,0 @@ 29207-// Copyright 2022 The Go Authors. All rights reserved. 29208-// Use of this source code is governed by a BSD-style 29209-// license that can be found in the LICENSE file. 29210- 29211-package cmd 29212- 29213-import ( 29214- "context" 29215- "encoding/json" 29216- "flag" 29217- "fmt" 29218- "os" 29219- 29220- "golang.org/x/tools/go/packages" 29221- vulnchecklib "golang.org/x/tools/gopls/internal/vulncheck" 29222- "golang.org/x/tools/internal/tool" 29223-) 29224- 29225-// vulncheck implements the vulncheck command. 29226-type vulncheck struct { 29227- Config bool `flag:"config" help:"If true, the command reads a JSON-encoded package load configuration from stdin"` 29228- AsSummary bool `flag:"summary" help:"If true, outputs a JSON-encoded govulnchecklib.Summary JSON"` 29229- app *Application 29230-} 29231- 29232-type pkgLoadConfig struct { 29233- // BuildFlags is a list of command-line flags to be passed through to 29234- // the build system's query tool. 29235- BuildFlags []string 29236- 29237- // If Tests is set, the loader includes related test packages. 29238- Tests bool 29239-} 29240- 29241-// TODO(hyangah): document pkgLoadConfig 29242- 29243-func (v *vulncheck) Name() string { return "vulncheck" } 29244-func (v *vulncheck) Parent() string { return v.app.Name() } 29245-func (v *vulncheck) Usage() string { return "" } 29246-func (v *vulncheck) ShortHelp() string { 29247- return "run experimental vulncheck analysis (experimental: under development)" 29248-} 29249-func (v *vulncheck) DetailedHelp(f *flag.FlagSet) { 29250- fmt.Fprint(f.Output(), ` 29251- WARNING: this command is experimental. 29252- 29253- By default, the command outputs a JSON-encoded 29254- golang.org/x/tools/gopls/internal/lsp/command.VulncheckResult 29255- message. 29256- Example: 29257- $ gopls vulncheck <packages> 29258- 29259-`) 29260- printFlagDefaults(f) 29261-} 29262- 29263-func (v *vulncheck) Run(ctx context.Context, args ...string) error { 29264- if vulnchecklib.Main == nil { 29265- return fmt.Errorf("vulncheck command is available only in gopls compiled with go1.18 or newer") 29266- } 29267- 29268- // TODO(hyangah): what's wrong with allowing multiple targets? 29269- if len(args) > 1 { 29270- return tool.CommandLineErrorf("vulncheck accepts at most one package pattern") 29271- } 29272- var cfg pkgLoadConfig 29273- if v.Config { 29274- if err := json.NewDecoder(os.Stdin).Decode(&cfg); err != nil { 29275- return tool.CommandLineErrorf("failed to parse cfg: %v", err) 29276- } 29277- } 29278- loadCfg := packages.Config{ 29279- Context: ctx, 29280- Tests: cfg.Tests, 29281- BuildFlags: cfg.BuildFlags, 29282- // inherit the current process's cwd and env. 29283- } 29284- 29285- if err := vulnchecklib.Main(loadCfg, args...); err != nil { 29286- fmt.Fprintln(os.Stderr, err) 29287- os.Exit(1) 29288- } 29289- return nil 29290-} 29291diff -urN a/gopls/internal/lsp/cmd/workspace_symbol.go b/gopls/internal/lsp/cmd/workspace_symbol.go 29292--- a/gopls/internal/lsp/cmd/workspace_symbol.go 2000-01-01 00:00:00.000000000 -0000 29293+++ b/gopls/internal/lsp/cmd/workspace_symbol.go 1970-01-01 00:00:00.000000000 +0000 29294@@ -1,85 +0,0 @@ 29295-// Copyright 2020 The Go Authors. All rights reserved. 29296-// Use of this source code is governed by a BSD-style 29297-// license that can be found in the LICENSE file. 29298- 29299-package cmd 29300- 29301-import ( 29302- "context" 29303- "flag" 29304- "fmt" 29305- 29306- "golang.org/x/tools/gopls/internal/lsp/protocol" 29307- "golang.org/x/tools/gopls/internal/lsp/source" 29308- "golang.org/x/tools/internal/tool" 29309-) 29310- 29311-// workspaceSymbol implements the workspace_symbol verb for gopls. 29312-type workspaceSymbol struct { 29313- Matcher string `flag:"matcher" help:"specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive.\nThe default is caseInsensitive."` 29314- 29315- app *Application 29316-} 29317- 29318-func (r *workspaceSymbol) Name() string { return "workspace_symbol" } 29319-func (r *workspaceSymbol) Parent() string { return r.app.Name() } 29320-func (r *workspaceSymbol) Usage() string { return "[workspace_symbol-flags] <query>" } 29321-func (r *workspaceSymbol) ShortHelp() string { return "search symbols in workspace" } 29322-func (r *workspaceSymbol) DetailedHelp(f *flag.FlagSet) { 29323- fmt.Fprint(f.Output(), ` 29324-Example: 29325- 29326- $ gopls workspace_symbol -matcher fuzzy 'wsymbols' 29327- 29328-workspace_symbol-flags: 29329-`) 29330- printFlagDefaults(f) 29331-} 29332- 29333-func (r *workspaceSymbol) Run(ctx context.Context, args ...string) error { 29334- if len(args) != 1 { 29335- return tool.CommandLineErrorf("workspace_symbol expects 1 argument") 29336- } 29337- 29338- opts := r.app.options 29339- r.app.options = func(o *source.Options) { 29340- if opts != nil { 29341- opts(o) 29342- } 29343- switch r.Matcher { 29344- case "fuzzy": 29345- o.SymbolMatcher = source.SymbolFuzzy 29346- case "caseSensitive": 29347- o.SymbolMatcher = source.SymbolCaseSensitive 29348- case "fastfuzzy": 29349- o.SymbolMatcher = source.SymbolFastFuzzy 29350- default: 29351- o.SymbolMatcher = source.SymbolCaseInsensitive 29352- } 29353- } 29354- 29355- conn, err := r.app.connect(ctx) 29356- if err != nil { 29357- return err 29358- } 29359- defer conn.terminate(ctx) 29360- 29361- p := protocol.WorkspaceSymbolParams{ 29362- Query: args[0], 29363- } 29364- 29365- symbols, err := conn.Symbol(ctx, &p) 29366- if err != nil { 29367- return err 29368- } 29369- for _, s := range symbols { 29370- f := conn.openFile(ctx, fileURI(s.Location.URI)) 29371- span, err := f.mapper.LocationSpan(s.Location) 29372- if err != nil { 29373- return err 29374- } 29375- fmt.Printf("%s %s %s\n", span, s.Name, s.Kind) 29376- } 29377- 29378- return nil 29379-} 29380diff -urN a/gopls/internal/lsp/code_action.go b/gopls/internal/lsp/code_action.go 29381--- a/gopls/internal/lsp/code_action.go 2000-01-01 00:00:00.000000000 -0000 29382+++ b/gopls/internal/lsp/code_action.go 1970-01-01 00:00:00.000000000 +0000 29383@@ -1,481 +0,0 @@ 29384-// Copyright 2018 The Go Authors. All rights reserved. 29385-// Use of this source code is governed by a BSD-style 29386-// license that can be found in the LICENSE file. 29387- 29388-package lsp 29389- 29390-import ( 29391- "context" 29392- "fmt" 29393- "sort" 29394- "strings" 29395- 29396- "golang.org/x/tools/gopls/internal/lsp/command" 29397- "golang.org/x/tools/gopls/internal/lsp/mod" 29398- "golang.org/x/tools/gopls/internal/lsp/protocol" 29399- "golang.org/x/tools/gopls/internal/lsp/source" 29400- "golang.org/x/tools/gopls/internal/span" 29401- "golang.org/x/tools/internal/event" 29402- "golang.org/x/tools/internal/event/tag" 29403- "golang.org/x/tools/internal/imports" 29404-) 29405- 29406-func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) { 29407- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 29408- defer release() 29409- if !ok { 29410- return nil, err 29411- } 29412- uri := fh.URI() 29413- 29414- // Determine the supported actions for this file kind. 29415- kind := snapshot.View().FileKind(fh) 29416- supportedCodeActions, ok := snapshot.View().Options().SupportedCodeActions[kind] 29417- if !ok { 29418- return nil, fmt.Errorf("no supported code actions for %v file kind", kind) 29419- } 29420- 29421- // The Only field of the context specifies which code actions the client wants. 29422- // If Only is empty, assume that the client wants all of the non-explicit code actions. 29423- var wanted map[protocol.CodeActionKind]bool 29424- 29425- // Explicit Code Actions are opt-in and shouldn't be returned to the client unless 29426- // requested using Only. 29427- // TODO: Add other CodeLenses such as GoGenerate, RegenerateCgo, etc.. 29428- explicit := map[protocol.CodeActionKind]bool{ 29429- protocol.GoTest: true, 29430- } 29431- 29432- if len(params.Context.Only) == 0 { 29433- wanted = supportedCodeActions 29434- } else { 29435- wanted = make(map[protocol.CodeActionKind]bool) 29436- for _, only := range params.Context.Only { 29437- for k, v := range supportedCodeActions { 29438- if only == k || strings.HasPrefix(string(k), string(only)+".") { 29439- wanted[k] = wanted[k] || v 29440- } 29441- } 29442- wanted[only] = wanted[only] || explicit[only] 29443- } 29444- } 29445- if len(supportedCodeActions) == 0 { 29446- return nil, nil // not an error if there are none supported 29447- } 29448- if len(wanted) == 0 { 29449- return nil, fmt.Errorf("no supported code action to execute for %s, wanted %v", uri, params.Context.Only) 29450- } 29451- 29452- var codeActions []protocol.CodeAction 29453- switch kind { 29454- case source.Mod: 29455- if diagnostics := params.Context.Diagnostics; len(diagnostics) > 0 { 29456- diags, err := mod.ModDiagnostics(ctx, snapshot, fh) 29457- if source.IsNonFatalGoModError(err) { 29458- return nil, nil 29459- } 29460- if err != nil { 29461- return nil, err 29462- } 29463- udiags, err := mod.ModUpgradeDiagnostics(ctx, snapshot, fh) 29464- if err != nil { 29465- return nil, err 29466- } 29467- quickFixes, err := codeActionsMatchingDiagnostics(ctx, snapshot, diagnostics, append(diags, udiags...)) 29468- if err != nil { 29469- return nil, err 29470- } 29471- codeActions = append(codeActions, quickFixes...) 29472- 29473- vdiags, err := mod.ModVulnerabilityDiagnostics(ctx, snapshot, fh) 29474- if err != nil { 29475- return nil, err 29476- } 29477- // Group vulnerabilities by location and then limit which code actions we return 29478- // for each location. 29479- m := make(map[protocol.Range][]*source.Diagnostic) 29480- for _, v := range vdiags { 29481- m[v.Range] = append(m[v.Range], v) 29482- } 29483- for _, sdiags := range m { 29484- quickFixes, err = codeActionsMatchingDiagnostics(ctx, snapshot, diagnostics, sdiags) 29485- if err != nil { 29486- return nil, err 29487- } 29488- quickFixes = mod.SelectUpgradeCodeActions(quickFixes) 29489- codeActions = append(codeActions, quickFixes...) 29490- } 29491- } 29492- case source.Go: 29493- // Don't suggest fixes for generated files, since they are generally 29494- // not useful and some editors may apply them automatically on save. 29495- if source.IsGenerated(ctx, snapshot, uri) { 29496- return nil, nil 29497- } 29498- diagnostics := params.Context.Diagnostics 29499- 29500- // First, process any missing imports and pair them with the 29501- // diagnostics they fix. 29502- if wantQuickFixes := wanted[protocol.QuickFix] && len(diagnostics) > 0; wantQuickFixes || wanted[protocol.SourceOrganizeImports] { 29503- importEdits, importEditsPerFix, err := source.AllImportsFixes(ctx, snapshot, fh) 29504- if err != nil { 29505- event.Error(ctx, "imports fixes", err, tag.File.Of(fh.URI().Filename())) 29506- } 29507- // Separate this into a set of codeActions per diagnostic, where 29508- // each action is the addition, removal, or renaming of one import. 29509- if wantQuickFixes { 29510- for _, importFix := range importEditsPerFix { 29511- fixes := importDiagnostics(importFix.Fix, diagnostics) 29512- if len(fixes) == 0 { 29513- continue 29514- } 29515- codeActions = append(codeActions, protocol.CodeAction{ 29516- Title: importFixTitle(importFix.Fix), 29517- Kind: protocol.QuickFix, 29518- Edit: &protocol.WorkspaceEdit{ 29519- DocumentChanges: documentChanges(fh, importFix.Edits), 29520- }, 29521- Diagnostics: fixes, 29522- }) 29523- } 29524- } 29525- 29526- // Send all of the import edits as one code action if the file is 29527- // being organized. 29528- if wanted[protocol.SourceOrganizeImports] && len(importEdits) > 0 { 29529- codeActions = append(codeActions, protocol.CodeAction{ 29530- Title: "Organize Imports", 29531- Kind: protocol.SourceOrganizeImports, 29532- Edit: &protocol.WorkspaceEdit{ 29533- DocumentChanges: documentChanges(fh, importEdits), 29534- }, 29535- }) 29536- } 29537- } 29538- if ctx.Err() != nil { 29539- return nil, ctx.Err() 29540- } 29541- 29542- // Type-check the package and also run analysis, 29543- // then combine their diagnostics. 29544- pkg, _, err := source.PackageForFile(ctx, snapshot, fh.URI(), source.NarrowestPackage) 29545- if err != nil { 29546- return nil, err 29547- } 29548- pkgDiags, err := pkg.DiagnosticsForFile(ctx, snapshot, uri) 29549- if err != nil { 29550- return nil, err 29551- } 29552- analysisDiags, err := source.Analyze(ctx, snapshot, pkg.Metadata().ID, true) 29553- if err != nil { 29554- return nil, err 29555- } 29556- var fileDiags []*source.Diagnostic 29557- source.CombineDiagnostics(pkgDiags, analysisDiags[uri], &fileDiags, &fileDiags) 29558- 29559- // Split diagnostics into fixes, which must match incoming diagnostics, 29560- // and non-fixes, which must match the requested range. Build actions 29561- // for all of them. 29562- var fixDiags, nonFixDiags []*source.Diagnostic 29563- for _, d := range fileDiags { 29564- if len(d.SuggestedFixes) == 0 { 29565- continue 29566- } 29567- var isFix bool 29568- for _, fix := range d.SuggestedFixes { 29569- if fix.ActionKind == protocol.QuickFix || fix.ActionKind == protocol.SourceFixAll { 29570- isFix = true 29571- break 29572- } 29573- } 29574- if isFix { 29575- fixDiags = append(fixDiags, d) 29576- } else { 29577- nonFixDiags = append(nonFixDiags, d) 29578- } 29579- } 29580- 29581- fixActions, err := codeActionsMatchingDiagnostics(ctx, snapshot, diagnostics, fixDiags) 29582- if err != nil { 29583- return nil, err 29584- } 29585- codeActions = append(codeActions, fixActions...) 29586- 29587- for _, nonfix := range nonFixDiags { 29588- // For now, only show diagnostics for matching lines. Maybe we should 29589- // alter this behavior in the future, depending on the user experience. 29590- if !protocol.Intersect(nonfix.Range, params.Range) { 29591- continue 29592- } 29593- actions, err := codeActionsForDiagnostic(ctx, snapshot, nonfix, nil) 29594- if err != nil { 29595- return nil, err 29596- } 29597- codeActions = append(codeActions, actions...) 29598- } 29599- 29600- if wanted[protocol.RefactorExtract] { 29601- fixes, err := extractionFixes(ctx, snapshot, uri, params.Range) 29602- if err != nil { 29603- return nil, err 29604- } 29605- codeActions = append(codeActions, fixes...) 29606- } 29607- 29608- if wanted[protocol.GoTest] { 29609- fixes, err := goTest(ctx, snapshot, uri, params.Range) 29610- if err != nil { 29611- return nil, err 29612- } 29613- codeActions = append(codeActions, fixes...) 29614- } 29615- 29616- default: 29617- // Unsupported file kind for a code action. 29618- return nil, nil 29619- } 29620- 29621- var filtered []protocol.CodeAction 29622- for _, action := range codeActions { 29623- if wanted[action.Kind] { 29624- filtered = append(filtered, action) 29625- } 29626- } 29627- return filtered, nil 29628-} 29629- 29630-func (s *Server) getSupportedCodeActions() []protocol.CodeActionKind { 29631- allCodeActionKinds := make(map[protocol.CodeActionKind]struct{}) 29632- for _, kinds := range s.session.Options().SupportedCodeActions { 29633- for kind := range kinds { 29634- allCodeActionKinds[kind] = struct{}{} 29635- } 29636- } 29637- var result []protocol.CodeActionKind 29638- for kind := range allCodeActionKinds { 29639- result = append(result, kind) 29640- } 29641- sort.Slice(result, func(i, j int) bool { 29642- return result[i] < result[j] 29643- }) 29644- return result 29645-} 29646- 29647-func importFixTitle(fix *imports.ImportFix) string { 29648- var str string 29649- switch fix.FixType { 29650- case imports.AddImport: 29651- str = fmt.Sprintf("Add import: %s %q", fix.StmtInfo.Name, fix.StmtInfo.ImportPath) 29652- case imports.DeleteImport: 29653- str = fmt.Sprintf("Delete import: %s %q", fix.StmtInfo.Name, fix.StmtInfo.ImportPath) 29654- case imports.SetImportName: 29655- str = fmt.Sprintf("Rename import: %s %q", fix.StmtInfo.Name, fix.StmtInfo.ImportPath) 29656- } 29657- return str 29658-} 29659- 29660-func importDiagnostics(fix *imports.ImportFix, diagnostics []protocol.Diagnostic) (results []protocol.Diagnostic) { 29661- for _, diagnostic := range diagnostics { 29662- switch { 29663- // "undeclared name: X" may be an unresolved import. 29664- case strings.HasPrefix(diagnostic.Message, "undeclared name: "): 29665- ident := strings.TrimPrefix(diagnostic.Message, "undeclared name: ") 29666- if ident == fix.IdentName { 29667- results = append(results, diagnostic) 29668- } 29669- // "undefined: X" may be an unresolved import at Go 1.20+. 29670- case strings.HasPrefix(diagnostic.Message, "undefined: "): 29671- ident := strings.TrimPrefix(diagnostic.Message, "undefined: ") 29672- if ident == fix.IdentName { 29673- results = append(results, diagnostic) 29674- } 29675- // "could not import: X" may be an invalid import. 29676- case strings.HasPrefix(diagnostic.Message, "could not import: "): 29677- ident := strings.TrimPrefix(diagnostic.Message, "could not import: ") 29678- if ident == fix.IdentName { 29679- results = append(results, diagnostic) 29680- } 29681- // "X imported but not used" is an unused import. 29682- // "X imported but not used as Y" is an unused import. 29683- case strings.Contains(diagnostic.Message, " imported but not used"): 29684- idx := strings.Index(diagnostic.Message, " imported but not used") 29685- importPath := diagnostic.Message[:idx] 29686- if importPath == fmt.Sprintf("%q", fix.StmtInfo.ImportPath) { 29687- results = append(results, diagnostic) 29688- } 29689- } 29690- } 29691- return results 29692-} 29693- 29694-func extractionFixes(ctx context.Context, snapshot source.Snapshot, uri span.URI, rng protocol.Range) ([]protocol.CodeAction, error) { 29695- if rng.Start == rng.End { 29696- return nil, nil 29697- } 29698- fh, err := snapshot.GetFile(ctx, uri) 29699- if err != nil { 29700- return nil, err 29701- } 29702- pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull) 29703- if err != nil { 29704- return nil, fmt.Errorf("getting file for Identifier: %w", err) 29705- } 29706- start, end, err := pgf.RangePos(rng) 29707- if err != nil { 29708- return nil, err 29709- } 29710- puri := protocol.URIFromSpanURI(uri) 29711- var commands []protocol.Command 29712- if _, ok, methodOk, _ := source.CanExtractFunction(pgf.Tok, start, end, pgf.Src, pgf.File); ok { 29713- cmd, err := command.NewApplyFixCommand("Extract function", command.ApplyFixArgs{ 29714- URI: puri, 29715- Fix: source.ExtractFunction, 29716- Range: rng, 29717- }) 29718- if err != nil { 29719- return nil, err 29720- } 29721- commands = append(commands, cmd) 29722- if methodOk { 29723- cmd, err := command.NewApplyFixCommand("Extract method", command.ApplyFixArgs{ 29724- URI: puri, 29725- Fix: source.ExtractMethod, 29726- Range: rng, 29727- }) 29728- if err != nil { 29729- return nil, err 29730- } 29731- commands = append(commands, cmd) 29732- } 29733- } 29734- if _, _, ok, _ := source.CanExtractVariable(start, end, pgf.File); ok { 29735- cmd, err := command.NewApplyFixCommand("Extract variable", command.ApplyFixArgs{ 29736- URI: puri, 29737- Fix: source.ExtractVariable, 29738- Range: rng, 29739- }) 29740- if err != nil { 29741- return nil, err 29742- } 29743- commands = append(commands, cmd) 29744- } 29745- var actions []protocol.CodeAction 29746- for i := range commands { 29747- actions = append(actions, protocol.CodeAction{ 29748- Title: commands[i].Title, 29749- Kind: protocol.RefactorExtract, 29750- Command: &commands[i], 29751- }) 29752- } 29753- return actions, nil 29754-} 29755- 29756-func documentChanges(fh source.FileHandle, edits []protocol.TextEdit) []protocol.DocumentChanges { 29757- return []protocol.DocumentChanges{ 29758- { 29759- TextDocumentEdit: &protocol.TextDocumentEdit{ 29760- TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{ 29761- Version: fh.Version(), 29762- TextDocumentIdentifier: protocol.TextDocumentIdentifier{ 29763- URI: protocol.URIFromSpanURI(fh.URI()), 29764- }, 29765- }, 29766- Edits: edits, 29767- }, 29768- }, 29769- } 29770-} 29771- 29772-func codeActionsMatchingDiagnostics(ctx context.Context, snapshot source.Snapshot, pdiags []protocol.Diagnostic, sdiags []*source.Diagnostic) ([]protocol.CodeAction, error) { 29773- var actions []protocol.CodeAction 29774- for _, sd := range sdiags { 29775- var diag *protocol.Diagnostic 29776- for _, pd := range pdiags { 29777- if sameDiagnostic(pd, sd) { 29778- diag = &pd 29779- break 29780- } 29781- } 29782- if diag == nil { 29783- continue 29784- } 29785- diagActions, err := codeActionsForDiagnostic(ctx, snapshot, sd, diag) 29786- if err != nil { 29787- return nil, err 29788- } 29789- actions = append(actions, diagActions...) 29790- 29791- } 29792- return actions, nil 29793-} 29794- 29795-func codeActionsForDiagnostic(ctx context.Context, snapshot source.Snapshot, sd *source.Diagnostic, pd *protocol.Diagnostic) ([]protocol.CodeAction, error) { 29796- var actions []protocol.CodeAction 29797- for _, fix := range sd.SuggestedFixes { 29798- var changes []protocol.DocumentChanges 29799- for uri, edits := range fix.Edits { 29800- fh, err := snapshot.GetFile(ctx, uri) 29801- if err != nil { 29802- return nil, err 29803- } 29804- changes = append(changes, documentChanges(fh, edits)...) 29805- } 29806- action := protocol.CodeAction{ 29807- Title: fix.Title, 29808- Kind: fix.ActionKind, 29809- Edit: &protocol.WorkspaceEdit{ 29810- DocumentChanges: changes, 29811- }, 29812- Command: fix.Command, 29813- } 29814- if pd != nil { 29815- action.Diagnostics = []protocol.Diagnostic{*pd} 29816- } 29817- actions = append(actions, action) 29818- } 29819- return actions, nil 29820-} 29821- 29822-func sameDiagnostic(pd protocol.Diagnostic, sd *source.Diagnostic) bool { 29823- return pd.Message == strings.TrimSpace(sd.Message) && // extra space may have been trimmed when converting to protocol.Diagnostic 29824- protocol.CompareRange(pd.Range, sd.Range) == 0 && pd.Source == string(sd.Source) 29825-} 29826- 29827-func goTest(ctx context.Context, snapshot source.Snapshot, uri span.URI, rng protocol.Range) ([]protocol.CodeAction, error) { 29828- fh, err := snapshot.GetFile(ctx, uri) 29829- if err != nil { 29830- return nil, err 29831- } 29832- fns, err := source.TestsAndBenchmarks(ctx, snapshot, fh) 29833- if err != nil { 29834- return nil, err 29835- } 29836- 29837- var tests, benchmarks []string 29838- for _, fn := range fns.Tests { 29839- if !protocol.Intersect(fn.Rng, rng) { 29840- continue 29841- } 29842- tests = append(tests, fn.Name) 29843- } 29844- for _, fn := range fns.Benchmarks { 29845- if !protocol.Intersect(fn.Rng, rng) { 29846- continue 29847- } 29848- benchmarks = append(benchmarks, fn.Name) 29849- } 29850- 29851- if len(tests) == 0 && len(benchmarks) == 0 { 29852- return nil, nil 29853- } 29854- 29855- cmd, err := command.NewTestCommand("Run tests and benchmarks", protocol.URIFromSpanURI(uri), tests, benchmarks) 29856- if err != nil { 29857- return nil, err 29858- } 29859- return []protocol.CodeAction{{ 29860- Title: cmd.Title, 29861- Kind: protocol.GoTest, 29862- Command: &cmd, 29863- }}, nil 29864-} 29865diff -urN a/gopls/internal/lsp/code_lens.go b/gopls/internal/lsp/code_lens.go 29866--- a/gopls/internal/lsp/code_lens.go 2000-01-01 00:00:00.000000000 -0000 29867+++ b/gopls/internal/lsp/code_lens.go 1970-01-01 00:00:00.000000000 +0000 29868@@ -1,57 +0,0 @@ 29869-// Copyright 2020 The Go Authors. All rights reserved. 29870-// Use of this source code is governed by a BSD-style 29871-// license that can be found in the LICENSE file. 29872- 29873-package lsp 29874- 29875-import ( 29876- "context" 29877- "fmt" 29878- "sort" 29879- 29880- "golang.org/x/tools/gopls/internal/lsp/command" 29881- "golang.org/x/tools/gopls/internal/lsp/mod" 29882- "golang.org/x/tools/gopls/internal/lsp/protocol" 29883- "golang.org/x/tools/gopls/internal/lsp/source" 29884- "golang.org/x/tools/internal/event" 29885-) 29886- 29887-func (s *Server) codeLens(ctx context.Context, params *protocol.CodeLensParams) ([]protocol.CodeLens, error) { 29888- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 29889- defer release() 29890- if !ok { 29891- return nil, err 29892- } 29893- var lenses map[command.Command]source.LensFunc 29894- switch snapshot.View().FileKind(fh) { 29895- case source.Mod: 29896- lenses = mod.LensFuncs() 29897- case source.Go: 29898- lenses = source.LensFuncs() 29899- default: 29900- // Unsupported file kind for a code lens. 29901- return nil, nil 29902- } 29903- var result []protocol.CodeLens 29904- for cmd, lf := range lenses { 29905- if !snapshot.View().Options().Codelenses[string(cmd)] { 29906- continue 29907- } 29908- added, err := lf(ctx, snapshot, fh) 29909- // Code lens is called on every keystroke, so we should just operate in 29910- // a best-effort mode, ignoring errors. 29911- if err != nil { 29912- event.Error(ctx, fmt.Sprintf("code lens %s failed", cmd), err) 29913- continue 29914- } 29915- result = append(result, added...) 29916- } 29917- sort.Slice(result, func(i, j int) bool { 29918- a, b := result[i], result[j] 29919- if cmp := protocol.CompareRange(a.Range, b.Range); cmp != 0 { 29920- return cmp < 0 29921- } 29922- return a.Command.Command < b.Command.Command 29923- }) 29924- return result, nil 29925-} 29926diff -urN a/gopls/internal/lsp/command/command_gen.go b/gopls/internal/lsp/command/command_gen.go 29927--- a/gopls/internal/lsp/command/command_gen.go 2000-01-01 00:00:00.000000000 -0000 29928+++ b/gopls/internal/lsp/command/command_gen.go 1970-01-01 00:00:00.000000000 +0000 29929@@ -1,509 +0,0 @@ 29930-// Copyright 2021 The Go Authors. All rights reserved. 29931-// Use of this source code is governed by a BSD-style 29932-// license that can be found in the LICENSE file. 29933- 29934-// Don't include this file during code generation, or it will break the build 29935-// if existing interface methods have been modified. 29936-//go:build !generate 29937-// +build !generate 29938- 29939-package command 29940- 29941-// Code generated by generate.go. DO NOT EDIT. 29942- 29943-import ( 29944- "context" 29945- "fmt" 29946- 29947- "golang.org/x/tools/gopls/internal/lsp/protocol" 29948-) 29949- 29950-const ( 29951- AddDependency Command = "add_dependency" 29952- AddImport Command = "add_import" 29953- ApplyFix Command = "apply_fix" 29954- CheckUpgrades Command = "check_upgrades" 29955- EditGoDirective Command = "edit_go_directive" 29956- FetchVulncheckResult Command = "fetch_vulncheck_result" 29957- GCDetails Command = "gc_details" 29958- Generate Command = "generate" 29959- GoGetPackage Command = "go_get_package" 29960- ListImports Command = "list_imports" 29961- ListKnownPackages Command = "list_known_packages" 29962- MemStats Command = "mem_stats" 29963- RegenerateCgo Command = "regenerate_cgo" 29964- RemoveDependency Command = "remove_dependency" 29965- ResetGoModDiagnostics Command = "reset_go_mod_diagnostics" 29966- RunGovulncheck Command = "run_govulncheck" 29967- RunTests Command = "run_tests" 29968- StartDebugging Command = "start_debugging" 29969- Test Command = "test" 29970- Tidy Command = "tidy" 29971- ToggleGCDetails Command = "toggle_gc_details" 29972- UpdateGoSum Command = "update_go_sum" 29973- UpgradeDependency Command = "upgrade_dependency" 29974- Vendor Command = "vendor" 29975-) 29976- 29977-var Commands = []Command{ 29978- AddDependency, 29979- AddImport, 29980- ApplyFix, 29981- CheckUpgrades, 29982- EditGoDirective, 29983- FetchVulncheckResult, 29984- GCDetails, 29985- Generate, 29986- GoGetPackage, 29987- ListImports, 29988- ListKnownPackages, 29989- MemStats, 29990- RegenerateCgo, 29991- RemoveDependency, 29992- ResetGoModDiagnostics, 29993- RunGovulncheck, 29994- RunTests, 29995- StartDebugging, 29996- Test, 29997- Tidy, 29998- ToggleGCDetails, 29999- UpdateGoSum, 30000- UpgradeDependency, 30001- Vendor, 30002-} 30003- 30004-func Dispatch(ctx context.Context, params *protocol.ExecuteCommandParams, s Interface) (interface{}, error) { 30005- switch params.Command { 30006- case "gopls.add_dependency": 30007- var a0 DependencyArgs 30008- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30009- return nil, err 30010- } 30011- return nil, s.AddDependency(ctx, a0) 30012- case "gopls.add_import": 30013- var a0 AddImportArgs 30014- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30015- return nil, err 30016- } 30017- return nil, s.AddImport(ctx, a0) 30018- case "gopls.apply_fix": 30019- var a0 ApplyFixArgs 30020- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30021- return nil, err 30022- } 30023- return nil, s.ApplyFix(ctx, a0) 30024- case "gopls.check_upgrades": 30025- var a0 CheckUpgradesArgs 30026- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30027- return nil, err 30028- } 30029- return nil, s.CheckUpgrades(ctx, a0) 30030- case "gopls.edit_go_directive": 30031- var a0 EditGoDirectiveArgs 30032- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30033- return nil, err 30034- } 30035- return nil, s.EditGoDirective(ctx, a0) 30036- case "gopls.fetch_vulncheck_result": 30037- var a0 URIArg 30038- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30039- return nil, err 30040- } 30041- return s.FetchVulncheckResult(ctx, a0) 30042- case "gopls.gc_details": 30043- var a0 protocol.DocumentURI 30044- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30045- return nil, err 30046- } 30047- return nil, s.GCDetails(ctx, a0) 30048- case "gopls.generate": 30049- var a0 GenerateArgs 30050- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30051- return nil, err 30052- } 30053- return nil, s.Generate(ctx, a0) 30054- case "gopls.go_get_package": 30055- var a0 GoGetPackageArgs 30056- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30057- return nil, err 30058- } 30059- return nil, s.GoGetPackage(ctx, a0) 30060- case "gopls.list_imports": 30061- var a0 URIArg 30062- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30063- return nil, err 30064- } 30065- return s.ListImports(ctx, a0) 30066- case "gopls.list_known_packages": 30067- var a0 URIArg 30068- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30069- return nil, err 30070- } 30071- return s.ListKnownPackages(ctx, a0) 30072- case "gopls.mem_stats": 30073- return s.MemStats(ctx) 30074- case "gopls.regenerate_cgo": 30075- var a0 URIArg 30076- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30077- return nil, err 30078- } 30079- return nil, s.RegenerateCgo(ctx, a0) 30080- case "gopls.remove_dependency": 30081- var a0 RemoveDependencyArgs 30082- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30083- return nil, err 30084- } 30085- return nil, s.RemoveDependency(ctx, a0) 30086- case "gopls.reset_go_mod_diagnostics": 30087- var a0 ResetGoModDiagnosticsArgs 30088- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30089- return nil, err 30090- } 30091- return nil, s.ResetGoModDiagnostics(ctx, a0) 30092- case "gopls.run_govulncheck": 30093- var a0 VulncheckArgs 30094- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30095- return nil, err 30096- } 30097- return s.RunGovulncheck(ctx, a0) 30098- case "gopls.run_tests": 30099- var a0 RunTestsArgs 30100- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30101- return nil, err 30102- } 30103- return nil, s.RunTests(ctx, a0) 30104- case "gopls.start_debugging": 30105- var a0 DebuggingArgs 30106- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30107- return nil, err 30108- } 30109- return s.StartDebugging(ctx, a0) 30110- case "gopls.test": 30111- var a0 protocol.DocumentURI 30112- var a1 []string 30113- var a2 []string 30114- if err := UnmarshalArgs(params.Arguments, &a0, &a1, &a2); err != nil { 30115- return nil, err 30116- } 30117- return nil, s.Test(ctx, a0, a1, a2) 30118- case "gopls.tidy": 30119- var a0 URIArgs 30120- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30121- return nil, err 30122- } 30123- return nil, s.Tidy(ctx, a0) 30124- case "gopls.toggle_gc_details": 30125- var a0 URIArg 30126- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30127- return nil, err 30128- } 30129- return nil, s.ToggleGCDetails(ctx, a0) 30130- case "gopls.update_go_sum": 30131- var a0 URIArgs 30132- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30133- return nil, err 30134- } 30135- return nil, s.UpdateGoSum(ctx, a0) 30136- case "gopls.upgrade_dependency": 30137- var a0 DependencyArgs 30138- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30139- return nil, err 30140- } 30141- return nil, s.UpgradeDependency(ctx, a0) 30142- case "gopls.vendor": 30143- var a0 URIArg 30144- if err := UnmarshalArgs(params.Arguments, &a0); err != nil { 30145- return nil, err 30146- } 30147- return nil, s.Vendor(ctx, a0) 30148- } 30149- return nil, fmt.Errorf("unsupported command %q", params.Command) 30150-} 30151- 30152-func NewAddDependencyCommand(title string, a0 DependencyArgs) (protocol.Command, error) { 30153- args, err := MarshalArgs(a0) 30154- if err != nil { 30155- return protocol.Command{}, err 30156- } 30157- return protocol.Command{ 30158- Title: title, 30159- Command: "gopls.add_dependency", 30160- Arguments: args, 30161- }, nil 30162-} 30163- 30164-func NewAddImportCommand(title string, a0 AddImportArgs) (protocol.Command, error) { 30165- args, err := MarshalArgs(a0) 30166- if err != nil { 30167- return protocol.Command{}, err 30168- } 30169- return protocol.Command{ 30170- Title: title, 30171- Command: "gopls.add_import", 30172- Arguments: args, 30173- }, nil 30174-} 30175- 30176-func NewApplyFixCommand(title string, a0 ApplyFixArgs) (protocol.Command, error) { 30177- args, err := MarshalArgs(a0) 30178- if err != nil { 30179- return protocol.Command{}, err 30180- } 30181- return protocol.Command{ 30182- Title: title, 30183- Command: "gopls.apply_fix", 30184- Arguments: args, 30185- }, nil 30186-} 30187- 30188-func NewCheckUpgradesCommand(title string, a0 CheckUpgradesArgs) (protocol.Command, error) { 30189- args, err := MarshalArgs(a0) 30190- if err != nil { 30191- return protocol.Command{}, err 30192- } 30193- return protocol.Command{ 30194- Title: title, 30195- Command: "gopls.check_upgrades", 30196- Arguments: args, 30197- }, nil 30198-} 30199- 30200-func NewEditGoDirectiveCommand(title string, a0 EditGoDirectiveArgs) (protocol.Command, error) { 30201- args, err := MarshalArgs(a0) 30202- if err != nil { 30203- return protocol.Command{}, err 30204- } 30205- return protocol.Command{ 30206- Title: title, 30207- Command: "gopls.edit_go_directive", 30208- Arguments: args, 30209- }, nil 30210-} 30211- 30212-func NewFetchVulncheckResultCommand(title string, a0 URIArg) (protocol.Command, error) { 30213- args, err := MarshalArgs(a0) 30214- if err != nil { 30215- return protocol.Command{}, err 30216- } 30217- return protocol.Command{ 30218- Title: title, 30219- Command: "gopls.fetch_vulncheck_result", 30220- Arguments: args, 30221- }, nil 30222-} 30223- 30224-func NewGCDetailsCommand(title string, a0 protocol.DocumentURI) (protocol.Command, error) { 30225- args, err := MarshalArgs(a0) 30226- if err != nil { 30227- return protocol.Command{}, err 30228- } 30229- return protocol.Command{ 30230- Title: title, 30231- Command: "gopls.gc_details", 30232- Arguments: args, 30233- }, nil 30234-} 30235- 30236-func NewGenerateCommand(title string, a0 GenerateArgs) (protocol.Command, error) { 30237- args, err := MarshalArgs(a0) 30238- if err != nil { 30239- return protocol.Command{}, err 30240- } 30241- return protocol.Command{ 30242- Title: title, 30243- Command: "gopls.generate", 30244- Arguments: args, 30245- }, nil 30246-} 30247- 30248-func NewGoGetPackageCommand(title string, a0 GoGetPackageArgs) (protocol.Command, error) { 30249- args, err := MarshalArgs(a0) 30250- if err != nil { 30251- return protocol.Command{}, err 30252- } 30253- return protocol.Command{ 30254- Title: title, 30255- Command: "gopls.go_get_package", 30256- Arguments: args, 30257- }, nil 30258-} 30259- 30260-func NewListImportsCommand(title string, a0 URIArg) (protocol.Command, error) { 30261- args, err := MarshalArgs(a0) 30262- if err != nil { 30263- return protocol.Command{}, err 30264- } 30265- return protocol.Command{ 30266- Title: title, 30267- Command: "gopls.list_imports", 30268- Arguments: args, 30269- }, nil 30270-} 30271- 30272-func NewListKnownPackagesCommand(title string, a0 URIArg) (protocol.Command, error) { 30273- args, err := MarshalArgs(a0) 30274- if err != nil { 30275- return protocol.Command{}, err 30276- } 30277- return protocol.Command{ 30278- Title: title, 30279- Command: "gopls.list_known_packages", 30280- Arguments: args, 30281- }, nil 30282-} 30283- 30284-func NewMemStatsCommand(title string) (protocol.Command, error) { 30285- args, err := MarshalArgs() 30286- if err != nil { 30287- return protocol.Command{}, err 30288- } 30289- return protocol.Command{ 30290- Title: title, 30291- Command: "gopls.mem_stats", 30292- Arguments: args, 30293- }, nil 30294-} 30295- 30296-func NewRegenerateCgoCommand(title string, a0 URIArg) (protocol.Command, error) { 30297- args, err := MarshalArgs(a0) 30298- if err != nil { 30299- return protocol.Command{}, err 30300- } 30301- return protocol.Command{ 30302- Title: title, 30303- Command: "gopls.regenerate_cgo", 30304- Arguments: args, 30305- }, nil 30306-} 30307- 30308-func NewRemoveDependencyCommand(title string, a0 RemoveDependencyArgs) (protocol.Command, error) { 30309- args, err := MarshalArgs(a0) 30310- if err != nil { 30311- return protocol.Command{}, err 30312- } 30313- return protocol.Command{ 30314- Title: title, 30315- Command: "gopls.remove_dependency", 30316- Arguments: args, 30317- }, nil 30318-} 30319- 30320-func NewResetGoModDiagnosticsCommand(title string, a0 ResetGoModDiagnosticsArgs) (protocol.Command, error) { 30321- args, err := MarshalArgs(a0) 30322- if err != nil { 30323- return protocol.Command{}, err 30324- } 30325- return protocol.Command{ 30326- Title: title, 30327- Command: "gopls.reset_go_mod_diagnostics", 30328- Arguments: args, 30329- }, nil 30330-} 30331- 30332-func NewRunGovulncheckCommand(title string, a0 VulncheckArgs) (protocol.Command, error) { 30333- args, err := MarshalArgs(a0) 30334- if err != nil { 30335- return protocol.Command{}, err 30336- } 30337- return protocol.Command{ 30338- Title: title, 30339- Command: "gopls.run_govulncheck", 30340- Arguments: args, 30341- }, nil 30342-} 30343- 30344-func NewRunTestsCommand(title string, a0 RunTestsArgs) (protocol.Command, error) { 30345- args, err := MarshalArgs(a0) 30346- if err != nil { 30347- return protocol.Command{}, err 30348- } 30349- return protocol.Command{ 30350- Title: title, 30351- Command: "gopls.run_tests", 30352- Arguments: args, 30353- }, nil 30354-} 30355- 30356-func NewStartDebuggingCommand(title string, a0 DebuggingArgs) (protocol.Command, error) { 30357- args, err := MarshalArgs(a0) 30358- if err != nil { 30359- return protocol.Command{}, err 30360- } 30361- return protocol.Command{ 30362- Title: title, 30363- Command: "gopls.start_debugging", 30364- Arguments: args, 30365- }, nil 30366-} 30367- 30368-func NewTestCommand(title string, a0 protocol.DocumentURI, a1 []string, a2 []string) (protocol.Command, error) { 30369- args, err := MarshalArgs(a0, a1, a2) 30370- if err != nil { 30371- return protocol.Command{}, err 30372- } 30373- return protocol.Command{ 30374- Title: title, 30375- Command: "gopls.test", 30376- Arguments: args, 30377- }, nil 30378-} 30379- 30380-func NewTidyCommand(title string, a0 URIArgs) (protocol.Command, error) { 30381- args, err := MarshalArgs(a0) 30382- if err != nil { 30383- return protocol.Command{}, err 30384- } 30385- return protocol.Command{ 30386- Title: title, 30387- Command: "gopls.tidy", 30388- Arguments: args, 30389- }, nil 30390-} 30391- 30392-func NewToggleGCDetailsCommand(title string, a0 URIArg) (protocol.Command, error) { 30393- args, err := MarshalArgs(a0) 30394- if err != nil { 30395- return protocol.Command{}, err 30396- } 30397- return protocol.Command{ 30398- Title: title, 30399- Command: "gopls.toggle_gc_details", 30400- Arguments: args, 30401- }, nil 30402-} 30403- 30404-func NewUpdateGoSumCommand(title string, a0 URIArgs) (protocol.Command, error) { 30405- args, err := MarshalArgs(a0) 30406- if err != nil { 30407- return protocol.Command{}, err 30408- } 30409- return protocol.Command{ 30410- Title: title, 30411- Command: "gopls.update_go_sum", 30412- Arguments: args, 30413- }, nil 30414-} 30415- 30416-func NewUpgradeDependencyCommand(title string, a0 DependencyArgs) (protocol.Command, error) { 30417- args, err := MarshalArgs(a0) 30418- if err != nil { 30419- return protocol.Command{}, err 30420- } 30421- return protocol.Command{ 30422- Title: title, 30423- Command: "gopls.upgrade_dependency", 30424- Arguments: args, 30425- }, nil 30426-} 30427- 30428-func NewVendorCommand(title string, a0 URIArg) (protocol.Command, error) { 30429- args, err := MarshalArgs(a0) 30430- if err != nil { 30431- return protocol.Command{}, err 30432- } 30433- return protocol.Command{ 30434- Title: title, 30435- Command: "gopls.vendor", 30436- Arguments: args, 30437- }, nil 30438-} 30439diff -urN a/gopls/internal/lsp/command/commandmeta/meta.go b/gopls/internal/lsp/command/commandmeta/meta.go 30440--- a/gopls/internal/lsp/command/commandmeta/meta.go 2000-01-01 00:00:00.000000000 -0000 30441+++ b/gopls/internal/lsp/command/commandmeta/meta.go 1970-01-01 00:00:00.000000000 +0000 30442@@ -1,259 +0,0 @@ 30443-// Copyright 2021 The Go Authors. All rights reserved. 30444-// Use of this source code is governed by a BSD-style 30445-// license that can be found in the LICENSE file. 30446- 30447-// Package commandmeta provides metadata about LSP commands, by analyzing the 30448-// command.Interface type. 30449-package commandmeta 30450- 30451-import ( 30452- "fmt" 30453- "go/ast" 30454- "go/token" 30455- "go/types" 30456- "reflect" 30457- "strings" 30458- "unicode" 30459- 30460- "golang.org/x/tools/go/ast/astutil" 30461- "golang.org/x/tools/go/packages" 30462- "golang.org/x/tools/gopls/internal/lsp/command" 30463-) 30464- 30465-type Command struct { 30466- MethodName string 30467- Name string 30468- // TODO(rFindley): I think Title can actually be eliminated. In all cases 30469- // where we use it, there is probably a more appropriate contextual title. 30470- Title string 30471- Doc string 30472- Args []*Field 30473- Result *Field 30474-} 30475- 30476-func (c *Command) ID() string { 30477- return command.ID(c.Name) 30478-} 30479- 30480-type Field struct { 30481- Name string 30482- Doc string 30483- JSONTag string 30484- Type types.Type 30485- FieldMod string 30486- // In some circumstances, we may want to recursively load additional field 30487- // descriptors for fields of struct types, documenting their internals. 30488- Fields []*Field 30489-} 30490- 30491-func Load() (*packages.Package, []*Command, error) { 30492- pkgs, err := packages.Load( 30493- &packages.Config{ 30494- Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedImports | packages.NeedDeps, 30495- BuildFlags: []string{"-tags=generate"}, 30496- }, 30497- "golang.org/x/tools/gopls/internal/lsp/command", 30498- ) 30499- if err != nil { 30500- return nil, nil, fmt.Errorf("packages.Load: %v", err) 30501- } 30502- pkg := pkgs[0] 30503- if len(pkg.Errors) > 0 { 30504- return pkg, nil, pkg.Errors[0] 30505- } 30506- 30507- // For a bit of type safety, use reflection to get the interface name within 30508- // the package scope. 30509- it := reflect.TypeOf((*command.Interface)(nil)).Elem() 30510- obj := pkg.Types.Scope().Lookup(it.Name()).Type().Underlying().(*types.Interface) 30511- 30512- // Load command metadata corresponding to each interface method. 30513- var commands []*Command 30514- loader := fieldLoader{make(map[types.Object]*Field)} 30515- for i := 0; i < obj.NumMethods(); i++ { 30516- m := obj.Method(i) 30517- c, err := loader.loadMethod(pkg, m) 30518- if err != nil { 30519- return nil, nil, fmt.Errorf("loading %s: %v", m.Name(), err) 30520- } 30521- commands = append(commands, c) 30522- } 30523- return pkg, commands, nil 30524-} 30525- 30526-// fieldLoader loads field information, memoizing results to prevent infinite 30527-// recursion. 30528-type fieldLoader struct { 30529- loaded map[types.Object]*Field 30530-} 30531- 30532-var universeError = types.Universe.Lookup("error").Type() 30533- 30534-func (l *fieldLoader) loadMethod(pkg *packages.Package, m *types.Func) (*Command, error) { 30535- node, err := findField(pkg, m.Pos()) 30536- if err != nil { 30537- return nil, err 30538- } 30539- title, doc := splitDoc(node.Doc.Text()) 30540- c := &Command{ 30541- MethodName: m.Name(), 30542- Name: lspName(m.Name()), 30543- Doc: doc, 30544- Title: title, 30545- } 30546- sig := m.Type().Underlying().(*types.Signature) 30547- rlen := sig.Results().Len() 30548- if rlen > 2 || rlen == 0 { 30549- return nil, fmt.Errorf("must have 1 or 2 returns, got %d", rlen) 30550- } 30551- finalResult := sig.Results().At(rlen - 1) 30552- if !types.Identical(finalResult.Type(), universeError) { 30553- return nil, fmt.Errorf("final return must be error") 30554- } 30555- if rlen == 2 { 30556- obj := sig.Results().At(0) 30557- c.Result, err = l.loadField(pkg, obj, "", "") 30558- if err != nil { 30559- return nil, err 30560- } 30561- } 30562- for i := 0; i < sig.Params().Len(); i++ { 30563- obj := sig.Params().At(i) 30564- fld, err := l.loadField(pkg, obj, "", "") 30565- if err != nil { 30566- return nil, err 30567- } 30568- if i == 0 { 30569- // Lazy check that the first argument is a context. We could relax this, 30570- // but then the generated code gets more complicated. 30571- if named, ok := fld.Type.(*types.Named); !ok || named.Obj().Name() != "Context" || named.Obj().Pkg().Path() != "context" { 30572- return nil, fmt.Errorf("first method parameter must be context.Context") 30573- } 30574- // Skip the context argument, as it is implied. 30575- continue 30576- } 30577- c.Args = append(c.Args, fld) 30578- } 30579- return c, nil 30580-} 30581- 30582-func (l *fieldLoader) loadField(pkg *packages.Package, obj *types.Var, doc, tag string) (*Field, error) { 30583- if existing, ok := l.loaded[obj]; ok { 30584- return existing, nil 30585- } 30586- fld := &Field{ 30587- Name: obj.Name(), 30588- Doc: strings.TrimSpace(doc), 30589- Type: obj.Type(), 30590- JSONTag: reflect.StructTag(tag).Get("json"), 30591- } 30592- under := fld.Type.Underlying() 30593- // Quick-and-dirty handling for various underlying types. 30594- switch p := under.(type) { 30595- case *types.Pointer: 30596- under = p.Elem().Underlying() 30597- case *types.Array: 30598- under = p.Elem().Underlying() 30599- fld.FieldMod = fmt.Sprintf("[%d]", p.Len()) 30600- case *types.Slice: 30601- under = p.Elem().Underlying() 30602- fld.FieldMod = "[]" 30603- } 30604- 30605- if s, ok := under.(*types.Struct); ok { 30606- for i := 0; i < s.NumFields(); i++ { 30607- obj2 := s.Field(i) 30608- pkg2 := pkg 30609- if obj2.Pkg() != pkg2.Types { 30610- pkg2, ok = pkg.Imports[obj2.Pkg().Path()] 30611- if !ok { 30612- return nil, fmt.Errorf("missing import for %q: %q", pkg.ID, obj2.Pkg().Path()) 30613- } 30614- } 30615- node, err := findField(pkg2, obj2.Pos()) 30616- if err != nil { 30617- return nil, err 30618- } 30619- tag := s.Tag(i) 30620- structField, err := l.loadField(pkg2, obj2, node.Doc.Text(), tag) 30621- if err != nil { 30622- return nil, err 30623- } 30624- fld.Fields = append(fld.Fields, structField) 30625- } 30626- } 30627- return fld, nil 30628-} 30629- 30630-// splitDoc parses a command doc string to separate the title from normal 30631-// documentation. 30632-// 30633-// The doc comment should be of the form: "MethodName: Title\nDocumentation" 30634-func splitDoc(text string) (title, doc string) { 30635- docParts := strings.SplitN(text, "\n", 2) 30636- titleParts := strings.SplitN(docParts[0], ":", 2) 30637- if len(titleParts) > 1 { 30638- title = strings.TrimSpace(titleParts[1]) 30639- } 30640- if len(docParts) > 1 { 30641- doc = strings.TrimSpace(docParts[1]) 30642- } 30643- return title, doc 30644-} 30645- 30646-// lspName returns the normalized command name to use in the LSP. 30647-func lspName(methodName string) string { 30648- words := splitCamel(methodName) 30649- for i := range words { 30650- words[i] = strings.ToLower(words[i]) 30651- } 30652- return strings.Join(words, "_") 30653-} 30654- 30655-// splitCamel splits s into words, according to camel-case word boundaries. 30656-// Initialisms are grouped as a single word. 30657-// 30658-// For example: 30659-// 30660-// "RunTests" -> []string{"Run", "Tests"} 30661-// "GCDetails" -> []string{"GC", "Details"} 30662-func splitCamel(s string) []string { 30663- var words []string 30664- for len(s) > 0 { 30665- last := strings.LastIndexFunc(s, unicode.IsUpper) 30666- if last < 0 { 30667- last = 0 30668- } 30669- if last == len(s)-1 { 30670- // Group initialisms as a single word. 30671- last = 1 + strings.LastIndexFunc(s[:last], func(r rune) bool { return !unicode.IsUpper(r) }) 30672- } 30673- words = append(words, s[last:]) 30674- s = s[:last] 30675- } 30676- for i := 0; i < len(words)/2; i++ { 30677- j := len(words) - i - 1 30678- words[i], words[j] = words[j], words[i] 30679- } 30680- return words 30681-} 30682- 30683-// findField finds the struct field or interface method positioned at pos, 30684-// within the AST. 30685-func findField(pkg *packages.Package, pos token.Pos) (*ast.Field, error) { 30686- fset := pkg.Fset 30687- var file *ast.File 30688- for _, f := range pkg.Syntax { 30689- if fset.File(f.Pos()).Name() == fset.File(pos).Name() { 30690- file = f 30691- break 30692- } 30693- } 30694- if file == nil { 30695- return nil, fmt.Errorf("no file for pos %v", pos) 30696- } 30697- path, _ := astutil.PathEnclosingInterval(file, pos, pos) 30698- // This is fragile, but in the cases we care about, the field will be in 30699- // path[1]. 30700- return path[1].(*ast.Field), nil 30701-} 30702diff -urN a/gopls/internal/lsp/command/gen/gen.go b/gopls/internal/lsp/command/gen/gen.go 30703--- a/gopls/internal/lsp/command/gen/gen.go 2000-01-01 00:00:00.000000000 -0000 30704+++ b/gopls/internal/lsp/command/gen/gen.go 1970-01-01 00:00:00.000000000 +0000 30705@@ -1,155 +0,0 @@ 30706-// Copyright 2021 The Go Authors. All rights reserved. 30707-// Use of this source code is governed by a BSD-style 30708-// license that can be found in the LICENSE file. 30709- 30710-// Package gen is used to generate command bindings from the gopls command 30711-// interface. 30712-package gen 30713- 30714-import ( 30715- "bytes" 30716- "fmt" 30717- "go/types" 30718- "text/template" 30719- 30720- "golang.org/x/tools/internal/imports" 30721- "golang.org/x/tools/gopls/internal/lsp/command/commandmeta" 30722-) 30723- 30724-const src = `// Copyright 2021 The Go Authors. All rights reserved. 30725-// Use of this source code is governed by a BSD-style 30726-// license that can be found in the LICENSE file. 30727- 30728-// Don't include this file during code generation, or it will break the build 30729-// if existing interface methods have been modified. 30730-//go:build !generate 30731-// +build !generate 30732- 30733-package command 30734- 30735-// Code generated by generate.go. DO NOT EDIT. 30736- 30737-import ( 30738- {{range $k, $v := .Imports -}} 30739- "{{$k}}" 30740- {{end}} 30741-) 30742- 30743-const ( 30744-{{- range .Commands}} 30745- {{.MethodName}} Command = "{{.Name}}" 30746-{{- end}} 30747-) 30748- 30749-var Commands = []Command { 30750-{{- range .Commands}} 30751- {{.MethodName}}, 30752-{{- end}} 30753-} 30754- 30755-func Dispatch(ctx context.Context, params *protocol.ExecuteCommandParams, s Interface) (interface{}, error) { 30756- switch params.Command { 30757- {{- range .Commands}} 30758- case "{{.ID}}": 30759- {{- if .Args -}} 30760- {{- range $i, $v := .Args}} 30761- var a{{$i}} {{typeString $v.Type}} 30762- {{- end}} 30763- if err := UnmarshalArgs(params.Arguments{{range $i, $v := .Args}}, &a{{$i}}{{end}}); err != nil { 30764- return nil, err 30765- } 30766- {{end -}} 30767- return {{if not .Result}}nil, {{end}}s.{{.MethodName}}(ctx{{range $i, $v := .Args}}, a{{$i}}{{end}}) 30768- {{- end}} 30769- } 30770- return nil, fmt.Errorf("unsupported command %q", params.Command) 30771-} 30772-{{- range .Commands}} 30773- 30774-func New{{.MethodName}}Command(title string, {{range $i, $v := .Args}}{{if $i}}, {{end}}a{{$i}} {{typeString $v.Type}}{{end}}) (protocol.Command, error) { 30775- args, err := MarshalArgs({{range $i, $v := .Args}}{{if $i}}, {{end}}a{{$i}}{{end}}) 30776- if err != nil { 30777- return protocol.Command{}, err 30778- } 30779- return protocol.Command{ 30780- Title: title, 30781- Command: "{{.ID}}", 30782- Arguments: args, 30783- }, nil 30784-} 30785-{{end}} 30786-` 30787- 30788-type data struct { 30789- Imports map[string]bool 30790- Commands []*commandmeta.Command 30791-} 30792- 30793-func Generate() ([]byte, error) { 30794- pkg, cmds, err := commandmeta.Load() 30795- if err != nil { 30796- return nil, fmt.Errorf("loading command data: %v", err) 30797- } 30798- qf := func(p *types.Package) string { 30799- if p == pkg.Types { 30800- return "" 30801- } 30802- return p.Name() 30803- } 30804- tmpl, err := template.New("").Funcs(template.FuncMap{ 30805- "typeString": func(t types.Type) string { 30806- return types.TypeString(t, qf) 30807- }, 30808- }).Parse(src) 30809- if err != nil { 30810- return nil, err 30811- } 30812- d := data{ 30813- Commands: cmds, 30814- Imports: map[string]bool{ 30815- "context": true, 30816- "fmt": true, 30817- "golang.org/x/tools/gopls/internal/lsp/protocol": true, 30818- }, 30819- } 30820- const thispkg = "golang.org/x/tools/gopls/internal/lsp/command" 30821- for _, c := range d.Commands { 30822- for _, arg := range c.Args { 30823- pth := pkgPath(arg.Type) 30824- if pth != "" && pth != thispkg { 30825- d.Imports[pth] = true 30826- } 30827- } 30828- if c.Result != nil { 30829- pth := pkgPath(c.Result.Type) 30830- if pth != "" && pth != thispkg { 30831- d.Imports[pth] = true 30832- } 30833- } 30834- } 30835- 30836- var buf bytes.Buffer 30837- if err := tmpl.Execute(&buf, d); err != nil { 30838- return nil, fmt.Errorf("executing: %v", err) 30839- } 30840- 30841- opts := &imports.Options{ 30842- AllErrors: true, 30843- FormatOnly: true, 30844- Comments: true, 30845- } 30846- content, err := imports.Process("", buf.Bytes(), opts) 30847- if err != nil { 30848- return nil, fmt.Errorf("goimports: %v", err) 30849- } 30850- return content, nil 30851-} 30852- 30853-func pkgPath(t types.Type) string { 30854- if n, ok := t.(*types.Named); ok { 30855- if pkg := n.Obj().Pkg(); pkg != nil { 30856- return pkg.Path() 30857- } 30858- } 30859- return "" 30860-} 30861diff -urN a/gopls/internal/lsp/command/generate.go b/gopls/internal/lsp/command/generate.go 30862--- a/gopls/internal/lsp/command/generate.go 2000-01-01 00:00:00.000000000 -0000 30863+++ b/gopls/internal/lsp/command/generate.go 1970-01-01 00:00:00.000000000 +0000 30864@@ -1,25 +0,0 @@ 30865-// Copyright 2021 The Go Authors. All rights reserved. 30866-// Use of this source code is governed by a BSD-style 30867-// license that can be found in the LICENSE file. 30868- 30869-//go:build ignore 30870-// +build ignore 30871- 30872-package main 30873- 30874-import ( 30875- "log" 30876- "os" 30877- 30878- "golang.org/x/tools/gopls/internal/lsp/command/gen" 30879-) 30880- 30881-func main() { 30882- content, err := gen.Generate() 30883- if err != nil { 30884- log.Fatal(err) 30885- } 30886- if err := os.WriteFile("command_gen.go", content, 0644); err != nil { 30887- log.Fatal(err) 30888- } 30889-} 30890diff -urN a/gopls/internal/lsp/command/interface.go b/gopls/internal/lsp/command/interface.go 30891--- a/gopls/internal/lsp/command/interface.go 2000-01-01 00:00:00.000000000 -0000 30892+++ b/gopls/internal/lsp/command/interface.go 1970-01-01 00:00:00.000000000 +0000 30893@@ -1,410 +0,0 @@ 30894-// Copyright 2021 The Go Authors. All rights reserved. 30895-// Use of this source code is governed by a BSD-style 30896-// license that can be found in the LICENSE file. 30897- 30898-//go:generate go run -tags=generate generate.go 30899- 30900-// Package command defines the interface provided by gopls for the 30901-// workspace/executeCommand LSP request. 30902-// 30903-// This interface is fully specified by the Interface type, provided it 30904-// conforms to the restrictions outlined in its doc string. 30905-// 30906-// Bindings for server-side command dispatch and client-side serialization are 30907-// also provided by this package, via code generation. 30908-package command 30909- 30910-import ( 30911- "context" 30912- 30913- "golang.org/x/tools/gopls/internal/govulncheck" 30914- "golang.org/x/tools/gopls/internal/lsp/protocol" 30915-) 30916- 30917-// Interface defines the interface gopls exposes for the 30918-// workspace/executeCommand request. 30919-// 30920-// This interface is used to generate marshaling/unmarshaling code, dispatch, 30921-// and documentation, and so has some additional restrictions: 30922-// 1. All method arguments must be JSON serializable. 30923-// 2. Methods must return either error or (T, error), where T is a 30924-// JSON serializable type. 30925-// 3. The first line of the doc string is special. Everything after the colon 30926-// is considered the command 'Title'. 30927-// TODO(rFindley): reconsider this -- Title may be unnecessary. 30928-type Interface interface { 30929- // ApplyFix: Apply a fix 30930- // 30931- // Applies a fix to a region of source code. 30932- ApplyFix(context.Context, ApplyFixArgs) error 30933- // Test: Run test(s) (legacy) 30934- // 30935- // Runs `go test` for a specific set of test or benchmark functions. 30936- Test(context.Context, protocol.DocumentURI, []string, []string) error 30937- 30938- // TODO: deprecate Test in favor of RunTests below. 30939- 30940- // Test: Run test(s) 30941- // 30942- // Runs `go test` for a specific set of test or benchmark functions. 30943- RunTests(context.Context, RunTestsArgs) error 30944- 30945- // Generate: Run go generate 30946- // 30947- // Runs `go generate` for a given directory. 30948- Generate(context.Context, GenerateArgs) error 30949- 30950- // RegenerateCgo: Regenerate cgo 30951- // 30952- // Regenerates cgo definitions. 30953- RegenerateCgo(context.Context, URIArg) error 30954- 30955- // Tidy: Run go mod tidy 30956- // 30957- // Runs `go mod tidy` for a module. 30958- Tidy(context.Context, URIArgs) error 30959- 30960- // Vendor: Run go mod vendor 30961- // 30962- // Runs `go mod vendor` for a module. 30963- Vendor(context.Context, URIArg) error 30964- 30965- // EditGoDirective: Run go mod edit -go=version 30966- // 30967- // Runs `go mod edit -go=version` for a module. 30968- EditGoDirective(context.Context, EditGoDirectiveArgs) error 30969- 30970- // UpdateGoSum: Update go.sum 30971- // 30972- // Updates the go.sum file for a module. 30973- UpdateGoSum(context.Context, URIArgs) error 30974- 30975- // CheckUpgrades: Check for upgrades 30976- // 30977- // Checks for module upgrades. 30978- CheckUpgrades(context.Context, CheckUpgradesArgs) error 30979- 30980- // AddDependency: Add a dependency 30981- // 30982- // Adds a dependency to the go.mod file for a module. 30983- AddDependency(context.Context, DependencyArgs) error 30984- 30985- // UpgradeDependency: Upgrade a dependency 30986- // 30987- // Upgrades a dependency in the go.mod file for a module. 30988- UpgradeDependency(context.Context, DependencyArgs) error 30989- 30990- // RemoveDependency: Remove a dependency 30991- // 30992- // Removes a dependency from the go.mod file of a module. 30993- RemoveDependency(context.Context, RemoveDependencyArgs) error 30994- 30995- // ResetGoModDiagnostics: Reset go.mod diagnostics 30996- // 30997- // Reset diagnostics in the go.mod file of a module. 30998- ResetGoModDiagnostics(context.Context, ResetGoModDiagnosticsArgs) error 30999- 31000- // GoGetPackage: go get a package 31001- // 31002- // Runs `go get` to fetch a package. 31003- GoGetPackage(context.Context, GoGetPackageArgs) error 31004- 31005- // GCDetails: Toggle gc_details 31006- // 31007- // Toggle the calculation of gc annotations. 31008- GCDetails(context.Context, protocol.DocumentURI) error 31009- 31010- // TODO: deprecate GCDetails in favor of ToggleGCDetails below. 31011- 31012- // ToggleGCDetails: Toggle gc_details 31013- // 31014- // Toggle the calculation of gc annotations. 31015- ToggleGCDetails(context.Context, URIArg) error 31016- 31017- // ListKnownPackages: List known packages 31018- // 31019- // Retrieve a list of packages that are importable from the given URI. 31020- ListKnownPackages(context.Context, URIArg) (ListKnownPackagesResult, error) 31021- 31022- // ListImports: List imports of a file and its package 31023- // 31024- // Retrieve a list of imports in the given Go file, and the package it 31025- // belongs to. 31026- ListImports(context.Context, URIArg) (ListImportsResult, error) 31027- 31028- // AddImport: Add an import 31029- // 31030- // Ask the server to add an import path to a given Go file. The method will 31031- // call applyEdit on the client so that clients don't have to apply the edit 31032- // themselves. 31033- AddImport(context.Context, AddImportArgs) error 31034- 31035- // StartDebugging: Start the gopls debug server 31036- // 31037- // Start the gopls debug server if it isn't running, and return the debug 31038- // address. 31039- StartDebugging(context.Context, DebuggingArgs) (DebuggingResult, error) 31040- 31041- // RunGovulncheck: Run govulncheck. 31042- // 31043- // Run vulnerability check (`govulncheck`). 31044- RunGovulncheck(context.Context, VulncheckArgs) (RunVulncheckResult, error) 31045- 31046- // FetchVulncheckResult: Get known vulncheck result 31047- // 31048- // Fetch the result of latest vulnerability check (`govulncheck`). 31049- FetchVulncheckResult(context.Context, URIArg) (map[protocol.DocumentURI]*govulncheck.Result, error) 31050- 31051- // MemStats: fetch memory statistics 31052- // 31053- // Call runtime.GC multiple times and return memory statistics as reported by 31054- // runtime.MemStats. 31055- // 31056- // This command is used for benchmarking, and may change in the future. 31057- MemStats(context.Context) (MemStatsResult, error) 31058-} 31059- 31060-type RunTestsArgs struct { 31061- // The test file containing the tests to run. 31062- URI protocol.DocumentURI 31063- 31064- // Specific test names to run, e.g. TestFoo. 31065- Tests []string 31066- 31067- // Specific benchmarks to run, e.g. BenchmarkFoo. 31068- Benchmarks []string 31069-} 31070- 31071-type GenerateArgs struct { 31072- // URI for the directory to generate. 31073- Dir protocol.DocumentURI 31074- 31075- // Whether to generate recursively (go generate ./...) 31076- Recursive bool 31077-} 31078- 31079-// TODO(rFindley): document the rest of these once the docgen is fleshed out. 31080- 31081-type ApplyFixArgs struct { 31082- // The fix to apply. 31083- Fix string 31084- // The file URI for the document to fix. 31085- URI protocol.DocumentURI 31086- // The document range to scan for fixes. 31087- Range protocol.Range 31088-} 31089- 31090-type URIArg struct { 31091- // The file URI. 31092- URI protocol.DocumentURI 31093-} 31094- 31095-type URIArgs struct { 31096- // The file URIs. 31097- URIs []protocol.DocumentURI 31098-} 31099- 31100-type CheckUpgradesArgs struct { 31101- // The go.mod file URI. 31102- URI protocol.DocumentURI 31103- // The modules to check. 31104- Modules []string 31105-} 31106- 31107-type DependencyArgs struct { 31108- // The go.mod file URI. 31109- URI protocol.DocumentURI 31110- // Additional args to pass to the go command. 31111- GoCmdArgs []string 31112- // Whether to add a require directive. 31113- AddRequire bool 31114-} 31115- 31116-type RemoveDependencyArgs struct { 31117- // The go.mod file URI. 31118- URI protocol.DocumentURI 31119- // The module path to remove. 31120- ModulePath string 31121- OnlyDiagnostic bool 31122-} 31123- 31124-type EditGoDirectiveArgs struct { 31125- // Any document URI within the relevant module. 31126- URI protocol.DocumentURI 31127- // The version to pass to `go mod edit -go`. 31128- Version string 31129-} 31130- 31131-type GoGetPackageArgs struct { 31132- // Any document URI within the relevant module. 31133- URI protocol.DocumentURI 31134- // The package to go get. 31135- Pkg string 31136- AddRequire bool 31137-} 31138- 31139-type AddImportArgs struct { 31140- // ImportPath is the target import path that should 31141- // be added to the URI file 31142- ImportPath string 31143- // URI is the file that the ImportPath should be 31144- // added to 31145- URI protocol.DocumentURI 31146-} 31147- 31148-type ListKnownPackagesResult struct { 31149- // Packages is a list of packages relative 31150- // to the URIArg passed by the command request. 31151- // In other words, it omits paths that are already 31152- // imported or cannot be imported due to compiler 31153- // restrictions. 31154- Packages []string 31155-} 31156- 31157-type ListImportsResult struct { 31158- // Imports is a list of imports in the requested file. 31159- Imports []FileImport 31160- 31161- // PackageImports is a list of all imports in the requested file's package. 31162- PackageImports []PackageImport 31163-} 31164- 31165-type FileImport struct { 31166- // Path is the import path of the import. 31167- Path string 31168- // Name is the name of the import, e.g. `foo` in `import foo "strings"`. 31169- Name string 31170-} 31171- 31172-type PackageImport struct { 31173- // Path is the import path of the import. 31174- Path string 31175-} 31176- 31177-type DebuggingArgs struct { 31178- // Optional: the address (including port) for the debug server to listen on. 31179- // If not provided, the debug server will bind to "localhost:0", and the 31180- // full debug URL will be contained in the result. 31181- // 31182- // If there is more than one gopls instance along the serving path (i.e. you 31183- // are using a daemon), each gopls instance will attempt to start debugging. 31184- // If Addr specifies a port, only the daemon will be able to bind to that 31185- // port, and each intermediate gopls instance will fail to start debugging. 31186- // For this reason it is recommended not to specify a port (or equivalently, 31187- // to specify ":0"). 31188- // 31189- // If the server was already debugging this field has no effect, and the 31190- // result will contain the previously configured debug URL(s). 31191- Addr string 31192-} 31193- 31194-type DebuggingResult struct { 31195- // The URLs to use to access the debug servers, for all gopls instances in 31196- // the serving path. For the common case of a single gopls instance (i.e. no 31197- // daemon), this will be exactly one address. 31198- // 31199- // In the case of one or more gopls instances forwarding the LSP to a daemon, 31200- // URLs will contain debug addresses for each server in the serving path, in 31201- // serving order. The daemon debug address will be the last entry in the 31202- // slice. If any intermediate gopls instance fails to start debugging, no 31203- // error will be returned but the debug URL for that server in the URLs slice 31204- // will be empty. 31205- URLs []string 31206-} 31207- 31208-type ResetGoModDiagnosticsArgs struct { 31209- URIArg 31210- 31211- // Optional: source of the diagnostics to reset. 31212- // If not set, all resettable go.mod diagnostics will be cleared. 31213- DiagnosticSource string 31214-} 31215- 31216-type VulncheckArgs struct { 31217- // Any document in the directory from which govulncheck will run. 31218- URI protocol.DocumentURI 31219- 31220- // Package pattern. E.g. "", ".", "./...". 31221- Pattern string 31222- 31223- // TODO: -tests 31224-} 31225- 31226-// RunVulncheckResult holds the result of asynchronously starting the vulncheck 31227-// command. 31228-type RunVulncheckResult struct { 31229- // Token holds the progress token for LSP workDone reporting of the vulncheck 31230- // invocation. 31231- Token protocol.ProgressToken 31232-} 31233- 31234-type VulncheckResult struct { 31235- Vuln []Vuln 31236- 31237- // TODO: Text string format output? 31238-} 31239- 31240-// CallStack models a trace of function calls starting 31241-// with a client function or method and ending with a 31242-// call to a vulnerable symbol. 31243-type CallStack []StackEntry 31244- 31245-// StackEntry models an element of a call stack. 31246-type StackEntry struct { 31247- // See golang.org/x/exp/vulncheck.StackEntry. 31248- 31249- // User-friendly representation of function/method names. 31250- // e.g. package.funcName, package.(recvType).methodName, ... 31251- Name string 31252- URI protocol.DocumentURI 31253- Pos protocol.Position // Start position. (0-based. Column is always 0) 31254-} 31255- 31256-// Vuln models an osv.Entry and representative call stacks. 31257-// TODO: deprecate 31258-type Vuln struct { 31259- // ID is the vulnerability ID (osv.Entry.ID). 31260- // https://ossf.github.io/osv-schema/#id-modified-fields 31261- ID string 31262- // Details is the description of the vulnerability (osv.Entry.Details). 31263- // https://ossf.github.io/osv-schema/#summary-details-fields 31264- Details string `json:",omitempty"` 31265- // Aliases are alternative IDs of the vulnerability. 31266- // https://ossf.github.io/osv-schema/#aliases-field 31267- Aliases []string `json:",omitempty"` 31268- 31269- // Symbol is the name of the detected vulnerable function or method. 31270- // Can be empty if the vulnerability exists in required modules, but no vulnerable symbols are used. 31271- Symbol string `json:",omitempty"` 31272- // PkgPath is the package path of the detected Symbol. 31273- // Can be empty if the vulnerability exists in required modules, but no vulnerable packages are used. 31274- PkgPath string `json:",omitempty"` 31275- // ModPath is the module path corresponding to PkgPath. 31276- // TODO: how do we specify standard library's vulnerability? 31277- ModPath string `json:",omitempty"` 31278- 31279- // URL is the URL for more info about the information. 31280- // Either the database specific URL or the one of the URLs 31281- // included in osv.Entry.References. 31282- URL string `json:",omitempty"` 31283- 31284- // Current is the current module version. 31285- CurrentVersion string `json:",omitempty"` 31286- 31287- // Fixed is the minimum module version that contains the fix. 31288- FixedVersion string `json:",omitempty"` 31289- 31290- // Example call stacks. 31291- CallStacks []CallStack `json:",omitempty"` 31292- 31293- // Short description of each call stack in CallStacks. 31294- CallStackSummaries []string `json:",omitempty"` 31295- 31296- // TODO: import graph & module graph. 31297-} 31298- 31299-// MemStatsResult holds selected fields from runtime.MemStats. 31300-type MemStatsResult struct { 31301- HeapAlloc uint64 31302- HeapInUse uint64 31303-} 31304diff -urN a/gopls/internal/lsp/command/interface_test.go b/gopls/internal/lsp/command/interface_test.go 31305--- a/gopls/internal/lsp/command/interface_test.go 2000-01-01 00:00:00.000000000 -0000 31306+++ b/gopls/internal/lsp/command/interface_test.go 1970-01-01 00:00:00.000000000 +0000 31307@@ -1,31 +0,0 @@ 31308-// Copyright 2021 The Go Authors. All rights reserved. 31309-// Use of this source code is governed by a BSD-style 31310-// license that can be found in the LICENSE file. 31311- 31312-package command_test 31313- 31314-import ( 31315- "io/ioutil" 31316- "testing" 31317- 31318- "github.com/google/go-cmp/cmp" 31319- "golang.org/x/tools/gopls/internal/lsp/command/gen" 31320- "golang.org/x/tools/internal/testenv" 31321-) 31322- 31323-func TestGenerated(t *testing.T) { 31324- testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code. 31325- 31326- onDisk, err := ioutil.ReadFile("command_gen.go") 31327- if err != nil { 31328- t.Fatal(err) 31329- } 31330- 31331- generated, err := gen.Generate() 31332- if err != nil { 31333- t.Fatal(err) 31334- } 31335- if diff := cmp.Diff(string(generated), string(onDisk)); diff != "" { 31336- t.Errorf("command_gen.go is stale -- regenerate (-generated +on disk)\n%s", diff) 31337- } 31338-} 31339diff -urN a/gopls/internal/lsp/command/util.go b/gopls/internal/lsp/command/util.go 31340--- a/gopls/internal/lsp/command/util.go 2000-01-01 00:00:00.000000000 -0000 31341+++ b/gopls/internal/lsp/command/util.go 1970-01-01 00:00:00.000000000 +0000 31342@@ -1,63 +0,0 @@ 31343-// Copyright 2021 The Go Authors. All rights reserved. 31344-// Use of this source code is governed by a BSD-style 31345-// license that can be found in the LICENSE file. 31346- 31347-package command 31348- 31349-import ( 31350- "encoding/json" 31351- "fmt" 31352-) 31353- 31354-// ID returns the command name for use in the LSP. 31355-func ID(name string) string { 31356- return "gopls." + name 31357-} 31358- 31359-type Command string 31360- 31361-func (c Command) ID() string { 31362- return ID(string(c)) 31363-} 31364- 31365-// MarshalArgs encodes the given arguments to json.RawMessages. This function 31366-// is used to construct arguments to a protocol.Command. 31367-// 31368-// Example usage: 31369-// 31370-// jsonArgs, err := MarshalArgs(1, "hello", true, StructuredArg{42, 12.6}) 31371-func MarshalArgs(args ...interface{}) ([]json.RawMessage, error) { 31372- var out []json.RawMessage 31373- for _, arg := range args { 31374- argJSON, err := json.Marshal(arg) 31375- if err != nil { 31376- return nil, err 31377- } 31378- out = append(out, argJSON) 31379- } 31380- return out, nil 31381-} 31382- 31383-// UnmarshalArgs decodes the given json.RawMessages to the variables provided 31384-// by args. Each element of args should be a pointer. 31385-// 31386-// Example usage: 31387-// 31388-// var ( 31389-// num int 31390-// str string 31391-// bul bool 31392-// structured StructuredArg 31393-// ) 31394-// err := UnmarshalArgs(args, &num, &str, &bul, &structured) 31395-func UnmarshalArgs(jsonArgs []json.RawMessage, args ...interface{}) error { 31396- if len(args) != len(jsonArgs) { 31397- return fmt.Errorf("DecodeArgs: expected %d input arguments, got %d JSON arguments", len(args), len(jsonArgs)) 31398- } 31399- for i, arg := range args { 31400- if err := json.Unmarshal(jsonArgs[i], arg); err != nil { 31401- return err 31402- } 31403- } 31404- return nil 31405-} 31406diff -urN a/gopls/internal/lsp/command.go b/gopls/internal/lsp/command.go 31407--- a/gopls/internal/lsp/command.go 2000-01-01 00:00:00.000000000 -0000 31408+++ b/gopls/internal/lsp/command.go 1970-01-01 00:00:00.000000000 +0000 31409@@ -1,964 +0,0 @@ 31410-// Copyright 2020 The Go Authors. All rights reserved. 31411-// Use of this source code is governed by a BSD-style 31412-// license that can be found in the LICENSE file. 31413- 31414-package lsp 31415- 31416-import ( 31417- "bytes" 31418- "context" 31419- "encoding/json" 31420- "errors" 31421- "fmt" 31422- "io" 31423- "io/ioutil" 31424- "os" 31425- "os/exec" 31426- "path/filepath" 31427- "runtime" 31428- "sort" 31429- "strings" 31430- "time" 31431- 31432- "golang.org/x/mod/modfile" 31433- "golang.org/x/tools/go/ast/astutil" 31434- "golang.org/x/tools/gopls/internal/govulncheck" 31435- "golang.org/x/tools/gopls/internal/lsp/command" 31436- "golang.org/x/tools/gopls/internal/lsp/debug" 31437- "golang.org/x/tools/gopls/internal/lsp/progress" 31438- "golang.org/x/tools/gopls/internal/lsp/protocol" 31439- "golang.org/x/tools/gopls/internal/lsp/source" 31440- "golang.org/x/tools/gopls/internal/span" 31441- "golang.org/x/tools/gopls/internal/vulncheck" 31442- "golang.org/x/tools/internal/event" 31443- "golang.org/x/tools/internal/gocommand" 31444- "golang.org/x/tools/internal/xcontext" 31445-) 31446- 31447-func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCommandParams) (interface{}, error) { 31448- var found bool 31449- for _, name := range s.session.Options().SupportedCommands { 31450- if name == params.Command { 31451- found = true 31452- break 31453- } 31454- } 31455- if !found { 31456- return nil, fmt.Errorf("%s is not a supported command", params.Command) 31457- } 31458- 31459- handler := &commandHandler{ 31460- s: s, 31461- params: params, 31462- } 31463- return command.Dispatch(ctx, params, handler) 31464-} 31465- 31466-type commandHandler struct { 31467- s *Server 31468- params *protocol.ExecuteCommandParams 31469-} 31470- 31471-// commandConfig configures common command set-up and execution. 31472-type commandConfig struct { 31473- async bool // whether to run the command asynchronously. Async commands can only return errors. 31474- requireSave bool // whether all files must be saved for the command to work 31475- progress string // title to use for progress reporting. If empty, no progress will be reported. 31476- forURI protocol.DocumentURI // URI to resolve to a snapshot. If unset, snapshot will be nil. 31477-} 31478- 31479-// commandDeps is evaluated from a commandConfig. Note that not all fields may 31480-// be populated, depending on which configuration is set. See comments in-line 31481-// for details. 31482-type commandDeps struct { 31483- snapshot source.Snapshot // present if cfg.forURI was set 31484- fh source.FileHandle // present if cfg.forURI was set 31485- work *progress.WorkDone // present cfg.progress was set 31486-} 31487- 31488-type commandFunc func(context.Context, commandDeps) error 31489- 31490-// run performs command setup for command execution, and invokes the given run 31491-// function. If cfg.async is set, run executes the given func in a separate 31492-// goroutine, and returns as soon as setup is complete and the goroutine is 31493-// scheduled. 31494-// 31495-// Invariant: if the resulting error is non-nil, the given run func will 31496-// (eventually) be executed exactly once. 31497-func (c *commandHandler) run(ctx context.Context, cfg commandConfig, run commandFunc) (err error) { 31498- if cfg.requireSave { 31499- var unsaved []string 31500- for _, overlay := range c.s.session.Overlays() { 31501- if !overlay.Saved() { 31502- unsaved = append(unsaved, overlay.URI().Filename()) 31503- } 31504- } 31505- if len(unsaved) > 0 { 31506- return fmt.Errorf("All files must be saved first (unsaved: %v).", unsaved) 31507- } 31508- } 31509- var deps commandDeps 31510- if cfg.forURI != "" { 31511- var ok bool 31512- var release func() 31513- deps.snapshot, deps.fh, ok, release, err = c.s.beginFileRequest(ctx, cfg.forURI, source.UnknownKind) 31514- defer release() 31515- if !ok { 31516- if err != nil { 31517- return err 31518- } 31519- return fmt.Errorf("invalid file URL: %v", cfg.forURI) 31520- } 31521- } 31522- ctx, cancel := context.WithCancel(xcontext.Detach(ctx)) 31523- if cfg.progress != "" { 31524- deps.work = c.s.progress.Start(ctx, cfg.progress, "Running...", c.params.WorkDoneToken, cancel) 31525- } 31526- runcmd := func() error { 31527- defer cancel() 31528- err := run(ctx, deps) 31529- if deps.work != nil { 31530- switch { 31531- case errors.Is(err, context.Canceled): 31532- deps.work.End(ctx, "canceled") 31533- case err != nil: 31534- event.Error(ctx, "command error", err) 31535- deps.work.End(ctx, "failed") 31536- default: 31537- deps.work.End(ctx, "completed") 31538- } 31539- } 31540- return err 31541- } 31542- if cfg.async { 31543- go func() { 31544- if err := runcmd(); err != nil { 31545- if showMessageErr := c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 31546- Type: protocol.Error, 31547- Message: err.Error(), 31548- }); showMessageErr != nil { 31549- event.Error(ctx, fmt.Sprintf("failed to show message: %q", err.Error()), showMessageErr) 31550- } 31551- } 31552- }() 31553- return nil 31554- } 31555- return runcmd() 31556-} 31557- 31558-func (c *commandHandler) ApplyFix(ctx context.Context, args command.ApplyFixArgs) error { 31559- return c.run(ctx, commandConfig{ 31560- // Note: no progress here. Applying fixes should be quick. 31561- forURI: args.URI, 31562- }, func(ctx context.Context, deps commandDeps) error { 31563- edits, err := source.ApplyFix(ctx, args.Fix, deps.snapshot, deps.fh, args.Range) 31564- if err != nil { 31565- return err 31566- } 31567- var changes []protocol.DocumentChanges 31568- for _, edit := range edits { 31569- edit := edit 31570- changes = append(changes, protocol.DocumentChanges{ 31571- TextDocumentEdit: &edit, 31572- }) 31573- } 31574- r, err := c.s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{ 31575- Edit: protocol.WorkspaceEdit{ 31576- DocumentChanges: changes, 31577- }, 31578- }) 31579- if err != nil { 31580- return err 31581- } 31582- if !r.Applied { 31583- return errors.New(r.FailureReason) 31584- } 31585- return nil 31586- }) 31587-} 31588- 31589-func (c *commandHandler) RegenerateCgo(ctx context.Context, args command.URIArg) error { 31590- return c.run(ctx, commandConfig{ 31591- progress: "Regenerating Cgo", 31592- }, func(ctx context.Context, deps commandDeps) error { 31593- mod := source.FileModification{ 31594- URI: args.URI.SpanURI(), 31595- Action: source.InvalidateMetadata, 31596- } 31597- return c.s.didModifyFiles(ctx, []source.FileModification{mod}, FromRegenerateCgo) 31598- }) 31599-} 31600- 31601-func (c *commandHandler) CheckUpgrades(ctx context.Context, args command.CheckUpgradesArgs) error { 31602- return c.run(ctx, commandConfig{ 31603- forURI: args.URI, 31604- progress: "Checking for upgrades", 31605- }, func(ctx context.Context, deps commandDeps) error { 31606- upgrades, err := c.s.getUpgrades(ctx, deps.snapshot, args.URI.SpanURI(), args.Modules) 31607- if err != nil { 31608- return err 31609- } 31610- deps.snapshot.View().RegisterModuleUpgrades(args.URI.SpanURI(), upgrades) 31611- // Re-diagnose the snapshot to publish the new module diagnostics. 31612- c.s.diagnoseSnapshot(deps.snapshot, nil, false) 31613- return nil 31614- }) 31615-} 31616- 31617-func (c *commandHandler) AddDependency(ctx context.Context, args command.DependencyArgs) error { 31618- return c.GoGetModule(ctx, args) 31619-} 31620- 31621-func (c *commandHandler) UpgradeDependency(ctx context.Context, args command.DependencyArgs) error { 31622- return c.GoGetModule(ctx, args) 31623-} 31624- 31625-func (c *commandHandler) ResetGoModDiagnostics(ctx context.Context, args command.ResetGoModDiagnosticsArgs) error { 31626- return c.run(ctx, commandConfig{ 31627- forURI: args.URI, 31628- }, func(ctx context.Context, deps commandDeps) error { 31629- // Clear all diagnostics coming from the upgrade check source and vulncheck. 31630- // This will clear the diagnostics in all go.mod files, but they 31631- // will be re-calculated when the snapshot is diagnosed again. 31632- if args.DiagnosticSource == "" || args.DiagnosticSource == string(source.UpgradeNotification) { 31633- deps.snapshot.View().ClearModuleUpgrades(args.URI.SpanURI()) 31634- c.s.clearDiagnosticSource(modCheckUpgradesSource) 31635- } 31636- 31637- if args.DiagnosticSource == "" || args.DiagnosticSource == string(source.Govulncheck) { 31638- deps.snapshot.View().SetVulnerabilities(args.URI.SpanURI(), nil) 31639- c.s.clearDiagnosticSource(modVulncheckSource) 31640- } 31641- 31642- // Re-diagnose the snapshot to remove the diagnostics. 31643- c.s.diagnoseSnapshot(deps.snapshot, nil, false) 31644- return nil 31645- }) 31646-} 31647- 31648-func (c *commandHandler) GoGetModule(ctx context.Context, args command.DependencyArgs) error { 31649- return c.run(ctx, commandConfig{ 31650- progress: "Running go get", 31651- forURI: args.URI, 31652- }, func(ctx context.Context, deps commandDeps) error { 31653- return c.s.runGoModUpdateCommands(ctx, deps.snapshot, args.URI.SpanURI(), func(invoke func(...string) (*bytes.Buffer, error)) error { 31654- return runGoGetModule(invoke, args.AddRequire, args.GoCmdArgs) 31655- }) 31656- }) 31657-} 31658- 31659-// TODO(rFindley): UpdateGoSum, Tidy, and Vendor could probably all be one command. 31660-func (c *commandHandler) UpdateGoSum(ctx context.Context, args command.URIArgs) error { 31661- return c.run(ctx, commandConfig{ 31662- progress: "Updating go.sum", 31663- }, func(ctx context.Context, deps commandDeps) error { 31664- for _, uri := range args.URIs { 31665- snapshot, fh, ok, release, err := c.s.beginFileRequest(ctx, uri, source.UnknownKind) 31666- defer release() 31667- if !ok { 31668- return err 31669- } 31670- if err := c.s.runGoModUpdateCommands(ctx, snapshot, fh.URI(), func(invoke func(...string) (*bytes.Buffer, error)) error { 31671- _, err := invoke("list", "all") 31672- return err 31673- }); err != nil { 31674- return err 31675- } 31676- } 31677- return nil 31678- }) 31679-} 31680- 31681-func (c *commandHandler) Tidy(ctx context.Context, args command.URIArgs) error { 31682- return c.run(ctx, commandConfig{ 31683- requireSave: true, 31684- progress: "Running go mod tidy", 31685- }, func(ctx context.Context, deps commandDeps) error { 31686- for _, uri := range args.URIs { 31687- snapshot, fh, ok, release, err := c.s.beginFileRequest(ctx, uri, source.UnknownKind) 31688- defer release() 31689- if !ok { 31690- return err 31691- } 31692- if err := c.s.runGoModUpdateCommands(ctx, snapshot, fh.URI(), func(invoke func(...string) (*bytes.Buffer, error)) error { 31693- _, err := invoke("mod", "tidy") 31694- return err 31695- }); err != nil { 31696- return err 31697- } 31698- } 31699- return nil 31700- }) 31701-} 31702- 31703-func (c *commandHandler) Vendor(ctx context.Context, args command.URIArg) error { 31704- return c.run(ctx, commandConfig{ 31705- requireSave: true, 31706- progress: "Running go mod vendor", 31707- forURI: args.URI, 31708- }, func(ctx context.Context, deps commandDeps) error { 31709- // Use RunGoCommandPiped here so that we don't compete with any other go 31710- // command invocations. go mod vendor deletes modules.txt before recreating 31711- // it, and therefore can run into file locking issues on Windows if that 31712- // file is in use by another process, such as go list. 31713- // 31714- // If golang/go#44119 is resolved, go mod vendor will instead modify 31715- // modules.txt in-place. In that case we could theoretically allow this 31716- // command to run concurrently. 31717- err := deps.snapshot.RunGoCommandPiped(ctx, source.Normal|source.AllowNetwork, &gocommand.Invocation{ 31718- Verb: "mod", 31719- Args: []string{"vendor"}, 31720- WorkingDir: filepath.Dir(args.URI.SpanURI().Filename()), 31721- }, &bytes.Buffer{}, &bytes.Buffer{}) 31722- return err 31723- }) 31724-} 31725- 31726-func (c *commandHandler) EditGoDirective(ctx context.Context, args command.EditGoDirectiveArgs) error { 31727- return c.run(ctx, commandConfig{ 31728- requireSave: true, // if go.mod isn't saved it could cause a problem 31729- forURI: args.URI, 31730- }, func(ctx context.Context, deps commandDeps) error { 31731- snapshot, fh, ok, release, err := c.s.beginFileRequest(ctx, args.URI, source.UnknownKind) 31732- defer release() 31733- if !ok { 31734- return err 31735- } 31736- if err := c.s.runGoModUpdateCommands(ctx, snapshot, fh.URI(), func(invoke func(...string) (*bytes.Buffer, error)) error { 31737- _, err := invoke("mod", "edit", "-go", args.Version) 31738- return err 31739- }); err != nil { 31740- return err 31741- } 31742- return nil 31743- }) 31744-} 31745- 31746-func (c *commandHandler) RemoveDependency(ctx context.Context, args command.RemoveDependencyArgs) error { 31747- return c.run(ctx, commandConfig{ 31748- progress: "Removing dependency", 31749- forURI: args.URI, 31750- }, func(ctx context.Context, deps commandDeps) error { 31751- // If the module is tidied apart from the one unused diagnostic, we can 31752- // run `go get module@none`, and then run `go mod tidy`. Otherwise, we 31753- // must make textual edits. 31754- // TODO(rstambler): In Go 1.17+, we will be able to use the go command 31755- // without checking if the module is tidy. 31756- if args.OnlyDiagnostic { 31757- return c.s.runGoModUpdateCommands(ctx, deps.snapshot, args.URI.SpanURI(), func(invoke func(...string) (*bytes.Buffer, error)) error { 31758- if err := runGoGetModule(invoke, false, []string{args.ModulePath + "@none"}); err != nil { 31759- return err 31760- } 31761- _, err := invoke("mod", "tidy") 31762- return err 31763- }) 31764- } 31765- pm, err := deps.snapshot.ParseMod(ctx, deps.fh) 31766- if err != nil { 31767- return err 31768- } 31769- edits, err := dropDependency(deps.snapshot, pm, args.ModulePath) 31770- if err != nil { 31771- return err 31772- } 31773- response, err := c.s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{ 31774- Edit: protocol.WorkspaceEdit{ 31775- DocumentChanges: []protocol.DocumentChanges{ 31776- { 31777- TextDocumentEdit: &protocol.TextDocumentEdit{ 31778- TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{ 31779- Version: deps.fh.Version(), 31780- TextDocumentIdentifier: protocol.TextDocumentIdentifier{ 31781- URI: protocol.URIFromSpanURI(deps.fh.URI()), 31782- }, 31783- }, 31784- Edits: edits, 31785- }, 31786- }, 31787- }, 31788- }, 31789- }) 31790- if err != nil { 31791- return err 31792- } 31793- if !response.Applied { 31794- return fmt.Errorf("edits not applied because of %s", response.FailureReason) 31795- } 31796- return nil 31797- }) 31798-} 31799- 31800-// dropDependency returns the edits to remove the given require from the go.mod 31801-// file. 31802-func dropDependency(snapshot source.Snapshot, pm *source.ParsedModule, modulePath string) ([]protocol.TextEdit, error) { 31803- // We need a private copy of the parsed go.mod file, since we're going to 31804- // modify it. 31805- copied, err := modfile.Parse("", pm.Mapper.Content, nil) 31806- if err != nil { 31807- return nil, err 31808- } 31809- if err := copied.DropRequire(modulePath); err != nil { 31810- return nil, err 31811- } 31812- copied.Cleanup() 31813- newContent, err := copied.Format() 31814- if err != nil { 31815- return nil, err 31816- } 31817- // Calculate the edits to be made due to the change. 31818- diff := snapshot.View().Options().ComputeEdits(string(pm.Mapper.Content), string(newContent)) 31819- return source.ToProtocolEdits(pm.Mapper, diff) 31820-} 31821- 31822-func (c *commandHandler) Test(ctx context.Context, uri protocol.DocumentURI, tests, benchmarks []string) error { 31823- return c.RunTests(ctx, command.RunTestsArgs{ 31824- URI: uri, 31825- Tests: tests, 31826- Benchmarks: benchmarks, 31827- }) 31828-} 31829- 31830-func (c *commandHandler) RunTests(ctx context.Context, args command.RunTestsArgs) error { 31831- return c.run(ctx, commandConfig{ 31832- async: true, 31833- progress: "Running go test", 31834- requireSave: true, 31835- forURI: args.URI, 31836- }, func(ctx context.Context, deps commandDeps) error { 31837- if err := c.runTests(ctx, deps.snapshot, deps.work, args.URI, args.Tests, args.Benchmarks); err != nil { 31838- return fmt.Errorf("running tests failed: %w", err) 31839- } 31840- return nil 31841- }) 31842-} 31843- 31844-func (c *commandHandler) runTests(ctx context.Context, snapshot source.Snapshot, work *progress.WorkDone, uri protocol.DocumentURI, tests, benchmarks []string) error { 31845- // TODO: fix the error reporting when this runs async. 31846- metas, err := snapshot.MetadataForFile(ctx, uri.SpanURI()) 31847- if err != nil { 31848- return err 31849- } 31850- metas = source.RemoveIntermediateTestVariants(metas) 31851- if len(metas) == 0 { 31852- return fmt.Errorf("package could not be found for file: %s", uri.SpanURI().Filename()) 31853- } 31854- pkgPath := string(metas[0].ForTest) 31855- 31856- // create output 31857- buf := &bytes.Buffer{} 31858- ew := progress.NewEventWriter(ctx, "test") 31859- out := io.MultiWriter(ew, progress.NewWorkDoneWriter(ctx, work), buf) 31860- 31861- // Run `go test -run Func` on each test. 31862- var failedTests int 31863- for _, funcName := range tests { 31864- inv := &gocommand.Invocation{ 31865- Verb: "test", 31866- Args: []string{pkgPath, "-v", "-count=1", "-run", fmt.Sprintf("^%s$", funcName)}, 31867- WorkingDir: filepath.Dir(uri.SpanURI().Filename()), 31868- } 31869- if err := snapshot.RunGoCommandPiped(ctx, source.Normal, inv, out, out); err != nil { 31870- if errors.Is(err, context.Canceled) { 31871- return err 31872- } 31873- failedTests++ 31874- } 31875- } 31876- 31877- // Run `go test -run=^$ -bench Func` on each test. 31878- var failedBenchmarks int 31879- for _, funcName := range benchmarks { 31880- inv := &gocommand.Invocation{ 31881- Verb: "test", 31882- Args: []string{pkgPath, "-v", "-run=^$", "-bench", fmt.Sprintf("^%s$", funcName)}, 31883- WorkingDir: filepath.Dir(uri.SpanURI().Filename()), 31884- } 31885- if err := snapshot.RunGoCommandPiped(ctx, source.Normal, inv, out, out); err != nil { 31886- if errors.Is(err, context.Canceled) { 31887- return err 31888- } 31889- failedBenchmarks++ 31890- } 31891- } 31892- 31893- var title string 31894- if len(tests) > 0 && len(benchmarks) > 0 { 31895- title = "tests and benchmarks" 31896- } else if len(tests) > 0 { 31897- title = "tests" 31898- } else if len(benchmarks) > 0 { 31899- title = "benchmarks" 31900- } else { 31901- return errors.New("No functions were provided") 31902- } 31903- message := fmt.Sprintf("all %s passed", title) 31904- if failedTests > 0 && failedBenchmarks > 0 { 31905- message = fmt.Sprintf("%d / %d tests failed and %d / %d benchmarks failed", failedTests, len(tests), failedBenchmarks, len(benchmarks)) 31906- } else if failedTests > 0 { 31907- message = fmt.Sprintf("%d / %d tests failed", failedTests, len(tests)) 31908- } else if failedBenchmarks > 0 { 31909- message = fmt.Sprintf("%d / %d benchmarks failed", failedBenchmarks, len(benchmarks)) 31910- } 31911- if failedTests > 0 || failedBenchmarks > 0 { 31912- message += "\n" + buf.String() 31913- } 31914- 31915- return c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 31916- Type: protocol.Info, 31917- Message: message, 31918- }) 31919-} 31920- 31921-func (c *commandHandler) Generate(ctx context.Context, args command.GenerateArgs) error { 31922- title := "Running go generate ." 31923- if args.Recursive { 31924- title = "Running go generate ./..." 31925- } 31926- return c.run(ctx, commandConfig{ 31927- requireSave: true, 31928- progress: title, 31929- forURI: args.Dir, 31930- }, func(ctx context.Context, deps commandDeps) error { 31931- er := progress.NewEventWriter(ctx, "generate") 31932- 31933- pattern := "." 31934- if args.Recursive { 31935- pattern = "./..." 31936- } 31937- inv := &gocommand.Invocation{ 31938- Verb: "generate", 31939- Args: []string{"-x", pattern}, 31940- WorkingDir: args.Dir.SpanURI().Filename(), 31941- } 31942- stderr := io.MultiWriter(er, progress.NewWorkDoneWriter(ctx, deps.work)) 31943- if err := deps.snapshot.RunGoCommandPiped(ctx, source.Normal, inv, er, stderr); err != nil { 31944- return err 31945- } 31946- return nil 31947- }) 31948-} 31949- 31950-func (c *commandHandler) GoGetPackage(ctx context.Context, args command.GoGetPackageArgs) error { 31951- return c.run(ctx, commandConfig{ 31952- forURI: args.URI, 31953- progress: "Running go get", 31954- }, func(ctx context.Context, deps commandDeps) error { 31955- // Run on a throwaway go.mod, otherwise it'll write to the real one. 31956- stdout, err := deps.snapshot.RunGoCommandDirect(ctx, source.WriteTemporaryModFile|source.AllowNetwork, &gocommand.Invocation{ 31957- Verb: "list", 31958- Args: []string{"-f", "{{.Module.Path}}@{{.Module.Version}}", args.Pkg}, 31959- WorkingDir: filepath.Dir(args.URI.SpanURI().Filename()), 31960- }) 31961- if err != nil { 31962- return err 31963- } 31964- ver := strings.TrimSpace(stdout.String()) 31965- return c.s.runGoModUpdateCommands(ctx, deps.snapshot, args.URI.SpanURI(), func(invoke func(...string) (*bytes.Buffer, error)) error { 31966- if args.AddRequire { 31967- if err := addModuleRequire(invoke, []string{ver}); err != nil { 31968- return err 31969- } 31970- } 31971- _, err := invoke(append([]string{"get", "-d"}, args.Pkg)...) 31972- return err 31973- }) 31974- }) 31975-} 31976- 31977-func (s *Server) runGoModUpdateCommands(ctx context.Context, snapshot source.Snapshot, uri span.URI, run func(invoke func(...string) (*bytes.Buffer, error)) error) error { 31978- tmpModfile, newModBytes, newSumBytes, err := snapshot.RunGoCommands(ctx, true, filepath.Dir(uri.Filename()), run) 31979- if err != nil { 31980- return err 31981- } 31982- if !tmpModfile { 31983- return nil 31984- } 31985- modURI := snapshot.GoModForFile(uri) 31986- sumURI := span.URIFromPath(strings.TrimSuffix(modURI.Filename(), ".mod") + ".sum") 31987- modEdits, err := applyFileEdits(ctx, snapshot, modURI, newModBytes) 31988- if err != nil { 31989- return err 31990- } 31991- sumEdits, err := applyFileEdits(ctx, snapshot, sumURI, newSumBytes) 31992- if err != nil { 31993- return err 31994- } 31995- changes := append(sumEdits, modEdits...) 31996- if len(changes) == 0 { 31997- return nil 31998- } 31999- var documentChanges []protocol.DocumentChanges 32000- for _, change := range changes { 32001- change := change 32002- documentChanges = append(documentChanges, protocol.DocumentChanges{ 32003- TextDocumentEdit: &change, 32004- }) 32005- } 32006- response, err := s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{ 32007- Edit: protocol.WorkspaceEdit{ 32008- DocumentChanges: documentChanges, 32009- }, 32010- }) 32011- if err != nil { 32012- return err 32013- } 32014- if !response.Applied { 32015- return fmt.Errorf("edits not applied because of %s", response.FailureReason) 32016- } 32017- return nil 32018-} 32019- 32020-func applyFileEdits(ctx context.Context, snapshot source.Snapshot, uri span.URI, newContent []byte) ([]protocol.TextDocumentEdit, error) { 32021- fh, err := snapshot.GetFile(ctx, uri) 32022- if err != nil { 32023- return nil, err 32024- } 32025- oldContent, err := fh.Read() 32026- if err != nil && !os.IsNotExist(err) { 32027- return nil, err 32028- } 32029- if bytes.Equal(oldContent, newContent) { 32030- return nil, nil 32031- } 32032- 32033- // Sending a workspace edit to a closed file causes VS Code to open the 32034- // file and leave it unsaved. We would rather apply the changes directly, 32035- // especially to go.sum, which should be mostly invisible to the user. 32036- if !snapshot.IsOpen(uri) { 32037- err := ioutil.WriteFile(uri.Filename(), newContent, 0666) 32038- return nil, err 32039- } 32040- 32041- m := protocol.NewMapper(fh.URI(), oldContent) 32042- diff := snapshot.View().Options().ComputeEdits(string(oldContent), string(newContent)) 32043- edits, err := source.ToProtocolEdits(m, diff) 32044- if err != nil { 32045- return nil, err 32046- } 32047- return []protocol.TextDocumentEdit{{ 32048- TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{ 32049- Version: fh.Version(), 32050- TextDocumentIdentifier: protocol.TextDocumentIdentifier{ 32051- URI: protocol.URIFromSpanURI(uri), 32052- }, 32053- }, 32054- Edits: edits, 32055- }}, nil 32056-} 32057- 32058-func runGoGetModule(invoke func(...string) (*bytes.Buffer, error), addRequire bool, args []string) error { 32059- if addRequire { 32060- if err := addModuleRequire(invoke, args); err != nil { 32061- return err 32062- } 32063- } 32064- _, err := invoke(append([]string{"get", "-d"}, args...)...) 32065- return err 32066-} 32067- 32068-func addModuleRequire(invoke func(...string) (*bytes.Buffer, error), args []string) error { 32069- // Using go get to create a new dependency results in an 32070- // `// indirect` comment we may not want. The only way to avoid it 32071- // is to add the require as direct first. Then we can use go get to 32072- // update go.sum and tidy up. 32073- _, err := invoke(append([]string{"mod", "edit", "-require"}, args...)...) 32074- return err 32075-} 32076- 32077-func (s *Server) getUpgrades(ctx context.Context, snapshot source.Snapshot, uri span.URI, modules []string) (map[string]string, error) { 32078- stdout, err := snapshot.RunGoCommandDirect(ctx, source.Normal|source.AllowNetwork, &gocommand.Invocation{ 32079- Verb: "list", 32080- Args: append([]string{"-m", "-u", "-json"}, modules...), 32081- WorkingDir: filepath.Dir(uri.Filename()), 32082- ModFlag: "readonly", 32083- }) 32084- if err != nil { 32085- return nil, err 32086- } 32087- 32088- upgrades := map[string]string{} 32089- for dec := json.NewDecoder(stdout); dec.More(); { 32090- mod := &gocommand.ModuleJSON{} 32091- if err := dec.Decode(mod); err != nil { 32092- return nil, err 32093- } 32094- if mod.Update == nil { 32095- continue 32096- } 32097- upgrades[mod.Path] = mod.Update.Version 32098- } 32099- return upgrades, nil 32100-} 32101- 32102-func (c *commandHandler) GCDetails(ctx context.Context, uri protocol.DocumentURI) error { 32103- return c.ToggleGCDetails(ctx, command.URIArg{URI: uri}) 32104-} 32105- 32106-func (c *commandHandler) ToggleGCDetails(ctx context.Context, args command.URIArg) error { 32107- return c.run(ctx, commandConfig{ 32108- requireSave: true, 32109- progress: "Toggling GC Details", 32110- forURI: args.URI, 32111- }, func(ctx context.Context, deps commandDeps) error { 32112- metas, err := deps.snapshot.MetadataForFile(ctx, deps.fh.URI()) 32113- if err != nil { 32114- return err 32115- } 32116- id := metas[0].ID // 0 => narrowest package 32117- c.s.gcOptimizationDetailsMu.Lock() 32118- if _, ok := c.s.gcOptimizationDetails[id]; ok { 32119- delete(c.s.gcOptimizationDetails, id) 32120- c.s.clearDiagnosticSource(gcDetailsSource) 32121- } else { 32122- c.s.gcOptimizationDetails[id] = struct{}{} 32123- } 32124- c.s.gcOptimizationDetailsMu.Unlock() 32125- c.s.diagnoseSnapshot(deps.snapshot, nil, false) 32126- return nil 32127- }) 32128-} 32129- 32130-func (c *commandHandler) ListKnownPackages(ctx context.Context, args command.URIArg) (command.ListKnownPackagesResult, error) { 32131- var result command.ListKnownPackagesResult 32132- err := c.run(ctx, commandConfig{ 32133- progress: "Listing packages", 32134- forURI: args.URI, 32135- }, func(ctx context.Context, deps commandDeps) error { 32136- pkgs, err := source.KnownPackagePaths(ctx, deps.snapshot, deps.fh) 32137- for _, pkg := range pkgs { 32138- result.Packages = append(result.Packages, string(pkg)) 32139- } 32140- return err 32141- }) 32142- return result, err 32143-} 32144- 32145-func (c *commandHandler) ListImports(ctx context.Context, args command.URIArg) (command.ListImportsResult, error) { 32146- var result command.ListImportsResult 32147- err := c.run(ctx, commandConfig{ 32148- forURI: args.URI, 32149- }, func(ctx context.Context, deps commandDeps) error { 32150- fh, err := deps.snapshot.GetFile(ctx, args.URI.SpanURI()) 32151- if err != nil { 32152- return err 32153- } 32154- pgf, err := deps.snapshot.ParseGo(ctx, fh, source.ParseHeader) 32155- if err != nil { 32156- return err 32157- } 32158- fset := source.FileSetFor(pgf.Tok) 32159- for _, group := range astutil.Imports(fset, pgf.File) { 32160- for _, imp := range group { 32161- if imp.Path == nil { 32162- continue 32163- } 32164- var name string 32165- if imp.Name != nil { 32166- name = imp.Name.Name 32167- } 32168- result.Imports = append(result.Imports, command.FileImport{ 32169- Path: string(source.UnquoteImportPath(imp)), 32170- Name: name, 32171- }) 32172- } 32173- } 32174- metas, err := deps.snapshot.MetadataForFile(ctx, args.URI.SpanURI()) 32175- if err != nil { 32176- return err // e.g. cancelled 32177- } 32178- if len(metas) == 0 { 32179- return fmt.Errorf("no package containing %v", args.URI.SpanURI()) 32180- } 32181- for pkgPath := range metas[0].DepsByPkgPath { // 0 => narrowest package 32182- result.PackageImports = append(result.PackageImports, 32183- command.PackageImport{Path: string(pkgPath)}) 32184- } 32185- sort.Slice(result.PackageImports, func(i, j int) bool { 32186- return result.PackageImports[i].Path < result.PackageImports[j].Path 32187- }) 32188- return nil 32189- }) 32190- return result, err 32191-} 32192- 32193-func (c *commandHandler) AddImport(ctx context.Context, args command.AddImportArgs) error { 32194- return c.run(ctx, commandConfig{ 32195- progress: "Adding import", 32196- forURI: args.URI, 32197- }, func(ctx context.Context, deps commandDeps) error { 32198- edits, err := source.AddImport(ctx, deps.snapshot, deps.fh, args.ImportPath) 32199- if err != nil { 32200- return fmt.Errorf("could not add import: %v", err) 32201- } 32202- if _, err := c.s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{ 32203- Edit: protocol.WorkspaceEdit{ 32204- DocumentChanges: documentChanges(deps.fh, edits), 32205- }, 32206- }); err != nil { 32207- return fmt.Errorf("could not apply import edits: %v", err) 32208- } 32209- return nil 32210- }) 32211-} 32212- 32213-func (c *commandHandler) StartDebugging(ctx context.Context, args command.DebuggingArgs) (result command.DebuggingResult, _ error) { 32214- addr := args.Addr 32215- if addr == "" { 32216- addr = "localhost:0" 32217- } 32218- di := debug.GetInstance(ctx) 32219- if di == nil { 32220- return result, errors.New("internal error: server has no debugging instance") 32221- } 32222- listenedAddr, err := di.Serve(ctx, addr) 32223- if err != nil { 32224- return result, fmt.Errorf("starting debug server: %w", err) 32225- } 32226- result.URLs = []string{"http://" + listenedAddr} 32227- return result, nil 32228-} 32229- 32230-// Copy of pkgLoadConfig defined in internal/lsp/cmd/vulncheck.go 32231-// TODO(hyangah): decide where to define this. 32232-type pkgLoadConfig struct { 32233- // BuildFlags is a list of command-line flags to be passed through to 32234- // the build system's query tool. 32235- BuildFlags []string 32236- 32237- // If Tests is set, the loader includes related test packages. 32238- Tests bool 32239-} 32240- 32241-func (c *commandHandler) FetchVulncheckResult(ctx context.Context, arg command.URIArg) (map[protocol.DocumentURI]*govulncheck.Result, error) { 32242- ret := map[protocol.DocumentURI]*govulncheck.Result{} 32243- err := c.run(ctx, commandConfig{forURI: arg.URI}, func(ctx context.Context, deps commandDeps) error { 32244- if deps.snapshot.View().Options().Vulncheck == source.ModeVulncheckImports { 32245- for _, modfile := range deps.snapshot.ModFiles() { 32246- res, err := deps.snapshot.ModVuln(ctx, modfile) 32247- if err != nil { 32248- return err 32249- } 32250- ret[protocol.URIFromSpanURI(modfile)] = res 32251- } 32252- } 32253- // Overwrite if there is any govulncheck-based result. 32254- for modfile, result := range deps.snapshot.View().Vulnerabilities() { 32255- ret[protocol.URIFromSpanURI(modfile)] = result 32256- } 32257- return nil 32258- }) 32259- return ret, err 32260-} 32261- 32262-func (c *commandHandler) RunGovulncheck(ctx context.Context, args command.VulncheckArgs) (command.RunVulncheckResult, error) { 32263- if args.URI == "" { 32264- return command.RunVulncheckResult{}, errors.New("VulncheckArgs is missing URI field") 32265- } 32266- 32267- // Return the workdone token so that clients can identify when this 32268- // vulncheck invocation is complete. 32269- // 32270- // Since the run function executes asynchronously, we use a channel to 32271- // synchronize the start of the run and return the token. 32272- tokenChan := make(chan protocol.ProgressToken, 1) 32273- err := c.run(ctx, commandConfig{ 32274- async: true, // need to be async to be cancellable 32275- progress: "govulncheck", 32276- requireSave: true, 32277- forURI: args.URI, 32278- }, func(ctx context.Context, deps commandDeps) error { 32279- tokenChan <- deps.work.Token() 32280- 32281- view := deps.snapshot.View() 32282- opts := view.Options() 32283- // quickly test if gopls is compiled to support govulncheck 32284- // by checking vulncheck.Main. Alternatively, we can continue and 32285- // let the `gopls vulncheck` command fail. This is lighter-weight. 32286- if vulncheck.Main == nil { 32287- return errors.New("vulncheck feature is not available") 32288- } 32289- 32290- cmd := exec.CommandContext(ctx, os.Args[0], "vulncheck", "-config", args.Pattern) 32291- cmd.Dir = filepath.Dir(args.URI.SpanURI().Filename()) 32292- 32293- var viewEnv []string 32294- if e := opts.EnvSlice(); e != nil { 32295- viewEnv = append(os.Environ(), e...) 32296- } 32297- cmd.Env = viewEnv 32298- 32299- // stdin: gopls vulncheck expects JSON-encoded configuration from STDIN when -config flag is set. 32300- var stdin bytes.Buffer 32301- cmd.Stdin = &stdin 32302- 32303- if err := json.NewEncoder(&stdin).Encode(pkgLoadConfig{ 32304- BuildFlags: opts.BuildFlags, 32305- // TODO(hyangah): add `tests` flag in command.VulncheckArgs 32306- }); err != nil { 32307- return fmt.Errorf("failed to pass package load config: %v", err) 32308- } 32309- 32310- // stderr: stream gopls vulncheck's STDERR as progress reports 32311- er := progress.NewEventWriter(ctx, "vulncheck") 32312- stderr := io.MultiWriter(er, progress.NewWorkDoneWriter(ctx, deps.work)) 32313- cmd.Stderr = stderr 32314- // TODO: can we stream stdout? 32315- stdout, err := cmd.Output() 32316- if err != nil { 32317- return fmt.Errorf("failed to run govulncheck: %v", err) 32318- } 32319- 32320- var result govulncheck.Result 32321- if err := json.Unmarshal(stdout, &result); err != nil { 32322- // TODO: for easy debugging, log the failed stdout somewhere? 32323- return fmt.Errorf("failed to parse govulncheck output: %v", err) 32324- } 32325- result.Mode = govulncheck.ModeGovulncheck 32326- result.AsOf = time.Now() 32327- deps.snapshot.View().SetVulnerabilities(args.URI.SpanURI(), &result) 32328- 32329- c.s.diagnoseSnapshot(deps.snapshot, nil, false) 32330- vulns := result.Vulns 32331- affecting := make([]string, 0, len(vulns)) 32332- for _, v := range vulns { 32333- if v.IsCalled() { 32334- affecting = append(affecting, v.OSV.ID) 32335- } 32336- } 32337- if len(affecting) == 0 { 32338- return c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 32339- Type: protocol.Info, 32340- Message: "No vulnerabilities found", 32341- }) 32342- } 32343- sort.Strings(affecting) 32344- return c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 32345- Type: protocol.Warning, 32346- Message: fmt.Sprintf("Found %v", strings.Join(affecting, ", ")), 32347- }) 32348- }) 32349- if err != nil { 32350- return command.RunVulncheckResult{}, err 32351- } 32352- select { 32353- case <-ctx.Done(): 32354- return command.RunVulncheckResult{}, ctx.Err() 32355- case token := <-tokenChan: 32356- return command.RunVulncheckResult{Token: token}, nil 32357- } 32358-} 32359- 32360-// MemStats implements the MemStats command. It returns an error as a 32361-// future-proof API, but the resulting error is currently always nil. 32362-func (c *commandHandler) MemStats(ctx context.Context) (command.MemStatsResult, error) { 32363- // GC a few times for stable results. 32364- runtime.GC() 32365- runtime.GC() 32366- runtime.GC() 32367- var m runtime.MemStats 32368- runtime.ReadMemStats(&m) 32369- return command.MemStatsResult{ 32370- HeapAlloc: m.HeapAlloc, 32371- HeapInUse: m.HeapInuse, 32372- }, nil 32373-} 32374diff -urN a/gopls/internal/lsp/completion.go b/gopls/internal/lsp/completion.go 32375--- a/gopls/internal/lsp/completion.go 2000-01-01 00:00:00.000000000 -0000 32376+++ b/gopls/internal/lsp/completion.go 1970-01-01 00:00:00.000000000 +0000 32377@@ -1,140 +0,0 @@ 32378-// Copyright 2018 The Go Authors. All rights reserved. 32379-// Use of this source code is governed by a BSD-style 32380-// license that can be found in the LICENSE file. 32381- 32382-package lsp 32383- 32384-import ( 32385- "context" 32386- "fmt" 32387- "strings" 32388- 32389- "golang.org/x/tools/gopls/internal/lsp/protocol" 32390- "golang.org/x/tools/gopls/internal/lsp/source" 32391- "golang.org/x/tools/gopls/internal/lsp/source/completion" 32392- "golang.org/x/tools/gopls/internal/lsp/template" 32393- "golang.org/x/tools/gopls/internal/lsp/work" 32394- "golang.org/x/tools/internal/event" 32395- "golang.org/x/tools/internal/event/tag" 32396-) 32397- 32398-func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) { 32399- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 32400- defer release() 32401- if !ok { 32402- return nil, err 32403- } 32404- var candidates []completion.CompletionItem 32405- var surrounding *completion.Selection 32406- switch snapshot.View().FileKind(fh) { 32407- case source.Go: 32408- candidates, surrounding, err = completion.Completion(ctx, snapshot, fh, params.Position, params.Context) 32409- case source.Mod: 32410- candidates, surrounding = nil, nil 32411- case source.Work: 32412- cl, err := work.Completion(ctx, snapshot, fh, params.Position) 32413- if err != nil { 32414- break 32415- } 32416- return cl, nil 32417- case source.Tmpl: 32418- var cl *protocol.CompletionList 32419- cl, err = template.Completion(ctx, snapshot, fh, params.Position, params.Context) 32420- if err != nil { 32421- break // use common error handling, candidates==nil 32422- } 32423- return cl, nil 32424- } 32425- if err != nil { 32426- event.Error(ctx, "no completions found", err, tag.Position.Of(params.Position)) 32427- } 32428- if candidates == nil { 32429- return &protocol.CompletionList{ 32430- IsIncomplete: true, 32431- Items: []protocol.CompletionItem{}, 32432- }, nil 32433- } 32434- 32435- rng, err := surrounding.Range() 32436- if err != nil { 32437- return nil, err 32438- } 32439- 32440- // When using deep completions/fuzzy matching, report results as incomplete so 32441- // client fetches updated completions after every key stroke. 32442- options := snapshot.View().Options() 32443- incompleteResults := options.DeepCompletion || options.Matcher == source.Fuzzy 32444- 32445- items := toProtocolCompletionItems(candidates, rng, options) 32446- 32447- return &protocol.CompletionList{ 32448- IsIncomplete: incompleteResults, 32449- Items: items, 32450- }, nil 32451-} 32452- 32453-func toProtocolCompletionItems(candidates []completion.CompletionItem, rng protocol.Range, options *source.Options) []protocol.CompletionItem { 32454- var ( 32455- items = make([]protocol.CompletionItem, 0, len(candidates)) 32456- numDeepCompletionsSeen int 32457- ) 32458- for i, candidate := range candidates { 32459- // Limit the number of deep completions to not overwhelm the user in cases 32460- // with dozens of deep completion matches. 32461- if candidate.Depth > 0 { 32462- if !options.DeepCompletion { 32463- continue 32464- } 32465- if numDeepCompletionsSeen >= completion.MaxDeepCompletions { 32466- continue 32467- } 32468- numDeepCompletionsSeen++ 32469- } 32470- insertText := candidate.InsertText 32471- if options.InsertTextFormat == protocol.SnippetTextFormat { 32472- insertText = candidate.Snippet() 32473- } 32474- 32475- // This can happen if the client has snippets disabled but the 32476- // candidate only supports snippet insertion. 32477- if insertText == "" { 32478- continue 32479- } 32480- 32481- doc := &protocol.Or_CompletionItem_documentation{ 32482- Value: protocol.MarkupContent{ 32483- Kind: protocol.Markdown, 32484- Value: source.CommentToMarkdown(candidate.Documentation, options), 32485- }, 32486- } 32487- if options.PreferredContentFormat != protocol.Markdown { 32488- doc.Value = candidate.Documentation 32489- } 32490- item := protocol.CompletionItem{ 32491- Label: candidate.Label, 32492- Detail: candidate.Detail, 32493- Kind: candidate.Kind, 32494- TextEdit: &protocol.TextEdit{ 32495- NewText: insertText, 32496- Range: rng, 32497- }, 32498- InsertTextFormat: &options.InsertTextFormat, 32499- AdditionalTextEdits: candidate.AdditionalTextEdits, 32500- // This is a hack so that the client sorts completion results in the order 32501- // according to their score. This can be removed upon the resolution of 32502- // https://github.com/Microsoft/language-server-protocol/issues/348. 32503- SortText: fmt.Sprintf("%05d", i), 32504- 32505- // Trim operators (VSCode doesn't like weird characters in 32506- // filterText). 32507- FilterText: strings.TrimLeft(candidate.InsertText, "&*"), 32508- 32509- Preselect: i == 0, 32510- Documentation: doc, 32511- Tags: candidate.Tags, 32512- Deprecated: candidate.Deprecated, 32513- } 32514- items = append(items, item) 32515- } 32516- return items 32517-} 32518diff -urN a/gopls/internal/lsp/completion_test.go b/gopls/internal/lsp/completion_test.go 32519--- a/gopls/internal/lsp/completion_test.go 2000-01-01 00:00:00.000000000 -0000 32520+++ b/gopls/internal/lsp/completion_test.go 1970-01-01 00:00:00.000000000 +0000 32521@@ -1,176 +0,0 @@ 32522-// Copyright 2019 The Go Authors. All rights reserved. 32523-// Use of this source code is governed by a BSD-style 32524-// license that can be found in the LICENSE file. 32525- 32526-package lsp 32527- 32528-import ( 32529- "fmt" 32530- "strings" 32531- "testing" 32532- 32533- "golang.org/x/tools/gopls/internal/lsp/protocol" 32534- "golang.org/x/tools/gopls/internal/lsp/source" 32535- "golang.org/x/tools/gopls/internal/lsp/source/completion" 32536- "golang.org/x/tools/gopls/internal/lsp/tests" 32537- "golang.org/x/tools/gopls/internal/span" 32538-) 32539- 32540-func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { 32541- got := r.callCompletion(t, src, func(opts *source.Options) { 32542- opts.DeepCompletion = false 32543- opts.Matcher = source.CaseInsensitive 32544- opts.CompleteUnimported = false 32545- opts.InsertTextFormat = protocol.SnippetTextFormat 32546- opts.LiteralCompletions = strings.Contains(string(src.URI()), "literal") 32547- opts.ExperimentalPostfixCompletions = strings.Contains(string(src.URI()), "postfix") 32548- }) 32549- got = tests.FilterBuiltins(src, got) 32550- want := expected(t, test, items) 32551- if diff := tests.DiffCompletionItems(want, got); diff != "" { 32552- t.Errorf("mismatching completion items (-want +got):\n%s", diff) 32553- } 32554-} 32555- 32556-func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) { 32557- list := r.callCompletion(t, src, func(opts *source.Options) { 32558- opts.UsePlaceholders = placeholders 32559- opts.DeepCompletion = true 32560- opts.Matcher = source.Fuzzy 32561- opts.CompleteUnimported = false 32562- }) 32563- got := tests.FindItem(list, *items[expected.CompletionItem]) 32564- want := expected.PlainSnippet 32565- if placeholders { 32566- want = expected.PlaceholderSnippet 32567- } 32568- if diff := tests.DiffSnippets(want, got); diff != "" { 32569- t.Errorf("%s", diff) 32570- } 32571-} 32572- 32573-func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { 32574- got := r.callCompletion(t, src, func(opts *source.Options) {}) 32575- got = tests.FilterBuiltins(src, got) 32576- want := expected(t, test, items) 32577- if diff := tests.CheckCompletionOrder(want, got, false); diff != "" { 32578- t.Errorf("%s", diff) 32579- } 32580-} 32581- 32582-func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { 32583- got := r.callCompletion(t, src, func(opts *source.Options) { 32584- opts.DeepCompletion = true 32585- opts.Matcher = source.CaseInsensitive 32586- opts.CompleteUnimported = false 32587- }) 32588- got = tests.FilterBuiltins(src, got) 32589- want := expected(t, test, items) 32590- if diff := tests.DiffCompletionItems(want, got); diff != "" { 32591- t.Errorf("mismatching completion items (-want +got):\n%s", diff) 32592- } 32593-} 32594- 32595-func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { 32596- got := r.callCompletion(t, src, func(opts *source.Options) { 32597- opts.DeepCompletion = true 32598- opts.Matcher = source.Fuzzy 32599- opts.CompleteUnimported = false 32600- }) 32601- got = tests.FilterBuiltins(src, got) 32602- want := expected(t, test, items) 32603- if diff := tests.DiffCompletionItems(want, got); diff != "" { 32604- t.Errorf("mismatching completion items (-want +got):\n%s", diff) 32605- } 32606-} 32607- 32608-func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { 32609- got := r.callCompletion(t, src, func(opts *source.Options) { 32610- opts.Matcher = source.CaseSensitive 32611- opts.CompleteUnimported = false 32612- }) 32613- got = tests.FilterBuiltins(src, got) 32614- want := expected(t, test, items) 32615- if diff := tests.DiffCompletionItems(want, got); diff != "" { 32616- t.Errorf("mismatching completion items (-want +got):\n%s", diff) 32617- } 32618-} 32619- 32620-func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { 32621- got := r.callCompletion(t, src, func(opts *source.Options) { 32622- opts.DeepCompletion = true 32623- opts.Matcher = source.Fuzzy 32624- opts.CompleteUnimported = false 32625- opts.LiteralCompletions = true 32626- opts.ExperimentalPostfixCompletions = true 32627- }) 32628- want := expected(t, test, items) 32629- if msg := tests.CheckCompletionOrder(want, got, true); msg != "" { 32630- t.Errorf("%s", msg) 32631- } 32632-} 32633- 32634-func expected(t *testing.T, test tests.Completion, items tests.CompletionItems) []protocol.CompletionItem { 32635- t.Helper() 32636- 32637- toProtocolCompletionItem := func(item *completion.CompletionItem) protocol.CompletionItem { 32638- pItem := protocol.CompletionItem{ 32639- Label: item.Label, 32640- Kind: item.Kind, 32641- Detail: item.Detail, 32642- Documentation: &protocol.Or_CompletionItem_documentation{ 32643- Value: item.Documentation, 32644- }, 32645- InsertText: item.InsertText, 32646- TextEdit: &protocol.TextEdit{ 32647- NewText: item.Snippet(), 32648- }, 32649- // Negate score so best score has lowest sort text like real API. 32650- SortText: fmt.Sprint(-item.Score), 32651- } 32652- if pItem.InsertText == "" { 32653- pItem.InsertText = pItem.Label 32654- } 32655- return pItem 32656- } 32657- 32658- var want []protocol.CompletionItem 32659- for _, pos := range test.CompletionItems { 32660- want = append(want, toProtocolCompletionItem(items[pos])) 32661- } 32662- return want 32663-} 32664- 32665-func (r *runner) callCompletion(t *testing.T, src span.Span, options func(*source.Options)) []protocol.CompletionItem { 32666- t.Helper() 32667- 32668- view, err := r.server.session.ViewOf(src.URI()) 32669- if err != nil { 32670- t.Fatal(err) 32671- } 32672- original := view.Options() 32673- modified := view.Options().Clone() 32674- options(modified) 32675- view, err = r.server.session.SetViewOptions(r.ctx, view, modified) 32676- if err != nil { 32677- t.Error(err) 32678- return nil 32679- } 32680- defer r.server.session.SetViewOptions(r.ctx, view, original) 32681- 32682- list, err := r.server.Completion(r.ctx, &protocol.CompletionParams{ 32683- TextDocumentPositionParams: protocol.TextDocumentPositionParams{ 32684- TextDocument: protocol.TextDocumentIdentifier{ 32685- URI: protocol.URIFromSpanURI(src.URI()), 32686- }, 32687- Position: protocol.Position{ 32688- Line: uint32(src.Start().Line() - 1), 32689- Character: uint32(src.Start().Column() - 1), 32690- }, 32691- }, 32692- }) 32693- if err != nil { 32694- t.Fatal(err) 32695- } 32696- return list.Items 32697-} 32698diff -urN a/gopls/internal/lsp/debounce.go b/gopls/internal/lsp/debounce.go 32699--- a/gopls/internal/lsp/debounce.go 2000-01-01 00:00:00.000000000 -0000 32700+++ b/gopls/internal/lsp/debounce.go 1970-01-01 00:00:00.000000000 +0000 32701@@ -1,71 +0,0 @@ 32702-// Copyright 2020 The Go Authors. All rights reserved. 32703-// Use of this source code is governed by a BSD-style 32704-// license that can be found in the LICENSE file. 32705- 32706-package lsp 32707- 32708-import ( 32709- "sync" 32710- "time" 32711-) 32712- 32713-type debounceEvent struct { 32714- order uint64 32715- done chan struct{} 32716-} 32717- 32718-type debouncer struct { 32719- mu sync.Mutex 32720- events map[string]*debounceEvent 32721-} 32722- 32723-func newDebouncer() *debouncer { 32724- return &debouncer{ 32725- events: make(map[string]*debounceEvent), 32726- } 32727-} 32728- 32729-// debounce returns a channel that receives a boolean reporting whether, 32730-// by the time the delay channel receives a value, this call is (or will be) 32731-// the most recent call with the highest order number for its key. 32732-func (d *debouncer) debounce(key string, order uint64, delay <-chan time.Time) <-chan bool { 32733- okc := make(chan bool, 1) 32734- 32735- d.mu.Lock() 32736- if prev, ok := d.events[key]; ok { 32737- if prev.order > order { 32738- // If we have a logical ordering of events (as is the case for snapshots), 32739- // don't overwrite a later event with an earlier event. 32740- d.mu.Unlock() 32741- okc <- false 32742- return okc 32743- } 32744- close(prev.done) 32745- } 32746- done := make(chan struct{}) 32747- next := &debounceEvent{ 32748- order: order, 32749- done: done, 32750- } 32751- d.events[key] = next 32752- d.mu.Unlock() 32753- 32754- go func() { 32755- ok := false 32756- select { 32757- case <-delay: 32758- d.mu.Lock() 32759- if d.events[key] == next { 32760- ok = true 32761- delete(d.events, key) 32762- } else { 32763- // The event was superseded before we acquired d.mu. 32764- } 32765- d.mu.Unlock() 32766- case <-done: 32767- } 32768- okc <- ok 32769- }() 32770- 32771- return okc 32772-} 32773diff -urN a/gopls/internal/lsp/debounce_test.go b/gopls/internal/lsp/debounce_test.go 32774--- a/gopls/internal/lsp/debounce_test.go 2000-01-01 00:00:00.000000000 -0000 32775+++ b/gopls/internal/lsp/debounce_test.go 1970-01-01 00:00:00.000000000 +0000 32776@@ -1,81 +0,0 @@ 32777-// Copyright 2020 The Go Authors. All rights reserved. 32778-// Use of this source code is governed by a BSD-style 32779-// license that can be found in the LICENSE file. 32780- 32781-package lsp 32782- 32783-import ( 32784- "testing" 32785- "time" 32786-) 32787- 32788-func TestDebouncer(t *testing.T) { 32789- t.Parallel() 32790- 32791- type event struct { 32792- key string 32793- order uint64 32794- wantFired bool 32795- } 32796- tests := []struct { 32797- label string 32798- events []*event 32799- }{ 32800- { 32801- label: "overridden", 32802- events: []*event{ 32803- {key: "a", order: 1, wantFired: false}, 32804- {key: "a", order: 2, wantFired: true}, 32805- }, 32806- }, 32807- { 32808- label: "distinct labels", 32809- events: []*event{ 32810- {key: "a", order: 1, wantFired: true}, 32811- {key: "b", order: 2, wantFired: true}, 32812- }, 32813- }, 32814- { 32815- label: "reverse order", 32816- events: []*event{ 32817- {key: "a", order: 2, wantFired: true}, 32818- {key: "a", order: 1, wantFired: false}, 32819- }, 32820- }, 32821- { 32822- label: "multiple overrides", 32823- events: []*event{ 32824- {key: "a", order: 1, wantFired: false}, 32825- {key: "a", order: 2, wantFired: false}, 32826- {key: "a", order: 3, wantFired: false}, 32827- {key: "a", order: 4, wantFired: false}, 32828- {key: "a", order: 5, wantFired: true}, 32829- }, 32830- }, 32831- } 32832- for _, test := range tests { 32833- test := test 32834- t.Run(test.label, func(t *testing.T) { 32835- d := newDebouncer() 32836- 32837- delays := make([]chan time.Time, len(test.events)) 32838- okcs := make([]<-chan bool, len(test.events)) 32839- 32840- // Register the events in deterministic order, synchronously. 32841- for i, e := range test.events { 32842- delays[i] = make(chan time.Time, 1) 32843- okcs[i] = d.debounce(e.key, e.order, delays[i]) 32844- } 32845- 32846- // Now see which event fired. 32847- for i, okc := range okcs { 32848- event := test.events[i] 32849- delays[i] <- time.Now() 32850- fired := <-okc 32851- if fired != event.wantFired { 32852- t.Errorf("[key: %q, order: %d]: fired = %t, want %t", event.key, event.order, fired, event.wantFired) 32853- } 32854- } 32855- }) 32856- } 32857-} 32858diff -urN a/gopls/internal/lsp/debug/buildinfo_go1.12.go b/gopls/internal/lsp/debug/buildinfo_go1.12.go 32859--- a/gopls/internal/lsp/debug/buildinfo_go1.12.go 2000-01-01 00:00:00.000000000 -0000 32860+++ b/gopls/internal/lsp/debug/buildinfo_go1.12.go 1970-01-01 00:00:00.000000000 +0000 32861@@ -1,29 +0,0 @@ 32862-// Copyright 2022 The Go Authors. All rights reserved. 32863-// Use of this source code is governed by a BSD-style 32864-// license that can be found in the LICENSE file. 32865- 32866-//go:build !go1.18 32867-// +build !go1.18 32868- 32869-package debug 32870- 32871-import ( 32872- "runtime" 32873- "runtime/debug" 32874-) 32875- 32876-type BuildInfo struct { 32877- debug.BuildInfo 32878- GoVersion string // Version of Go that produced this binary 32879-} 32880- 32881-func readBuildInfo() (*BuildInfo, bool) { 32882- rinfo, ok := debug.ReadBuildInfo() 32883- if !ok { 32884- return nil, false 32885- } 32886- return &BuildInfo{ 32887- GoVersion: runtime.Version(), 32888- BuildInfo: *rinfo, 32889- }, true 32890-} 32891diff -urN a/gopls/internal/lsp/debug/buildinfo_go1.18.go b/gopls/internal/lsp/debug/buildinfo_go1.18.go 32892--- a/gopls/internal/lsp/debug/buildinfo_go1.18.go 2000-01-01 00:00:00.000000000 -0000 32893+++ b/gopls/internal/lsp/debug/buildinfo_go1.18.go 1970-01-01 00:00:00.000000000 +0000 32894@@ -1,19 +0,0 @@ 32895-// Copyright 2022 The Go Authors. All rights reserved. 32896-// Use of this source code is governed by a BSD-style 32897-// license that can be found in the LICENSE file. 32898- 32899-//go:build go1.18 32900-// +build go1.18 32901- 32902-package debug 32903- 32904-import ( 32905- "runtime/debug" 32906-) 32907- 32908-type BuildInfo debug.BuildInfo 32909- 32910-func readBuildInfo() (*BuildInfo, bool) { 32911- info, ok := debug.ReadBuildInfo() 32912- return (*BuildInfo)(info), ok 32913-} 32914diff -urN a/gopls/internal/lsp/debug/info.go b/gopls/internal/lsp/debug/info.go 32915--- a/gopls/internal/lsp/debug/info.go 2000-01-01 00:00:00.000000000 -0000 32916+++ b/gopls/internal/lsp/debug/info.go 1970-01-01 00:00:00.000000000 +0000 32917@@ -1,254 +0,0 @@ 32918-// Copyright 2019 The Go Authors. All rights reserved. 32919-// Use of this source code is governed by a BSD-style 32920-// license that can be found in the LICENSE file. 32921- 32922-// Package debug exports debug information for gopls. 32923-package debug 32924- 32925-import ( 32926- "context" 32927- "encoding/json" 32928- "fmt" 32929- "io" 32930- "reflect" 32931- "runtime" 32932- "runtime/debug" 32933- "sort" 32934- "strings" 32935- 32936- "golang.org/x/tools/gopls/internal/lsp/source" 32937-) 32938- 32939-type PrintMode int 32940- 32941-const ( 32942- PlainText = PrintMode(iota) 32943- Markdown 32944- HTML 32945- JSON 32946-) 32947- 32948-// Version is a manually-updated mechanism for tracking versions. 32949-const Version = "master" 32950- 32951-// ServerVersion is the format used by gopls to report its version to the 32952-// client. This format is structured so that the client can parse it easily. 32953-type ServerVersion struct { 32954- *BuildInfo 32955- Version string 32956-} 32957- 32958-// VersionInfo returns the build info for the gopls process. If it was not 32959-// built in module mode, we return a GOPATH-specific message with the 32960-// hardcoded version. 32961-func VersionInfo() *ServerVersion { 32962- if info, ok := readBuildInfo(); ok { 32963- return getVersion(info) 32964- } 32965- buildInfo := &BuildInfo{} 32966- // go1.17 or earlier, part of s.BuildInfo are embedded fields. 32967- buildInfo.Path = "gopls, built in GOPATH mode" 32968- buildInfo.GoVersion = runtime.Version() 32969- return &ServerVersion{ 32970- Version: Version, 32971- BuildInfo: buildInfo, 32972- } 32973-} 32974- 32975-func getVersion(info *BuildInfo) *ServerVersion { 32976- return &ServerVersion{ 32977- Version: Version, 32978- BuildInfo: info, 32979- } 32980-} 32981- 32982-// PrintServerInfo writes HTML debug info to w for the Instance. 32983-func (i *Instance) PrintServerInfo(ctx context.Context, w io.Writer) { 32984- section(w, HTML, "Server Instance", func() { 32985- fmt.Fprintf(w, "Start time: %v\n", i.StartTime) 32986- fmt.Fprintf(w, "LogFile: %s\n", i.Logfile) 32987- fmt.Fprintf(w, "Working directory: %s\n", i.Workdir) 32988- fmt.Fprintf(w, "Address: %s\n", i.ServerAddress) 32989- fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress()) 32990- }) 32991- PrintVersionInfo(ctx, w, true, HTML) 32992- section(w, HTML, "Command Line", func() { 32993- fmt.Fprintf(w, "<a href=/debug/pprof/cmdline>cmdline</a>") 32994- }) 32995-} 32996- 32997-// PrintVersionInfo writes version information to w, using the output format 32998-// specified by mode. verbose controls whether additional information is 32999-// written, including section headers. 33000-func PrintVersionInfo(_ context.Context, w io.Writer, verbose bool, mode PrintMode) error { 33001- info := VersionInfo() 33002- if mode == JSON { 33003- return printVersionInfoJSON(w, info) 33004- } 33005- 33006- if !verbose { 33007- printBuildInfo(w, info, false, mode) 33008- return nil 33009- } 33010- section(w, mode, "Build info", func() { 33011- printBuildInfo(w, info, true, mode) 33012- }) 33013- return nil 33014-} 33015- 33016-func printVersionInfoJSON(w io.Writer, info *ServerVersion) error { 33017- js, err := json.MarshalIndent(info, "", "\t") 33018- if err != nil { 33019- return err 33020- } 33021- _, err = fmt.Fprint(w, string(js)) 33022- return err 33023-} 33024- 33025-func section(w io.Writer, mode PrintMode, title string, body func()) { 33026- switch mode { 33027- case PlainText: 33028- fmt.Fprintln(w, title) 33029- fmt.Fprintln(w, strings.Repeat("-", len(title))) 33030- body() 33031- case Markdown: 33032- fmt.Fprintf(w, "#### %s\n\n```\n", title) 33033- body() 33034- fmt.Fprintf(w, "```\n") 33035- case HTML: 33036- fmt.Fprintf(w, "<h3>%s</h3>\n<pre>\n", title) 33037- body() 33038- fmt.Fprint(w, "</pre>\n") 33039- } 33040-} 33041- 33042-func printBuildInfo(w io.Writer, info *ServerVersion, verbose bool, mode PrintMode) { 33043- fmt.Fprintf(w, "%v %v\n", info.Path, Version) 33044- printModuleInfo(w, info.Main, mode) 33045- if !verbose { 33046- return 33047- } 33048- for _, dep := range info.Deps { 33049- printModuleInfo(w, *dep, mode) 33050- } 33051- fmt.Fprintf(w, "go: %v\n", info.GoVersion) 33052-} 33053- 33054-func printModuleInfo(w io.Writer, m debug.Module, _ PrintMode) { 33055- fmt.Fprintf(w, " %s@%s", m.Path, m.Version) 33056- if m.Sum != "" { 33057- fmt.Fprintf(w, " %s", m.Sum) 33058- } 33059- if m.Replace != nil { 33060- fmt.Fprintf(w, " => %v", m.Replace.Path) 33061- } 33062- fmt.Fprintf(w, "\n") 33063-} 33064- 33065-type field struct { 33066- index []int 33067-} 33068- 33069-var fields []field 33070- 33071-// find all the options. The presumption is that the Options are nested structs 33072-// and that pointers don't need to be dereferenced 33073-func swalk(t reflect.Type, ix []int, indent string) { 33074- switch t.Kind() { 33075- case reflect.Struct: 33076- for i := 0; i < t.NumField(); i++ { 33077- fld := t.Field(i) 33078- ixx := append(append([]int{}, ix...), i) 33079- swalk(fld.Type, ixx, indent+". ") 33080- } 33081- default: 33082- // everything is either a struct or a field (that's an assumption about Options) 33083- fields = append(fields, field{ix}) 33084- } 33085-} 33086- 33087-type sessionOption struct { 33088- Name string 33089- Type string 33090- Current string 33091- Default string 33092-} 33093- 33094-func showOptions(o *source.Options) []sessionOption { 33095- var out []sessionOption 33096- t := reflect.TypeOf(*o) 33097- swalk(t, []int{}, "") 33098- v := reflect.ValueOf(*o) 33099- do := reflect.ValueOf(*source.DefaultOptions()) 33100- for _, f := range fields { 33101- val := v.FieldByIndex(f.index) 33102- def := do.FieldByIndex(f.index) 33103- tx := t.FieldByIndex(f.index) 33104- is := strVal(val) 33105- was := strVal(def) 33106- out = append(out, sessionOption{ 33107- Name: tx.Name, 33108- Type: tx.Type.String(), 33109- Current: is, 33110- Default: was, 33111- }) 33112- } 33113- sort.Slice(out, func(i, j int) bool { 33114- rd := out[i].Current == out[i].Default 33115- ld := out[j].Current == out[j].Default 33116- if rd != ld { 33117- return ld 33118- } 33119- return out[i].Name < out[j].Name 33120- }) 33121- return out 33122-} 33123- 33124-func strVal(val reflect.Value) string { 33125- switch val.Kind() { 33126- case reflect.Bool: 33127- return fmt.Sprintf("%v", val.Interface()) 33128- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 33129- return fmt.Sprintf("%v", val.Interface()) 33130- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 33131- return fmt.Sprintf("%v", val.Interface()) 33132- case reflect.Uintptr, reflect.UnsafePointer: 33133- return fmt.Sprintf("0x%x", val.Pointer()) 33134- case reflect.Complex64, reflect.Complex128: 33135- return fmt.Sprintf("%v", val.Complex()) 33136- case reflect.Array, reflect.Slice: 33137- ans := []string{} 33138- for i := 0; i < val.Len(); i++ { 33139- ans = append(ans, strVal(val.Index(i))) 33140- } 33141- sort.Strings(ans) 33142- return fmt.Sprintf("%v", ans) 33143- case reflect.Chan, reflect.Func, reflect.Ptr: 33144- return val.Kind().String() 33145- case reflect.Struct: 33146- var x source.Analyzer 33147- if val.Type() != reflect.TypeOf(x) { 33148- return val.Kind().String() 33149- } 33150- // this is sort of ugly, but usable 33151- str := val.FieldByName("Analyzer").Elem().FieldByName("Doc").String() 33152- ix := strings.Index(str, "\n") 33153- if ix == -1 { 33154- ix = len(str) 33155- } 33156- return str[:ix] 33157- case reflect.String: 33158- return fmt.Sprintf("%q", val.Interface()) 33159- case reflect.Map: 33160- ans := []string{} 33161- iter := val.MapRange() 33162- for iter.Next() { 33163- k := iter.Key() 33164- v := iter.Value() 33165- ans = append(ans, fmt.Sprintf("%s:%s, ", strVal(k), strVal(v))) 33166- } 33167- sort.Strings(ans) 33168- return fmt.Sprintf("%v", ans) 33169- } 33170- return fmt.Sprintf("??%s??", val.Type()) 33171-} 33172diff -urN a/gopls/internal/lsp/debug/info_test.go b/gopls/internal/lsp/debug/info_test.go 33173--- a/gopls/internal/lsp/debug/info_test.go 2000-01-01 00:00:00.000000000 -0000 33174+++ b/gopls/internal/lsp/debug/info_test.go 1970-01-01 00:00:00.000000000 +0000 33175@@ -1,47 +0,0 @@ 33176-// Copyright 2022 The Go Authors. All rights reserved. 33177-// Use of this source code is governed by a BSD-style 33178-// license that can be found in the LICENSE file. 33179- 33180-// Package debug exports debug information for gopls. 33181-package debug 33182- 33183-import ( 33184- "bytes" 33185- "context" 33186- "encoding/json" 33187- "runtime" 33188- "testing" 33189-) 33190- 33191-func TestPrintVersionInfoJSON(t *testing.T) { 33192- buf := new(bytes.Buffer) 33193- if err := PrintVersionInfo(context.Background(), buf, true, JSON); err != nil { 33194- t.Fatalf("PrintVersionInfo failed: %v", err) 33195- } 33196- res := buf.Bytes() 33197- 33198- var got ServerVersion 33199- if err := json.Unmarshal(res, &got); err != nil { 33200- t.Fatalf("unexpected output: %v\n%s", err, res) 33201- } 33202- if g, w := got.GoVersion, runtime.Version(); g != w { 33203- t.Errorf("go version = %v, want %v", g, w) 33204- } 33205- if g, w := got.Version, Version; g != w { 33206- t.Errorf("gopls version = %v, want %v", g, w) 33207- } 33208- // Other fields of BuildInfo may not be available during test. 33209-} 33210- 33211-func TestPrintVersionInfoPlainText(t *testing.T) { 33212- buf := new(bytes.Buffer) 33213- if err := PrintVersionInfo(context.Background(), buf, true, PlainText); err != nil { 33214- t.Fatalf("PrintVersionInfo failed: %v", err) 33215- } 33216- res := buf.Bytes() 33217- 33218- // Other fields of BuildInfo may not be available during test. 33219- if !bytes.Contains(res, []byte(Version)) || !bytes.Contains(res, []byte(runtime.Version())) { 33220- t.Errorf("plaintext output = %q,\nwant (version: %v, go: %v)", res, Version, runtime.Version()) 33221- } 33222-} 33223diff -urN a/gopls/internal/lsp/debug/log/log.go b/gopls/internal/lsp/debug/log/log.go 33224--- a/gopls/internal/lsp/debug/log/log.go 2000-01-01 00:00:00.000000000 -0000 33225+++ b/gopls/internal/lsp/debug/log/log.go 1970-01-01 00:00:00.000000000 +0000 33226@@ -1,43 +0,0 @@ 33227-// Copyright 2020 The Go Authors. All rights reserved. 33228-// Use of this source code is governed by a BSD-style 33229-// license that can be found in the LICENSE file. 33230- 33231-// Package log provides helper methods for exporting log events to the 33232-// internal/event package. 33233-package log 33234- 33235-import ( 33236- "context" 33237- "fmt" 33238- 33239- "golang.org/x/tools/internal/event" 33240- "golang.org/x/tools/internal/event/label" 33241- "golang.org/x/tools/internal/event/tag" 33242-) 33243- 33244-// Level parameterizes log severity. 33245-type Level int 33246- 33247-const ( 33248- _ Level = iota 33249- Error 33250- Warning 33251- Info 33252- Debug 33253- Trace 33254-) 33255- 33256-// Log exports a log event labeled with level l. 33257-func (l Level) Log(ctx context.Context, msg string) { 33258- event.Log(ctx, msg, tag.Level.Of(int(l))) 33259-} 33260- 33261-// Logf formats and exports a log event labeled with level l. 33262-func (l Level) Logf(ctx context.Context, format string, args ...interface{}) { 33263- l.Log(ctx, fmt.Sprintf(format, args...)) 33264-} 33265- 33266-// LabeledLevel extracts the labeled log l 33267-func LabeledLevel(lm label.Map) Level { 33268- return Level(tag.Level.Get(lm)) 33269-} 33270diff -urN a/gopls/internal/lsp/debug/metrics.go b/gopls/internal/lsp/debug/metrics.go 33271--- a/gopls/internal/lsp/debug/metrics.go 2000-01-01 00:00:00.000000000 -0000 33272+++ b/gopls/internal/lsp/debug/metrics.go 1970-01-01 00:00:00.000000000 +0000 33273@@ -1,58 +0,0 @@ 33274-// Copyright 2019 The Go Authors. All rights reserved. 33275-// Use of this source code is governed by a BSD-style 33276-// license that can be found in the LICENSE file. 33277- 33278-package debug 33279- 33280-import ( 33281- "golang.org/x/tools/internal/event/export/metric" 33282- "golang.org/x/tools/internal/event/label" 33283- "golang.org/x/tools/internal/event/tag" 33284-) 33285- 33286-var ( 33287- // the distributions we use for histograms 33288- bytesDistribution = []int64{1 << 10, 1 << 11, 1 << 12, 1 << 14, 1 << 16, 1 << 20} 33289- millisecondsDistribution = []float64{0.1, 0.5, 1, 2, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000} 33290- 33291- receivedBytes = metric.HistogramInt64{ 33292- Name: "received_bytes", 33293- Description: "Distribution of received bytes, by method.", 33294- Keys: []label.Key{tag.RPCDirection, tag.Method}, 33295- Buckets: bytesDistribution, 33296- } 33297- 33298- sentBytes = metric.HistogramInt64{ 33299- Name: "sent_bytes", 33300- Description: "Distribution of sent bytes, by method.", 33301- Keys: []label.Key{tag.RPCDirection, tag.Method}, 33302- Buckets: bytesDistribution, 33303- } 33304- 33305- latency = metric.HistogramFloat64{ 33306- Name: "latency", 33307- Description: "Distribution of latency in milliseconds, by method.", 33308- Keys: []label.Key{tag.RPCDirection, tag.Method}, 33309- Buckets: millisecondsDistribution, 33310- } 33311- 33312- started = metric.Scalar{ 33313- Name: "started", 33314- Description: "Count of RPCs started by method.", 33315- Keys: []label.Key{tag.RPCDirection, tag.Method}, 33316- } 33317- 33318- completed = metric.Scalar{ 33319- Name: "completed", 33320- Description: "Count of RPCs completed by method and status.", 33321- Keys: []label.Key{tag.RPCDirection, tag.Method, tag.StatusCode}, 33322- } 33323-) 33324- 33325-func registerMetrics(m *metric.Config) { 33326- receivedBytes.Record(m, tag.ReceivedBytes) 33327- sentBytes.Record(m, tag.SentBytes) 33328- latency.Record(m, tag.Latency) 33329- started.Count(m, tag.Started) 33330- completed.Count(m, tag.Latency) 33331-} 33332diff -urN a/gopls/internal/lsp/debug/rpc.go b/gopls/internal/lsp/debug/rpc.go 33333--- a/gopls/internal/lsp/debug/rpc.go 2000-01-01 00:00:00.000000000 -0000 33334+++ b/gopls/internal/lsp/debug/rpc.go 1970-01-01 00:00:00.000000000 +0000 33335@@ -1,239 +0,0 @@ 33336-// Copyright 2019 The Go Authors. All rights reserved. 33337-// Use of this source code is governed by a BSD-style 33338-// license that can be found in the LICENSE file. 33339- 33340-package debug 33341- 33342-import ( 33343- "context" 33344- "fmt" 33345- "html/template" 33346- "net/http" 33347- "sort" 33348- "sync" 33349- "time" 33350- 33351- "golang.org/x/tools/internal/event" 33352- "golang.org/x/tools/internal/event/core" 33353- "golang.org/x/tools/internal/event/export" 33354- "golang.org/x/tools/internal/event/label" 33355- "golang.org/x/tools/internal/event/tag" 33356-) 33357- 33358-var RPCTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 33359-{{define "title"}}RPC Information{{end}} 33360-{{define "body"}} 33361- <H2>Inbound</H2> 33362- {{template "rpcSection" .Inbound}} 33363- <H2>Outbound</H2> 33364- {{template "rpcSection" .Outbound}} 33365-{{end}} 33366-{{define "rpcSection"}} 33367- {{range .}}<P> 33368- <b>{{.Method}}</b> {{.Started}} <a href="/trace/{{.Method}}">traces</a> ({{.InProgress}} in progress) 33369- <br> 33370- <i>Latency</i> {{with .Latency}}{{.Mean}} ({{.Min}}<{{.Max}}){{end}} 33371- <i>By bucket</i> 0s {{range .Latency.Values}}{{if gt .Count 0}}<b>{{.Count}}</b> {{.Limit}} {{end}}{{end}} 33372- <br> 33373- <i>Received</i> {{.Received}} (avg. {{.ReceivedMean}}) 33374- <i>Sent</i> {{.Sent}} (avg. {{.SentMean}}) 33375- <br> 33376- <i>Result codes</i> {{range .Codes}}{{.Key}}={{.Count}} {{end}} 33377- </P> 33378- {{end}} 33379-{{end}} 33380-`)) 33381- 33382-type Rpcs struct { // exported for testing 33383- mu sync.Mutex 33384- Inbound []*rpcStats // stats for incoming lsp rpcs sorted by method name 33385- Outbound []*rpcStats // stats for outgoing lsp rpcs sorted by method name 33386-} 33387- 33388-type rpcStats struct { 33389- Method string 33390- Started int64 33391- Completed int64 33392- 33393- Latency rpcTimeHistogram 33394- Received byteUnits 33395- Sent byteUnits 33396- Codes []*rpcCodeBucket 33397-} 33398- 33399-type rpcTimeHistogram struct { 33400- Sum timeUnits 33401- Count int64 33402- Min timeUnits 33403- Max timeUnits 33404- Values []rpcTimeBucket 33405-} 33406- 33407-type rpcTimeBucket struct { 33408- Limit timeUnits 33409- Count int64 33410-} 33411- 33412-type rpcCodeBucket struct { 33413- Key string 33414- Count int64 33415-} 33416- 33417-func (r *Rpcs) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context { 33418- r.mu.Lock() 33419- defer r.mu.Unlock() 33420- switch { 33421- case event.IsStart(ev): 33422- if _, stats := r.getRPCSpan(ctx, ev); stats != nil { 33423- stats.Started++ 33424- } 33425- case event.IsEnd(ev): 33426- span, stats := r.getRPCSpan(ctx, ev) 33427- if stats != nil { 33428- endRPC(ctx, ev, span, stats) 33429- } 33430- case event.IsMetric(ev): 33431- sent := byteUnits(tag.SentBytes.Get(lm)) 33432- rec := byteUnits(tag.ReceivedBytes.Get(lm)) 33433- if sent != 0 || rec != 0 { 33434- if _, stats := r.getRPCSpan(ctx, ev); stats != nil { 33435- stats.Sent += sent 33436- stats.Received += rec 33437- } 33438- } 33439- } 33440- return ctx 33441-} 33442- 33443-func endRPC(ctx context.Context, ev core.Event, span *export.Span, stats *rpcStats) { 33444- // update the basic counts 33445- stats.Completed++ 33446- 33447- // get and record the status code 33448- if status := getStatusCode(span); status != "" { 33449- var b *rpcCodeBucket 33450- for c, entry := range stats.Codes { 33451- if entry.Key == status { 33452- b = stats.Codes[c] 33453- break 33454- } 33455- } 33456- if b == nil { 33457- b = &rpcCodeBucket{Key: status} 33458- stats.Codes = append(stats.Codes, b) 33459- sort.Slice(stats.Codes, func(i int, j int) bool { 33460- return stats.Codes[i].Key < stats.Codes[j].Key 33461- }) 33462- } 33463- b.Count++ 33464- } 33465- 33466- // calculate latency if this was an rpc span 33467- elapsedTime := span.Finish().At().Sub(span.Start().At()) 33468- latencyMillis := timeUnits(elapsedTime) / timeUnits(time.Millisecond) 33469- if stats.Latency.Count == 0 { 33470- stats.Latency.Min = latencyMillis 33471- stats.Latency.Max = latencyMillis 33472- } else { 33473- if stats.Latency.Min > latencyMillis { 33474- stats.Latency.Min = latencyMillis 33475- } 33476- if stats.Latency.Max < latencyMillis { 33477- stats.Latency.Max = latencyMillis 33478- } 33479- } 33480- stats.Latency.Count++ 33481- stats.Latency.Sum += latencyMillis 33482- for i := range stats.Latency.Values { 33483- if stats.Latency.Values[i].Limit > latencyMillis { 33484- stats.Latency.Values[i].Count++ 33485- break 33486- } 33487- } 33488-} 33489- 33490-func (r *Rpcs) getRPCSpan(ctx context.Context, ev core.Event) (*export.Span, *rpcStats) { 33491- // get the span 33492- span := export.GetSpan(ctx) 33493- if span == nil { 33494- return nil, nil 33495- } 33496- // use the span start event look up the correct stats block 33497- // we do this because it prevents us matching a sub span 33498- return span, r.getRPCStats(span.Start()) 33499-} 33500- 33501-func (r *Rpcs) getRPCStats(lm label.Map) *rpcStats { 33502- method := tag.Method.Get(lm) 33503- if method == "" { 33504- return nil 33505- } 33506- set := &r.Inbound 33507- if tag.RPCDirection.Get(lm) != tag.Inbound { 33508- set = &r.Outbound 33509- } 33510- // get the record for this method 33511- index := sort.Search(len(*set), func(i int) bool { 33512- return (*set)[i].Method >= method 33513- }) 33514- 33515- if index < len(*set) && (*set)[index].Method == method { 33516- return (*set)[index] 33517- } 33518- 33519- old := *set 33520- *set = make([]*rpcStats, len(old)+1) 33521- copy(*set, old[:index]) 33522- copy((*set)[index+1:], old[index:]) 33523- stats := &rpcStats{Method: method} 33524- stats.Latency.Values = make([]rpcTimeBucket, len(millisecondsDistribution)) 33525- for i, m := range millisecondsDistribution { 33526- stats.Latency.Values[i].Limit = timeUnits(m) 33527- } 33528- (*set)[index] = stats 33529- return stats 33530-} 33531- 33532-func (s *rpcStats) InProgress() int64 { return s.Started - s.Completed } 33533-func (s *rpcStats) SentMean() byteUnits { return s.Sent / byteUnits(s.Started) } 33534-func (s *rpcStats) ReceivedMean() byteUnits { return s.Received / byteUnits(s.Started) } 33535- 33536-func (h *rpcTimeHistogram) Mean() timeUnits { return h.Sum / timeUnits(h.Count) } 33537- 33538-func getStatusCode(span *export.Span) string { 33539- for _, ev := range span.Events() { 33540- if status := tag.StatusCode.Get(ev); status != "" { 33541- return status 33542- } 33543- } 33544- return "" 33545-} 33546- 33547-func (r *Rpcs) getData(req *http.Request) interface{} { 33548- return r 33549-} 33550- 33551-func units(v float64, suffixes []string) string { 33552- s := "" 33553- for _, s = range suffixes { 33554- n := v / 1000 33555- if n < 1 { 33556- break 33557- } 33558- v = n 33559- } 33560- return fmt.Sprintf("%.2f%s", v, s) 33561-} 33562- 33563-type timeUnits float64 33564- 33565-func (v timeUnits) String() string { 33566- v = v * 1000 * 1000 33567- return units(float64(v), []string{"ns", "μs", "ms", "s"}) 33568-} 33569- 33570-type byteUnits float64 33571- 33572-func (v byteUnits) String() string { 33573- return units(float64(v), []string{"B", "KB", "MB", "GB", "TB"}) 33574-} 33575diff -urN a/gopls/internal/lsp/debug/serve.go b/gopls/internal/lsp/debug/serve.go 33576--- a/gopls/internal/lsp/debug/serve.go 2000-01-01 00:00:00.000000000 -0000 33577+++ b/gopls/internal/lsp/debug/serve.go 1970-01-01 00:00:00.000000000 +0000 33578@@ -1,909 +0,0 @@ 33579-// Copyright 2019 The Go Authors. All rights reserved. 33580-// Use of this source code is governed by a BSD-style 33581-// license that can be found in the LICENSE file. 33582- 33583-package debug 33584- 33585-import ( 33586- "archive/zip" 33587- "bytes" 33588- "context" 33589- "errors" 33590- "fmt" 33591- "html/template" 33592- "io" 33593- stdlog "log" 33594- "net" 33595- "net/http" 33596- "net/http/pprof" 33597- "os" 33598- "path" 33599- "path/filepath" 33600- "runtime" 33601- rpprof "runtime/pprof" 33602- "strconv" 33603- "strings" 33604- "sync" 33605- "time" 33606- 33607- "golang.org/x/tools/gopls/internal/lsp/cache" 33608- "golang.org/x/tools/gopls/internal/lsp/debug/log" 33609- "golang.org/x/tools/gopls/internal/lsp/protocol" 33610- "golang.org/x/tools/internal/bug" 33611- "golang.org/x/tools/internal/event" 33612- "golang.org/x/tools/internal/event/core" 33613- "golang.org/x/tools/internal/event/export" 33614- "golang.org/x/tools/internal/event/export/metric" 33615- "golang.org/x/tools/internal/event/export/ocagent" 33616- "golang.org/x/tools/internal/event/export/prometheus" 33617- "golang.org/x/tools/internal/event/keys" 33618- "golang.org/x/tools/internal/event/label" 33619- "golang.org/x/tools/internal/event/tag" 33620-) 33621- 33622-type contextKeyType int 33623- 33624-const ( 33625- instanceKey contextKeyType = iota 33626- traceKey 33627-) 33628- 33629-// An Instance holds all debug information associated with a gopls instance. 33630-type Instance struct { 33631- Logfile string 33632- StartTime time.Time 33633- ServerAddress string 33634- Workdir string 33635- OCAgentConfig string 33636- 33637- LogWriter io.Writer 33638- 33639- exporter event.Exporter 33640- 33641- ocagent *ocagent.Exporter 33642- prometheus *prometheus.Exporter 33643- rpcs *Rpcs 33644- traces *traces 33645- State *State 33646- 33647- serveMu sync.Mutex 33648- debugAddress string 33649- listenedDebugAddress string 33650-} 33651- 33652-// State holds debugging information related to the server state. 33653-type State struct { 33654- mu sync.Mutex 33655- clients []*Client 33656- servers []*Server 33657-} 33658- 33659-func (st *State) Bugs() []bug.Bug { 33660- return bug.List() 33661-} 33662- 33663-// Caches returns the set of Cache objects currently being served. 33664-func (st *State) Caches() []*cache.Cache { 33665- var caches []*cache.Cache 33666- seen := make(map[string]struct{}) 33667- for _, client := range st.Clients() { 33668- cache := client.Session.Cache() 33669- if _, found := seen[cache.ID()]; found { 33670- continue 33671- } 33672- seen[cache.ID()] = struct{}{} 33673- caches = append(caches, cache) 33674- } 33675- return caches 33676-} 33677- 33678-// Cache returns the Cache that matches the supplied id. 33679-func (st *State) Cache(id string) *cache.Cache { 33680- for _, c := range st.Caches() { 33681- if c.ID() == id { 33682- return c 33683- } 33684- } 33685- return nil 33686-} 33687- 33688-// Sessions returns the set of Session objects currently being served. 33689-func (st *State) Sessions() []*cache.Session { 33690- var sessions []*cache.Session 33691- for _, client := range st.Clients() { 33692- sessions = append(sessions, client.Session) 33693- } 33694- return sessions 33695-} 33696- 33697-// Session returns the Session that matches the supplied id. 33698-func (st *State) Session(id string) *cache.Session { 33699- for _, s := range st.Sessions() { 33700- if s.ID() == id { 33701- return s 33702- } 33703- } 33704- return nil 33705-} 33706- 33707-// Views returns the set of View objects currently being served. 33708-func (st *State) Views() []*cache.View { 33709- var views []*cache.View 33710- for _, s := range st.Sessions() { 33711- views = append(views, s.Views()...) 33712- } 33713- return views 33714-} 33715- 33716-// View returns the View that matches the supplied id. 33717-func (st *State) View(id string) *cache.View { 33718- for _, v := range st.Views() { 33719- if v.ID() == id { 33720- return v 33721- } 33722- } 33723- return nil 33724-} 33725- 33726-// Clients returns the set of Clients currently being served. 33727-func (st *State) Clients() []*Client { 33728- st.mu.Lock() 33729- defer st.mu.Unlock() 33730- clients := make([]*Client, len(st.clients)) 33731- copy(clients, st.clients) 33732- return clients 33733-} 33734- 33735-// Client returns the Client matching the supplied id. 33736-func (st *State) Client(id string) *Client { 33737- for _, c := range st.Clients() { 33738- if c.Session.ID() == id { 33739- return c 33740- } 33741- } 33742- return nil 33743-} 33744- 33745-// Servers returns the set of Servers the instance is currently connected to. 33746-func (st *State) Servers() []*Server { 33747- st.mu.Lock() 33748- defer st.mu.Unlock() 33749- servers := make([]*Server, len(st.servers)) 33750- copy(servers, st.servers) 33751- return servers 33752-} 33753- 33754-// A Client is an incoming connection from a remote client. 33755-type Client struct { 33756- Session *cache.Session 33757- DebugAddress string 33758- Logfile string 33759- GoplsPath string 33760- ServerID string 33761- Service protocol.Server 33762-} 33763- 33764-// A Server is an outgoing connection to a remote LSP server. 33765-type Server struct { 33766- ID string 33767- DebugAddress string 33768- Logfile string 33769- GoplsPath string 33770- ClientID string 33771-} 33772- 33773-// addClient adds a client to the set being served. 33774-func (st *State) addClient(session *cache.Session) { 33775- st.mu.Lock() 33776- defer st.mu.Unlock() 33777- st.clients = append(st.clients, &Client{Session: session}) 33778-} 33779- 33780-// dropClient removes a client from the set being served. 33781-func (st *State) dropClient(session *cache.Session) { 33782- st.mu.Lock() 33783- defer st.mu.Unlock() 33784- for i, c := range st.clients { 33785- if c.Session == session { 33786- copy(st.clients[i:], st.clients[i+1:]) 33787- st.clients[len(st.clients)-1] = nil 33788- st.clients = st.clients[:len(st.clients)-1] 33789- return 33790- } 33791- } 33792-} 33793- 33794-// updateServer updates a server to the set being queried. In practice, there should 33795-// be at most one remote server. 33796-func (st *State) updateServer(server *Server) { 33797- st.mu.Lock() 33798- defer st.mu.Unlock() 33799- for i, existing := range st.servers { 33800- if existing.ID == server.ID { 33801- // Replace, rather than mutate, to avoid a race. 33802- newServers := make([]*Server, len(st.servers)) 33803- copy(newServers, st.servers[:i]) 33804- newServers[i] = server 33805- copy(newServers[i+1:], st.servers[i+1:]) 33806- st.servers = newServers 33807- return 33808- } 33809- } 33810- st.servers = append(st.servers, server) 33811-} 33812- 33813-// dropServer drops a server from the set being queried. 33814-func (st *State) dropServer(id string) { 33815- st.mu.Lock() 33816- defer st.mu.Unlock() 33817- for i, s := range st.servers { 33818- if s.ID == id { 33819- copy(st.servers[i:], st.servers[i+1:]) 33820- st.servers[len(st.servers)-1] = nil 33821- st.servers = st.servers[:len(st.servers)-1] 33822- return 33823- } 33824- } 33825-} 33826- 33827-// an http.ResponseWriter that filters writes 33828-type filterResponse struct { 33829- w http.ResponseWriter 33830- edit func([]byte) []byte 33831-} 33832- 33833-func (c filterResponse) Header() http.Header { 33834- return c.w.Header() 33835-} 33836- 33837-func (c filterResponse) Write(buf []byte) (int, error) { 33838- ans := c.edit(buf) 33839- return c.w.Write(ans) 33840-} 33841- 33842-func (c filterResponse) WriteHeader(n int) { 33843- c.w.WriteHeader(n) 33844-} 33845- 33846-// replace annoying nuls by spaces 33847-func cmdline(w http.ResponseWriter, r *http.Request) { 33848- fake := filterResponse{ 33849- w: w, 33850- edit: func(buf []byte) []byte { 33851- return bytes.ReplaceAll(buf, []byte{0}, []byte{' '}) 33852- }, 33853- } 33854- pprof.Cmdline(fake, r) 33855-} 33856- 33857-func (i *Instance) getCache(r *http.Request) interface{} { 33858- return i.State.Cache(path.Base(r.URL.Path)) 33859-} 33860- 33861-func (i *Instance) getSession(r *http.Request) interface{} { 33862- return i.State.Session(path.Base(r.URL.Path)) 33863-} 33864- 33865-func (i *Instance) getClient(r *http.Request) interface{} { 33866- return i.State.Client(path.Base(r.URL.Path)) 33867-} 33868- 33869-func (i *Instance) getServer(r *http.Request) interface{} { 33870- i.State.mu.Lock() 33871- defer i.State.mu.Unlock() 33872- id := path.Base(r.URL.Path) 33873- for _, s := range i.State.servers { 33874- if s.ID == id { 33875- return s 33876- } 33877- } 33878- return nil 33879-} 33880- 33881-func (i *Instance) getView(r *http.Request) interface{} { 33882- return i.State.View(path.Base(r.URL.Path)) 33883-} 33884- 33885-func (i *Instance) getFile(r *http.Request) interface{} { 33886- identifier := path.Base(r.URL.Path) 33887- sid := path.Base(path.Dir(r.URL.Path)) 33888- s := i.State.Session(sid) 33889- if s == nil { 33890- return nil 33891- } 33892- for _, o := range s.Overlays() { 33893- // TODO(adonovan): understand and document this comparison. 33894- if o.FileIdentity().Hash.String() == identifier { 33895- return o 33896- } 33897- } 33898- return nil 33899-} 33900- 33901-func (i *Instance) getInfo(r *http.Request) interface{} { 33902- buf := &bytes.Buffer{} 33903- i.PrintServerInfo(r.Context(), buf) 33904- return template.HTML(buf.String()) 33905-} 33906- 33907-func (i *Instance) AddService(s protocol.Server, session *cache.Session) { 33908- for _, c := range i.State.clients { 33909- if c.Session == session { 33910- c.Service = s 33911- return 33912- } 33913- } 33914- stdlog.Printf("unable to find a Client to add the protocol.Server to") 33915-} 33916- 33917-func getMemory(_ *http.Request) interface{} { 33918- var m runtime.MemStats 33919- runtime.ReadMemStats(&m) 33920- return m 33921-} 33922- 33923-func init() { 33924- event.SetExporter(makeGlobalExporter(os.Stderr)) 33925-} 33926- 33927-func GetInstance(ctx context.Context) *Instance { 33928- if ctx == nil { 33929- return nil 33930- } 33931- v := ctx.Value(instanceKey) 33932- if v == nil { 33933- return nil 33934- } 33935- return v.(*Instance) 33936-} 33937- 33938-// WithInstance creates debug instance ready for use using the supplied 33939-// configuration and stores it in the returned context. 33940-func WithInstance(ctx context.Context, workdir, agent string) context.Context { 33941- i := &Instance{ 33942- StartTime: time.Now(), 33943- Workdir: workdir, 33944- OCAgentConfig: agent, 33945- } 33946- i.LogWriter = os.Stderr 33947- ocConfig := ocagent.Discover() 33948- //TODO: we should not need to adjust the discovered configuration 33949- ocConfig.Address = i.OCAgentConfig 33950- i.ocagent = ocagent.Connect(ocConfig) 33951- i.prometheus = prometheus.New() 33952- i.rpcs = &Rpcs{} 33953- i.traces = &traces{} 33954- i.State = &State{} 33955- i.exporter = makeInstanceExporter(i) 33956- return context.WithValue(ctx, instanceKey, i) 33957-} 33958- 33959-// SetLogFile sets the logfile for use with this instance. 33960-func (i *Instance) SetLogFile(logfile string, isDaemon bool) (func(), error) { 33961- // TODO: probably a better solution for deferring closure to the caller would 33962- // be for the debug instance to itself be closed, but this fixes the 33963- // immediate bug of logs not being captured. 33964- closeLog := func() {} 33965- if logfile != "" { 33966- if logfile == "auto" { 33967- if isDaemon { 33968- logfile = filepath.Join(os.TempDir(), fmt.Sprintf("gopls-daemon-%d.log", os.Getpid())) 33969- } else { 33970- logfile = filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.log", os.Getpid())) 33971- } 33972- } 33973- f, err := os.Create(logfile) 33974- if err != nil { 33975- return nil, fmt.Errorf("unable to create log file: %w", err) 33976- } 33977- closeLog = func() { 33978- defer f.Close() 33979- } 33980- stdlog.SetOutput(io.MultiWriter(os.Stderr, f)) 33981- i.LogWriter = f 33982- } 33983- i.Logfile = logfile 33984- return closeLog, nil 33985-} 33986- 33987-// Serve starts and runs a debug server in the background on the given addr. 33988-// It also logs the port the server starts on, to allow for :0 auto assigned 33989-// ports. 33990-func (i *Instance) Serve(ctx context.Context, addr string) (string, error) { 33991- stdlog.SetFlags(stdlog.Lshortfile) 33992- if addr == "" { 33993- return "", nil 33994- } 33995- i.serveMu.Lock() 33996- defer i.serveMu.Unlock() 33997- 33998- if i.listenedDebugAddress != "" { 33999- // Already serving. Return the bound address. 34000- return i.listenedDebugAddress, nil 34001- } 34002- 34003- i.debugAddress = addr 34004- listener, err := net.Listen("tcp", i.debugAddress) 34005- if err != nil { 34006- return "", err 34007- } 34008- i.listenedDebugAddress = listener.Addr().String() 34009- 34010- port := listener.Addr().(*net.TCPAddr).Port 34011- if strings.HasSuffix(i.debugAddress, ":0") { 34012- stdlog.Printf("debug server listening at http://localhost:%d", port) 34013- } 34014- event.Log(ctx, "Debug serving", tag.Port.Of(port)) 34015- go func() { 34016- mux := http.NewServeMux() 34017- mux.HandleFunc("/", render(MainTmpl, func(*http.Request) interface{} { return i })) 34018- mux.HandleFunc("/debug/", render(DebugTmpl, nil)) 34019- mux.HandleFunc("/debug/pprof/", pprof.Index) 34020- mux.HandleFunc("/debug/pprof/cmdline", cmdline) 34021- mux.HandleFunc("/debug/pprof/profile", pprof.Profile) 34022- mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 34023- mux.HandleFunc("/debug/pprof/trace", pprof.Trace) 34024- if i.prometheus != nil { 34025- mux.HandleFunc("/metrics/", i.prometheus.Serve) 34026- } 34027- if i.rpcs != nil { 34028- mux.HandleFunc("/rpc/", render(RPCTmpl, i.rpcs.getData)) 34029- } 34030- if i.traces != nil { 34031- mux.HandleFunc("/trace/", render(TraceTmpl, i.traces.getData)) 34032- } 34033- mux.HandleFunc("/cache/", render(CacheTmpl, i.getCache)) 34034- mux.HandleFunc("/session/", render(SessionTmpl, i.getSession)) 34035- mux.HandleFunc("/view/", render(ViewTmpl, i.getView)) 34036- mux.HandleFunc("/client/", render(ClientTmpl, i.getClient)) 34037- mux.HandleFunc("/server/", render(ServerTmpl, i.getServer)) 34038- mux.HandleFunc("/file/", render(FileTmpl, i.getFile)) 34039- mux.HandleFunc("/info", render(InfoTmpl, i.getInfo)) 34040- mux.HandleFunc("/memory", render(MemoryTmpl, getMemory)) 34041- 34042- // Internal debugging helpers. 34043- mux.HandleFunc("/_dogc", func(w http.ResponseWriter, r *http.Request) { 34044- runtime.GC() 34045- runtime.GC() 34046- runtime.GC() 34047- http.Error(w, "OK", 200) 34048- }) 34049- mux.HandleFunc("/_makeabug", func(w http.ResponseWriter, r *http.Request) { 34050- bug.Report("bug here", nil) 34051- http.Error(w, "made a bug", http.StatusOK) 34052- }) 34053- 34054- if err := http.Serve(listener, mux); err != nil { 34055- event.Error(ctx, "Debug server failed", err) 34056- return 34057- } 34058- event.Log(ctx, "Debug server finished") 34059- }() 34060- return i.listenedDebugAddress, nil 34061-} 34062- 34063-func (i *Instance) DebugAddress() string { 34064- i.serveMu.Lock() 34065- defer i.serveMu.Unlock() 34066- return i.debugAddress 34067-} 34068- 34069-func (i *Instance) ListenedDebugAddress() string { 34070- i.serveMu.Lock() 34071- defer i.serveMu.Unlock() 34072- return i.listenedDebugAddress 34073-} 34074- 34075-// MonitorMemory starts recording memory statistics each second. 34076-func (i *Instance) MonitorMemory(ctx context.Context) { 34077- tick := time.NewTicker(time.Second) 34078- nextThresholdGiB := uint64(1) 34079- go func() { 34080- for { 34081- <-tick.C 34082- var mem runtime.MemStats 34083- runtime.ReadMemStats(&mem) 34084- if mem.HeapAlloc < nextThresholdGiB*1<<30 { 34085- continue 34086- } 34087- if err := i.writeMemoryDebug(nextThresholdGiB, true); err != nil { 34088- event.Error(ctx, "writing memory debug info", err) 34089- } 34090- if err := i.writeMemoryDebug(nextThresholdGiB, false); err != nil { 34091- event.Error(ctx, "writing memory debug info", err) 34092- } 34093- event.Log(ctx, fmt.Sprintf("Wrote memory usage debug info to %v", os.TempDir())) 34094- nextThresholdGiB++ 34095- } 34096- }() 34097-} 34098- 34099-func (i *Instance) writeMemoryDebug(threshold uint64, withNames bool) error { 34100- suffix := "withnames" 34101- if !withNames { 34102- suffix = "nonames" 34103- } 34104- 34105- filename := fmt.Sprintf("gopls.%d-%dGiB-%s.zip", os.Getpid(), threshold, suffix) 34106- zipf, err := os.OpenFile(filepath.Join(os.TempDir(), filename), os.O_CREATE|os.O_RDWR, 0644) 34107- if err != nil { 34108- return err 34109- } 34110- zipw := zip.NewWriter(zipf) 34111- 34112- f, err := zipw.Create("heap.pb.gz") 34113- if err != nil { 34114- return err 34115- } 34116- if err := rpprof.Lookup("heap").WriteTo(f, 0); err != nil { 34117- return err 34118- } 34119- 34120- f, err = zipw.Create("goroutines.txt") 34121- if err != nil { 34122- return err 34123- } 34124- if err := rpprof.Lookup("goroutine").WriteTo(f, 1); err != nil { 34125- return err 34126- } 34127- 34128- if err := zipw.Close(); err != nil { 34129- return err 34130- } 34131- return zipf.Close() 34132-} 34133- 34134-func makeGlobalExporter(stderr io.Writer) event.Exporter { 34135- p := export.Printer{} 34136- var pMu sync.Mutex 34137- return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { 34138- i := GetInstance(ctx) 34139- 34140- if event.IsLog(ev) { 34141- // Don't log context cancellation errors. 34142- if err := keys.Err.Get(ev); errors.Is(err, context.Canceled) { 34143- return ctx 34144- } 34145- // Make sure any log messages without an instance go to stderr. 34146- if i == nil { 34147- pMu.Lock() 34148- p.WriteEvent(stderr, ev, lm) 34149- pMu.Unlock() 34150- } 34151- level := log.LabeledLevel(lm) 34152- // Exclude trace logs from LSP logs. 34153- if level < log.Trace { 34154- ctx = protocol.LogEvent(ctx, ev, lm, messageType(level)) 34155- } 34156- } 34157- if i == nil { 34158- return ctx 34159- } 34160- return i.exporter(ctx, ev, lm) 34161- } 34162-} 34163- 34164-func messageType(l log.Level) protocol.MessageType { 34165- switch l { 34166- case log.Error: 34167- return protocol.Error 34168- case log.Warning: 34169- return protocol.Warning 34170- case log.Debug: 34171- return protocol.Log 34172- } 34173- return protocol.Info 34174-} 34175- 34176-func makeInstanceExporter(i *Instance) event.Exporter { 34177- exporter := func(ctx context.Context, ev core.Event, lm label.Map) context.Context { 34178- if i.ocagent != nil { 34179- ctx = i.ocagent.ProcessEvent(ctx, ev, lm) 34180- } 34181- if i.prometheus != nil { 34182- ctx = i.prometheus.ProcessEvent(ctx, ev, lm) 34183- } 34184- if i.rpcs != nil { 34185- ctx = i.rpcs.ProcessEvent(ctx, ev, lm) 34186- } 34187- if i.traces != nil { 34188- ctx = i.traces.ProcessEvent(ctx, ev, lm) 34189- } 34190- if event.IsLog(ev) { 34191- if s := cache.KeyCreateSession.Get(ev); s != nil { 34192- i.State.addClient(s) 34193- } 34194- if sid := tag.NewServer.Get(ev); sid != "" { 34195- i.State.updateServer(&Server{ 34196- ID: sid, 34197- Logfile: tag.Logfile.Get(ev), 34198- DebugAddress: tag.DebugAddress.Get(ev), 34199- GoplsPath: tag.GoplsPath.Get(ev), 34200- ClientID: tag.ClientID.Get(ev), 34201- }) 34202- } 34203- if s := cache.KeyShutdownSession.Get(ev); s != nil { 34204- i.State.dropClient(s) 34205- } 34206- if sid := tag.EndServer.Get(ev); sid != "" { 34207- i.State.dropServer(sid) 34208- } 34209- if s := cache.KeyUpdateSession.Get(ev); s != nil { 34210- if c := i.State.Client(s.ID()); c != nil { 34211- c.DebugAddress = tag.DebugAddress.Get(ev) 34212- c.Logfile = tag.Logfile.Get(ev) 34213- c.ServerID = tag.ServerID.Get(ev) 34214- c.GoplsPath = tag.GoplsPath.Get(ev) 34215- } 34216- } 34217- } 34218- return ctx 34219- } 34220- // StdTrace must be above export.Spans below (by convention, export 34221- // middleware applies its wrapped exporter last). 34222- exporter = StdTrace(exporter) 34223- metrics := metric.Config{} 34224- registerMetrics(&metrics) 34225- exporter = metrics.Exporter(exporter) 34226- exporter = export.Spans(exporter) 34227- exporter = export.Labels(exporter) 34228- return exporter 34229-} 34230- 34231-type dataFunc func(*http.Request) interface{} 34232- 34233-func render(tmpl *template.Template, fun dataFunc) func(http.ResponseWriter, *http.Request) { 34234- return func(w http.ResponseWriter, r *http.Request) { 34235- var data interface{} 34236- if fun != nil { 34237- data = fun(r) 34238- } 34239- if err := tmpl.Execute(w, data); err != nil { 34240- event.Error(context.Background(), "", err) 34241- http.Error(w, err.Error(), http.StatusInternalServerError) 34242- } 34243- } 34244-} 34245- 34246-func commas(s string) string { 34247- for i := len(s); i > 3; { 34248- i -= 3 34249- s = s[:i] + "," + s[i:] 34250- } 34251- return s 34252-} 34253- 34254-func fuint64(v uint64) string { 34255- return commas(strconv.FormatUint(v, 10)) 34256-} 34257- 34258-func fuint32(v uint32) string { 34259- return commas(strconv.FormatUint(uint64(v), 10)) 34260-} 34261- 34262-func fcontent(v []byte) string { 34263- return string(v) 34264-} 34265- 34266-var BaseTemplate = template.Must(template.New("").Parse(` 34267-<html> 34268-<head> 34269-<title>{{template "title" .}}</title> 34270-<style> 34271-.profile-name{ 34272- display:inline-block; 34273- width:6rem; 34274-} 34275-td.value { 34276- text-align: right; 34277-} 34278-ul.events { 34279- list-style-type: none; 34280-} 34281- 34282-</style> 34283-{{block "head" .}}{{end}} 34284-</head> 34285-<body> 34286-<a href="/">Main</a> 34287-<a href="/info">Info</a> 34288-<a href="/memory">Memory</a> 34289-<a href="/metrics">Metrics</a> 34290-<a href="/rpc">RPC</a> 34291-<a href="/trace">Trace</a> 34292-<hr> 34293-<h1>{{template "title" .}}</h1> 34294-{{block "body" .}} 34295-Unknown page 34296-{{end}} 34297-</body> 34298-</html> 34299- 34300-{{define "cachelink"}}<a href="/cache/{{.}}">Cache {{.}}</a>{{end}} 34301-{{define "clientlink"}}<a href="/client/{{.}}">Client {{.}}</a>{{end}} 34302-{{define "serverlink"}}<a href="/server/{{.}}">Server {{.}}</a>{{end}} 34303-{{define "sessionlink"}}<a href="/session/{{.}}">Session {{.}}</a>{{end}} 34304-{{define "viewlink"}}<a href="/view/{{.}}">View {{.}}</a>{{end}} 34305-`)).Funcs(template.FuncMap{ 34306- "fuint64": fuint64, 34307- "fuint32": fuint32, 34308- "fcontent": fcontent, 34309- "localAddress": func(s string) string { 34310- // Try to translate loopback addresses to localhost, both for cosmetics and 34311- // because unspecified ipv6 addresses can break links on Windows. 34312- // 34313- // TODO(rfindley): In the future, it would be better not to assume the 34314- // server is running on localhost, and instead construct this address using 34315- // the remote host. 34316- host, port, err := net.SplitHostPort(s) 34317- if err != nil { 34318- return s 34319- } 34320- ip := net.ParseIP(host) 34321- if ip == nil { 34322- return s 34323- } 34324- if ip.IsLoopback() || ip.IsUnspecified() { 34325- return "localhost:" + port 34326- } 34327- return s 34328- }, 34329- "options": func(s *cache.Session) []sessionOption { 34330- return showOptions(s.Options()) 34331- }, 34332-}) 34333- 34334-var MainTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34335-{{define "title"}}GoPls server information{{end}} 34336-{{define "body"}} 34337-<h2>Caches</h2> 34338-<ul>{{range .State.Caches}}<li>{{template "cachelink" .ID}}</li>{{end}}</ul> 34339-<h2>Sessions</h2> 34340-<ul>{{range .State.Sessions}}<li>{{template "sessionlink" .ID}} from {{template "cachelink" .Cache.ID}}</li>{{end}}</ul> 34341-<h2>Clients</h2> 34342-<ul>{{range .State.Clients}}<li>{{template "clientlink" .Session.ID}}</li>{{end}}</ul> 34343-<h2>Servers</h2> 34344-<ul>{{range .State.Servers}}<li>{{template "serverlink" .ID}}</li>{{end}}</ul> 34345-<h2>Bug reports</h2> 34346-<dl>{{range .State.Bugs}}<dt>{{.Key}}</dt><dd>{{.Description}}</dd>{{end}}</dl> 34347-{{end}} 34348-`)) 34349- 34350-var InfoTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34351-{{define "title"}}GoPls version information{{end}} 34352-{{define "body"}} 34353-{{.}} 34354-{{end}} 34355-`)) 34356- 34357-var MemoryTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34358-{{define "title"}}GoPls memory usage{{end}} 34359-{{define "head"}}<meta http-equiv="refresh" content="5">{{end}} 34360-{{define "body"}} 34361-<h2>Stats</h2> 34362-<table> 34363-<tr><td class="label">Allocated bytes</td><td class="value">{{fuint64 .HeapAlloc}}</td></tr> 34364-<tr><td class="label">Total allocated bytes</td><td class="value">{{fuint64 .TotalAlloc}}</td></tr> 34365-<tr><td class="label">System bytes</td><td class="value">{{fuint64 .Sys}}</td></tr> 34366-<tr><td class="label">Heap system bytes</td><td class="value">{{fuint64 .HeapSys}}</td></tr> 34367-<tr><td class="label">Malloc calls</td><td class="value">{{fuint64 .Mallocs}}</td></tr> 34368-<tr><td class="label">Frees</td><td class="value">{{fuint64 .Frees}}</td></tr> 34369-<tr><td class="label">Idle heap bytes</td><td class="value">{{fuint64 .HeapIdle}}</td></tr> 34370-<tr><td class="label">In use bytes</td><td class="value">{{fuint64 .HeapInuse}}</td></tr> 34371-<tr><td class="label">Released to system bytes</td><td class="value">{{fuint64 .HeapReleased}}</td></tr> 34372-<tr><td class="label">Heap object count</td><td class="value">{{fuint64 .HeapObjects}}</td></tr> 34373-<tr><td class="label">Stack in use bytes</td><td class="value">{{fuint64 .StackInuse}}</td></tr> 34374-<tr><td class="label">Stack from system bytes</td><td class="value">{{fuint64 .StackSys}}</td></tr> 34375-<tr><td class="label">Bucket hash bytes</td><td class="value">{{fuint64 .BuckHashSys}}</td></tr> 34376-<tr><td class="label">GC metadata bytes</td><td class="value">{{fuint64 .GCSys}}</td></tr> 34377-<tr><td class="label">Off heap bytes</td><td class="value">{{fuint64 .OtherSys}}</td></tr> 34378-</table> 34379-<h2>By size</h2> 34380-<table> 34381-<tr><th>Size</th><th>Mallocs</th><th>Frees</th></tr> 34382-{{range .BySize}}<tr><td class="value">{{fuint32 .Size}}</td><td class="value">{{fuint64 .Mallocs}}</td><td class="value">{{fuint64 .Frees}}</td></tr>{{end}} 34383-</table> 34384-{{end}} 34385-`)) 34386- 34387-var DebugTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34388-{{define "title"}}GoPls Debug pages{{end}} 34389-{{define "body"}} 34390-<a href="/debug/pprof">Profiling</a> 34391-{{end}} 34392-`)) 34393- 34394-var CacheTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34395-{{define "title"}}Cache {{.ID}}{{end}} 34396-{{define "body"}} 34397-<h2>memoize.Store entries</h2> 34398-<ul>{{range $k,$v := .MemStats}}<li>{{$k}} - {{$v}}</li>{{end}}</ul> 34399-{{end}} 34400-`)) 34401- 34402-var ClientTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34403-{{define "title"}}Client {{.Session.ID}}{{end}} 34404-{{define "body"}} 34405-Using session: <b>{{template "sessionlink" .Session.ID}}</b><br> 34406-{{if .DebugAddress}}Debug this client at: <a href="http://{{localAddress .DebugAddress}}">{{localAddress .DebugAddress}}</a><br>{{end}} 34407-Logfile: {{.Logfile}}<br> 34408-Gopls Path: {{.GoplsPath}}<br> 34409-<h2>Diagnostics</h2> 34410-{{/*Service: []protocol.Server; each server has map[uri]fileReports; 34411- each fileReport: map[diagnosticSoure]diagnosticReport 34412- diagnosticSource is one of 5 source 34413- diagnosticReport: snapshotID and map[hash]*source.Diagnostic 34414- sourceDiagnostic: struct { 34415- Range protocol.Range 34416- Message string 34417- Source string 34418- Code string 34419- CodeHref string 34420- Severity protocol.DiagnosticSeverity 34421- Tags []protocol.DiagnosticTag 34422- 34423- Related []RelatedInformation 34424- } 34425- RelatedInformation: struct { 34426- URI span.URI 34427- Range protocol.Range 34428- Message string 34429- } 34430- */}} 34431-<ul>{{range $k, $v := .Service.Diagnostics}}<li>{{$k}}:<ol>{{range $v}}<li>{{.}}</li>{{end}}</ol></li>{{end}}</ul> 34432-{{end}} 34433-`)) 34434- 34435-var ServerTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34436-{{define "title"}}Server {{.ID}}{{end}} 34437-{{define "body"}} 34438-{{if .DebugAddress}}Debug this server at: <a href="http://{{localAddress .DebugAddress}}">{{localAddress .DebugAddress}}</a><br>{{end}} 34439-Logfile: {{.Logfile}}<br> 34440-Gopls Path: {{.GoplsPath}}<br> 34441-{{end}} 34442-`)) 34443- 34444-var SessionTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34445-{{define "title"}}Session {{.ID}}{{end}} 34446-{{define "body"}} 34447-From: <b>{{template "cachelink" .Cache.ID}}</b><br> 34448-<h2>Views</h2> 34449-<ul>{{range .Views}}<li>{{.Name}} is {{template "viewlink" .ID}} in {{.Folder}}</li>{{end}}</ul> 34450-<h2>Overlays</h2> 34451-{{$session := .}} 34452-<ul>{{range .Overlays}} 34453-<li> 34454-<a href="/file/{{$session.ID}}/{{.FileIdentity.Hash}}">{{.FileIdentity.URI}}</a> 34455-</li>{{end}}</ul> 34456-<h2>Options</h2> 34457-{{range options .}} 34458-<p><b>{{.Name}}</b> {{.Type}}</p> 34459-<p><i>default:</i> {{.Default}}</p> 34460-{{if ne .Default .Current}}<p><i>current:</i> {{.Current}}</p>{{end}} 34461-{{end}} 34462-{{end}} 34463-`)) 34464- 34465-var ViewTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34466-{{define "title"}}View {{.ID}}{{end}} 34467-{{define "body"}} 34468-Name: <b>{{.Name}}</b><br> 34469-Folder: <b>{{.Folder}}</b><br> 34470-<h2>Environment</h2> 34471-<ul>{{range .Options.Env}}<li>{{.}}</li>{{end}}</ul> 34472-{{end}} 34473-`)) 34474- 34475-var FileTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34476-{{define "title"}}Overlay {{.FileIdentity.Hash}}{{end}} 34477-{{define "body"}} 34478-{{with .}} 34479- URI: <b>{{.URI}}</b><br> 34480- Identifier: <b>{{.FileIdentity.Hash}}</b><br> 34481- Version: <b>{{.Version}}</b><br> 34482- Kind: <b>{{.Kind}}</b><br> 34483-{{end}} 34484-<h3>Contents</h3> 34485-<pre>{{fcontent .Read}}</pre> 34486-{{end}} 34487-`)) 34488diff -urN a/gopls/internal/lsp/debug/trace.go b/gopls/internal/lsp/debug/trace.go 34489--- a/gopls/internal/lsp/debug/trace.go 2000-01-01 00:00:00.000000000 -0000 34490+++ b/gopls/internal/lsp/debug/trace.go 1970-01-01 00:00:00.000000000 +0000 34491@@ -1,233 +0,0 @@ 34492-// Copyright 2019 The Go Authors. All rights reserved. 34493-// Use of this source code is governed by a BSD-style 34494-// license that can be found in the LICENSE file. 34495- 34496-package debug 34497- 34498-import ( 34499- "bytes" 34500- "context" 34501- "fmt" 34502- "html/template" 34503- "net/http" 34504- "runtime/trace" 34505- "sort" 34506- "strings" 34507- "sync" 34508- "time" 34509- 34510- "golang.org/x/tools/internal/event" 34511- "golang.org/x/tools/internal/event/core" 34512- "golang.org/x/tools/internal/event/export" 34513- "golang.org/x/tools/internal/event/label" 34514-) 34515- 34516-var TraceTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` 34517-{{define "title"}}Trace Information{{end}} 34518-{{define "body"}} 34519- {{range .Traces}}<a href="/trace/{{.Name}}">{{.Name}}</a> last: {{.Last.Duration}}, longest: {{.Longest.Duration}}<br>{{end}} 34520- {{if .Selected}} 34521- <H2>{{.Selected.Name}}</H2> 34522- {{if .Selected.Last}}<H3>Last</H3><ul>{{template "details" .Selected.Last}}</ul>{{end}} 34523- {{if .Selected.Longest}}<H3>Longest</H3><ul>{{template "details" .Selected.Longest}}</ul>{{end}} 34524- {{end}} 34525-{{end}} 34526-{{define "details"}} 34527- <li>{{.Offset}} {{.Name}} {{.Duration}} {{.Tags}}</li> 34528- {{if .Events}}<ul class=events>{{range .Events}}<li>{{.Offset}} {{.Tags}}</li>{{end}}</ul>{{end}} 34529- {{if .Children}}<ul>{{range .Children}}{{template "details" .}}{{end}}</ul>{{end}} 34530-{{end}} 34531-`)) 34532- 34533-type traces struct { 34534- mu sync.Mutex 34535- sets map[string]*traceSet 34536- unfinished map[export.SpanContext]*traceData 34537-} 34538- 34539-type TraceResults struct { // exported for testing 34540- Traces []*traceSet 34541- Selected *traceSet 34542-} 34543- 34544-type traceSet struct { 34545- Name string 34546- Last *traceData 34547- Longest *traceData 34548-} 34549- 34550-type traceData struct { 34551- TraceID export.TraceID 34552- SpanID export.SpanID 34553- ParentID export.SpanID 34554- Name string 34555- Start time.Time 34556- Finish time.Time 34557- Offset time.Duration 34558- Duration time.Duration 34559- Tags string 34560- Events []traceEvent 34561- Children []*traceData 34562-} 34563- 34564-type traceEvent struct { 34565- Time time.Time 34566- Offset time.Duration 34567- Tags string 34568-} 34569- 34570-func StdTrace(exporter event.Exporter) event.Exporter { 34571- return func(ctx context.Context, ev core.Event, lm label.Map) context.Context { 34572- span := export.GetSpan(ctx) 34573- if span == nil { 34574- return exporter(ctx, ev, lm) 34575- } 34576- switch { 34577- case event.IsStart(ev): 34578- if span.ParentID.IsValid() { 34579- region := trace.StartRegion(ctx, span.Name) 34580- ctx = context.WithValue(ctx, traceKey, region) 34581- } else { 34582- var task *trace.Task 34583- ctx, task = trace.NewTask(ctx, span.Name) 34584- ctx = context.WithValue(ctx, traceKey, task) 34585- } 34586- // Log the start event as it may contain useful labels. 34587- msg := formatEvent(ctx, ev, lm) 34588- trace.Log(ctx, "start", msg) 34589- case event.IsLog(ev): 34590- category := "" 34591- if event.IsError(ev) { 34592- category = "error" 34593- } 34594- msg := formatEvent(ctx, ev, lm) 34595- trace.Log(ctx, category, msg) 34596- case event.IsEnd(ev): 34597- if v := ctx.Value(traceKey); v != nil { 34598- v.(interface{ End() }).End() 34599- } 34600- } 34601- return exporter(ctx, ev, lm) 34602- } 34603-} 34604- 34605-func formatEvent(ctx context.Context, ev core.Event, lm label.Map) string { 34606- buf := &bytes.Buffer{} 34607- p := export.Printer{} 34608- p.WriteEvent(buf, ev, lm) 34609- return buf.String() 34610-} 34611- 34612-func (t *traces) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context { 34613- span := export.GetSpan(ctx) 34614- if span == nil { 34615- return ctx 34616- } 34617- 34618- switch { 34619- case event.IsStart(ev): 34620- // Just starting: add it to the unfinished map. 34621- // Allocate before the critical section. 34622- td := &traceData{ 34623- TraceID: span.ID.TraceID, 34624- SpanID: span.ID.SpanID, 34625- ParentID: span.ParentID, 34626- Name: span.Name, 34627- Start: span.Start().At(), 34628- Tags: renderLabels(span.Start()), 34629- } 34630- 34631- t.mu.Lock() 34632- defer t.mu.Unlock() 34633- if t.sets == nil { 34634- t.sets = make(map[string]*traceSet) 34635- t.unfinished = make(map[export.SpanContext]*traceData) 34636- } 34637- t.unfinished[span.ID] = td 34638- // and wire up parents if we have them 34639- if !span.ParentID.IsValid() { 34640- return ctx 34641- } 34642- parentID := export.SpanContext{TraceID: span.ID.TraceID, SpanID: span.ParentID} 34643- parent, found := t.unfinished[parentID] 34644- if !found { 34645- // trace had an invalid parent, so it cannot itself be valid 34646- return ctx 34647- } 34648- parent.Children = append(parent.Children, td) 34649- 34650- case event.IsEnd(ev): 34651- // Finishing: must be already in the map. 34652- // Allocate events before the critical section. 34653- events := span.Events() 34654- tdEvents := make([]traceEvent, len(events)) 34655- for i, event := range events { 34656- tdEvents[i] = traceEvent{ 34657- Time: event.At(), 34658- Tags: renderLabels(event), 34659- } 34660- } 34661- 34662- t.mu.Lock() 34663- defer t.mu.Unlock() 34664- td, found := t.unfinished[span.ID] 34665- if !found { 34666- return ctx // if this happens we are in a bad place 34667- } 34668- delete(t.unfinished, span.ID) 34669- 34670- td.Finish = span.Finish().At() 34671- td.Duration = span.Finish().At().Sub(span.Start().At()) 34672- td.Events = tdEvents 34673- 34674- set, ok := t.sets[span.Name] 34675- if !ok { 34676- set = &traceSet{Name: span.Name} 34677- t.sets[span.Name] = set 34678- } 34679- set.Last = td 34680- if set.Longest == nil || set.Last.Duration > set.Longest.Duration { 34681- set.Longest = set.Last 34682- } 34683- if !td.ParentID.IsValid() { 34684- fillOffsets(td, td.Start) 34685- } 34686- } 34687- return ctx 34688-} 34689- 34690-func (t *traces) getData(req *http.Request) interface{} { 34691- if len(t.sets) == 0 { 34692- return nil 34693- } 34694- data := TraceResults{} 34695- data.Traces = make([]*traceSet, 0, len(t.sets)) 34696- for _, set := range t.sets { 34697- data.Traces = append(data.Traces, set) 34698- } 34699- sort.Slice(data.Traces, func(i, j int) bool { return data.Traces[i].Name < data.Traces[j].Name }) 34700- if bits := strings.SplitN(req.URL.Path, "/trace/", 2); len(bits) > 1 { 34701- data.Selected = t.sets[bits[1]] 34702- } 34703- return data 34704-} 34705- 34706-func fillOffsets(td *traceData, start time.Time) { 34707- td.Offset = td.Start.Sub(start) 34708- for i := range td.Events { 34709- td.Events[i].Offset = td.Events[i].Time.Sub(start) 34710- } 34711- for _, child := range td.Children { 34712- fillOffsets(child, start) 34713- } 34714-} 34715- 34716-func renderLabels(labels label.List) string { 34717- buf := &bytes.Buffer{} 34718- for index := 0; labels.Valid(index); index++ { 34719- if l := labels.Label(index); l.Valid() { 34720- fmt.Fprintf(buf, "%v ", l) 34721- } 34722- } 34723- return buf.String() 34724-} 34725diff -urN a/gopls/internal/lsp/definition.go b/gopls/internal/lsp/definition.go 34726--- a/gopls/internal/lsp/definition.go 2000-01-01 00:00:00.000000000 -0000 34727+++ b/gopls/internal/lsp/definition.go 1970-01-01 00:00:00.000000000 +0000 34728@@ -1,52 +0,0 @@ 34729-// Copyright 2019 The Go Authors. All rights reserved. 34730-// Use of this source code is governed by a BSD-style 34731-// license that can be found in the LICENSE file. 34732- 34733-package lsp 34734- 34735-import ( 34736- "context" 34737- "errors" 34738- "fmt" 34739- 34740- "golang.org/x/tools/gopls/internal/lsp/protocol" 34741- "golang.org/x/tools/gopls/internal/lsp/source" 34742- "golang.org/x/tools/gopls/internal/lsp/template" 34743-) 34744- 34745-func (s *Server) definition(ctx context.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) { 34746- // TODO(rfindley): definition requests should be multiplexed across all views. 34747- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 34748- defer release() 34749- if !ok { 34750- return nil, err 34751- } 34752- switch kind := snapshot.View().FileKind(fh); kind { 34753- case source.Tmpl: 34754- return template.Definition(snapshot, fh, params.Position) 34755- case source.Go: 34756- // Partial support for jumping from linkname directive (position at 2nd argument). 34757- locations, err := source.LinknameDefinition(ctx, snapshot, fh, params.Position) 34758- if !errors.Is(err, source.ErrNoLinkname) { 34759- return locations, err 34760- } 34761- return source.Definition(ctx, snapshot, fh, params.Position) 34762- default: 34763- return nil, fmt.Errorf("can't find definitions for file type %s", kind) 34764- } 34765-} 34766- 34767-func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefinitionParams) ([]protocol.Location, error) { 34768- // TODO(rfindley): type definition requests should be multiplexed across all views. 34769- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 34770- defer release() 34771- if !ok { 34772- return nil, err 34773- } 34774- switch kind := snapshot.View().FileKind(fh); kind { 34775- case source.Go: 34776- return source.TypeDefinition(ctx, snapshot, fh, params.Position) 34777- default: 34778- return nil, fmt.Errorf("can't find type definitions for file type %s", kind) 34779- } 34780-} 34781diff -urN a/gopls/internal/lsp/diagnostics.go b/gopls/internal/lsp/diagnostics.go 34782--- a/gopls/internal/lsp/diagnostics.go 2000-01-01 00:00:00.000000000 -0000 34783+++ b/gopls/internal/lsp/diagnostics.go 1970-01-01 00:00:00.000000000 +0000 34784@@ -1,764 +0,0 @@ 34785-// Copyright 2018 The Go Authors. All rights reserved. 34786-// Use of this source code is governed by a BSD-style 34787-// license that can be found in the LICENSE file. 34788- 34789-package lsp 34790- 34791-import ( 34792- "context" 34793- "crypto/sha256" 34794- "errors" 34795- "fmt" 34796- "os" 34797- "path/filepath" 34798- "strings" 34799- "sync" 34800- "time" 34801- 34802- "golang.org/x/sync/errgroup" 34803- "golang.org/x/tools/gopls/internal/lsp/debug/log" 34804- "golang.org/x/tools/gopls/internal/lsp/mod" 34805- "golang.org/x/tools/gopls/internal/lsp/protocol" 34806- "golang.org/x/tools/gopls/internal/lsp/source" 34807- "golang.org/x/tools/gopls/internal/lsp/template" 34808- "golang.org/x/tools/gopls/internal/lsp/work" 34809- "golang.org/x/tools/gopls/internal/span" 34810- "golang.org/x/tools/internal/event" 34811- "golang.org/x/tools/internal/event/tag" 34812- "golang.org/x/tools/internal/xcontext" 34813-) 34814- 34815-// diagnosticSource differentiates different sources of diagnostics. 34816-type diagnosticSource int 34817- 34818-const ( 34819- modSource diagnosticSource = iota 34820- gcDetailsSource 34821- analysisSource 34822- typeCheckSource 34823- orphanedSource 34824- workSource 34825- modCheckUpgradesSource 34826- modVulncheckSource // source.Govulncheck + source.Vulncheck 34827-) 34828- 34829-// A diagnosticReport holds results for a single diagnostic source. 34830-type diagnosticReport struct { 34831- snapshotID source.GlobalSnapshotID // global snapshot ID on which the report was computed 34832- publishedHash string // last published hash for this (URI, source) 34833- diags map[string]*source.Diagnostic 34834-} 34835- 34836-// fileReports holds a collection of diagnostic reports for a single file, as 34837-// well as the hash of the last published set of diagnostics. 34838-type fileReports struct { 34839- // publishedSnapshotID is the last snapshot ID for which we have "published" 34840- // diagnostics (though the publishDiagnostics notification may not have 34841- // actually been sent, if nothing changed). 34842- // 34843- // Specifically, publishedSnapshotID is updated to a later snapshot ID when 34844- // we either: 34845- // (1) publish diagnostics for the file for a snapshot, or 34846- // (2) determine that published diagnostics are valid for a new snapshot. 34847- // 34848- // Notably publishedSnapshotID may not match the snapshot id on individual reports in 34849- // the reports map: 34850- // - we may have published partial diagnostics from only a subset of 34851- // diagnostic sources for which new results have been computed, or 34852- // - we may have started computing reports for an even new snapshot, but not 34853- // yet published. 34854- // 34855- // This prevents gopls from publishing stale diagnostics. 34856- publishedSnapshotID source.GlobalSnapshotID 34857- 34858- // publishedHash is a hash of the latest diagnostics published for the file. 34859- publishedHash string 34860- 34861- // If set, mustPublish marks diagnostics as needing publication, independent 34862- // of whether their publishedHash has changed. 34863- mustPublish bool 34864- 34865- // The last stored diagnostics for each diagnostic source. 34866- reports map[diagnosticSource]diagnosticReport 34867-} 34868- 34869-func (d diagnosticSource) String() string { 34870- switch d { 34871- case modSource: 34872- return "FromSource" 34873- case gcDetailsSource: 34874- return "FromGCDetails" 34875- case analysisSource: 34876- return "FromAnalysis" 34877- case typeCheckSource: 34878- return "FromTypeChecking" 34879- case orphanedSource: 34880- return "FromOrphans" 34881- case workSource: 34882- return "FromGoWork" 34883- case modCheckUpgradesSource: 34884- return "FromCheckForUpgrades" 34885- case modVulncheckSource: 34886- return "FromModVulncheck" 34887- default: 34888- return fmt.Sprintf("From?%d?", d) 34889- } 34890-} 34891- 34892-// hashDiagnostics computes a hash to identify diags. 34893-func hashDiagnostics(diags ...*source.Diagnostic) string { 34894- source.SortDiagnostics(diags) 34895- h := sha256.New() 34896- for _, d := range diags { 34897- for _, t := range d.Tags { 34898- fmt.Fprintf(h, "%s", t) 34899- } 34900- for _, r := range d.Related { 34901- fmt.Fprintf(h, "%s%s%s", r.Location.URI.SpanURI(), r.Message, r.Location.Range) 34902- } 34903- fmt.Fprintf(h, "%s%s%s%s", d.Message, d.Range, d.Severity, d.Source) 34904- } 34905- return fmt.Sprintf("%x", h.Sum(nil)) 34906-} 34907- 34908-func (s *Server) diagnoseDetached(snapshot source.Snapshot) { 34909- ctx := snapshot.BackgroundContext() 34910- ctx = xcontext.Detach(ctx) 34911- s.diagnose(ctx, snapshot, false) 34912- s.publishDiagnostics(ctx, true, snapshot) 34913-} 34914- 34915-func (s *Server) diagnoseSnapshots(snapshots map[source.Snapshot][]span.URI, onDisk bool) { 34916- var diagnosticWG sync.WaitGroup 34917- for snapshot, uris := range snapshots { 34918- diagnosticWG.Add(1) 34919- go func(snapshot source.Snapshot, uris []span.URI) { 34920- defer diagnosticWG.Done() 34921- s.diagnoseSnapshot(snapshot, uris, onDisk) 34922- }(snapshot, uris) 34923- } 34924- diagnosticWG.Wait() 34925-} 34926- 34927-func (s *Server) diagnoseSnapshot(snapshot source.Snapshot, changedURIs []span.URI, onDisk bool) { 34928- ctx := snapshot.BackgroundContext() 34929- ctx, done := event.Start(ctx, "Server.diagnoseSnapshot", source.SnapshotLabels(snapshot)...) 34930- defer done() 34931- 34932- delay := snapshot.View().Options().DiagnosticsDelay 34933- if delay > 0 { 34934- // 2-phase diagnostics. 34935- // 34936- // The first phase just parses and type-checks (but 34937- // does not analyze) packages directly affected by 34938- // file modifications. 34939- // 34940- // The second phase runs analysis on the entire snapshot, 34941- // and is debounced by the configured delay. 34942- s.diagnoseChangedFiles(ctx, snapshot, changedURIs, onDisk) 34943- s.publishDiagnostics(ctx, false, snapshot) 34944- 34945- // We debounce diagnostics separately for each view, using the snapshot 34946- // local ID as logical ordering. 34947- // 34948- // TODO(rfindley): it would be cleaner to simply put the diagnostic 34949- // debouncer on the view, and remove the "key" argument to debouncing. 34950- if ok := <-s.diagDebouncer.debounce(snapshot.View().Name(), snapshot.SequenceID(), time.After(delay)); ok { 34951- s.diagnose(ctx, snapshot, false) 34952- s.publishDiagnostics(ctx, true, snapshot) 34953- } 34954- return 34955- } 34956- 34957- // Ignore possible workspace configuration warnings in the normal flow. 34958- s.diagnose(ctx, snapshot, false) 34959- s.publishDiagnostics(ctx, true, snapshot) 34960-} 34961- 34962-func (s *Server) diagnoseChangedFiles(ctx context.Context, snapshot source.Snapshot, uris []span.URI, onDisk bool) { 34963- ctx, done := event.Start(ctx, "Server.diagnoseChangedFiles", source.SnapshotLabels(snapshot)...) 34964- defer done() 34965- 34966- // TODO(adonovan): safety: refactor so that group.Go is called 34967- // in a second loop, so that if we should later add an early 34968- // return to the first loop, we don't leak goroutines. 34969- var group errgroup.Group 34970- seen := make(map[*source.Metadata]bool) 34971- for _, uri := range uris { 34972- // If the change is only on-disk and the file is not open, don't 34973- // directly request its package. It may not be a workspace package. 34974- if onDisk && !snapshot.IsOpen(uri) { 34975- continue 34976- } 34977- // If the file is not known to the snapshot (e.g., if it was deleted), 34978- // don't diagnose it. 34979- if snapshot.FindFile(uri) == nil { 34980- continue 34981- } 34982- 34983- // Don't request type-checking for builtin.go: it's not a real package. 34984- if snapshot.IsBuiltin(ctx, uri) { 34985- continue 34986- } 34987- 34988- // Find all packages that include this file and diagnose them in parallel. 34989- metas, err := snapshot.MetadataForFile(ctx, uri) 34990- if err != nil { 34991- // TODO(findleyr): we should probably do something with the error here, 34992- // but as of now this can fail repeatedly if load fails, so can be too 34993- // noisy to log (and we'll handle things later in the slow pass). 34994- continue 34995- } 34996- for _, m := range metas { 34997- if m.IsIntermediateTestVariant() { 34998- continue 34999- } 35000- if !seen[m] { 35001- seen[m] = true 35002- m := m 35003- group.Go(func() error { 35004- s.diagnosePkg(ctx, snapshot, m, false) 35005- return nil // error result is ignored 35006- }) 35007- } 35008- } 35009- } 35010- group.Wait() // ignore error 35011-} 35012- 35013-// diagnose is a helper function for running diagnostics with a given context. 35014-// Do not call it directly. forceAnalysis is only true for testing purposes. 35015-func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAnalysis bool) { 35016- ctx, done := event.Start(ctx, "Server.diagnose", source.SnapshotLabels(snapshot)...) 35017- defer done() 35018- 35019- // Wait for a free diagnostics slot. 35020- // TODO(adonovan): opt: shouldn't it be the analysis implementation's 35021- // job to de-dup and limit resource consumption? In any case this 35022- // this function spends most its time waiting for awaitLoaded, at 35023- // least initially. 35024- select { 35025- case <-ctx.Done(): 35026- return 35027- case s.diagnosticsSema <- struct{}{}: 35028- } 35029- defer func() { 35030- <-s.diagnosticsSema 35031- }() 35032- 35033- // common code for dispatching diagnostics 35034- store := func(dsource diagnosticSource, operation string, diagsByFile map[span.URI][]*source.Diagnostic, err error, merge bool) { 35035- if err != nil { 35036- event.Error(ctx, "warning: while "+operation, err, source.SnapshotLabels(snapshot)...) 35037- } 35038- for uri, diags := range diagsByFile { 35039- if uri == "" { 35040- event.Error(ctx, "missing URI while "+operation, fmt.Errorf("empty URI"), tag.Directory.Of(snapshot.View().Folder().Filename())) 35041- continue 35042- } 35043- s.storeDiagnostics(snapshot, uri, dsource, diags, merge) 35044- } 35045- } 35046- 35047- // Diagnose go.mod upgrades. 35048- upgradeReports, upgradeErr := mod.UpgradeDiagnostics(ctx, snapshot) 35049- if ctx.Err() != nil { 35050- log.Trace.Log(ctx, "diagnose cancelled") 35051- return 35052- } 35053- store(modCheckUpgradesSource, "diagnosing go.mod upgrades", upgradeReports, upgradeErr, true) 35054- 35055- // Diagnose go.work file. 35056- workReports, workErr := work.Diagnostics(ctx, snapshot) 35057- if ctx.Err() != nil { 35058- log.Trace.Log(ctx, "diagnose cancelled") 35059- return 35060- } 35061- store(workSource, "diagnosing go.work file", workReports, workErr, true) 35062- 35063- // Diagnose go.mod file. 35064- // (This step demands type checking of all active packages: 35065- // the bottleneck in the startup sequence for a big workspace.) 35066- modReports, modErr := mod.Diagnostics(ctx, snapshot) 35067- if ctx.Err() != nil { 35068- log.Trace.Log(ctx, "diagnose cancelled") 35069- return 35070- } 35071- store(modSource, "diagnosing go.mod file", modReports, modErr, true) 35072- 35073- // Diagnose vulnerabilities. 35074- vulnReports, vulnErr := mod.VulnerabilityDiagnostics(ctx, snapshot) 35075- if ctx.Err() != nil { 35076- log.Trace.Log(ctx, "diagnose cancelled") 35077- return 35078- } 35079- store(modVulncheckSource, "diagnosing vulnerabilities", vulnReports, vulnErr, false) 35080- 35081- activeMetas, activeErr := snapshot.ActiveMetadata(ctx) 35082- if s.shouldIgnoreError(ctx, snapshot, activeErr) { 35083- return 35084- } 35085- criticalErr := snapshot.GetCriticalError(ctx) 35086- if ctx.Err() != nil { // must check ctx after GetCriticalError 35087- return 35088- } 35089- 35090- // Show the error as a progress error report so that it appears in the 35091- // status bar. If a client doesn't support progress reports, the error 35092- // will still be shown as a ShowMessage. If there is no error, any running 35093- // error progress reports will be closed. 35094- s.showCriticalErrorStatus(ctx, snapshot, criticalErr) 35095- 35096- // Diagnose template (.tmpl) files. 35097- for _, f := range snapshot.Templates() { 35098- diags := template.Diagnose(f) 35099- s.storeDiagnostics(snapshot, f.URI(), typeCheckSource, diags, true) 35100- } 35101- 35102- // If there are no workspace packages, there is nothing to diagnose and 35103- // there are no orphaned files. 35104- if len(activeMetas) == 0 { 35105- return 35106- } 35107- 35108- // Run go/analysis diagnosis of packages in parallel. 35109- // TODO(adonovan): opt: it may be more efficient to 35110- // have diagnosePkg take a set of packages. 35111- // 35112- // TODO(adonovan): opt: since the new analysis driver does its 35113- // own type checking, we could strength-reduce pkg to 35114- // PackageID and get this step started as soon as the set of 35115- // active package IDs are known, without waiting for them to load. 35116- var ( 35117- wg sync.WaitGroup 35118- seen = map[span.URI]struct{}{} 35119- ) 35120- for _, m := range activeMetas { 35121- for _, uri := range m.CompiledGoFiles { 35122- seen[uri] = struct{}{} 35123- } 35124- 35125- wg.Add(1) 35126- go func(m *source.Metadata) { 35127- defer wg.Done() 35128- s.diagnosePkg(ctx, snapshot, m, forceAnalysis) 35129- }(m) 35130- } 35131- wg.Wait() 35132- 35133- // Orphaned files. 35134- // Confirm that every opened file belongs to a package (if any exist in 35135- // the workspace). Otherwise, add a diagnostic to the file. 35136- for _, o := range s.session.Overlays() { 35137- if _, ok := seen[o.URI()]; ok { 35138- continue 35139- } 35140- diagnostic := s.checkForOrphanedFile(ctx, snapshot, o) 35141- if diagnostic == nil { 35142- continue 35143- } 35144- s.storeDiagnostics(snapshot, o.URI(), orphanedSource, []*source.Diagnostic{diagnostic}, true) 35145- } 35146-} 35147- 35148-func (s *Server) diagnosePkg(ctx context.Context, snapshot source.Snapshot, m *source.Metadata, alwaysAnalyze bool) { 35149- ctx, done := event.Start(ctx, "Server.diagnosePkg", append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...) 35150- defer done() 35151- enableDiagnostics := false 35152- includeAnalysis := alwaysAnalyze // only run analyses for packages with open files 35153- for _, uri := range m.CompiledGoFiles { 35154- enableDiagnostics = enableDiagnostics || !snapshot.IgnoredFile(uri) 35155- includeAnalysis = includeAnalysis || snapshot.IsOpen(uri) 35156- } 35157- // Don't show any diagnostics on ignored files. 35158- if !enableDiagnostics { 35159- return 35160- } 35161- 35162- diags, err := snapshot.PackageDiagnostics(ctx, m.ID) 35163- if err != nil { 35164- event.Error(ctx, "warning: diagnostics failed", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...) 35165- return 35166- } 35167- 35168- // Get diagnostics from analysis framework. 35169- // This includes type-error analyzers, which suggest fixes to compiler errors. 35170- var analysisDiags map[span.URI][]*source.Diagnostic 35171- if includeAnalysis { 35172- diags, err := source.Analyze(ctx, snapshot, m.ID, false) 35173- if err != nil { 35174- event.Error(ctx, "warning: analyzing package", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...) 35175- return 35176- } 35177- analysisDiags = diags 35178- } 35179- 35180- // For each file, update the server's diagnostics state. 35181- for _, uri := range m.CompiledGoFiles { 35182- // builtin.go exists only for documentation purposes and 35183- // is not valid Go code. Don't report distracting errors. 35184- if snapshot.IsBuiltin(ctx, uri) { 35185- continue 35186- } 35187- 35188- pkgDiags := diags[uri] 35189- var tdiags, adiags []*source.Diagnostic 35190- source.CombineDiagnostics(pkgDiags, analysisDiags[uri], &tdiags, &adiags) 35191- s.storeDiagnostics(snapshot, uri, typeCheckSource, tdiags, true) 35192- s.storeDiagnostics(snapshot, uri, analysisSource, adiags, true) 35193- } 35194- 35195- // If gc optimization details are requested, add them to the 35196- // diagnostic reports. 35197- s.gcOptimizationDetailsMu.Lock() 35198- _, enableGCDetails := s.gcOptimizationDetails[m.ID] 35199- s.gcOptimizationDetailsMu.Unlock() 35200- if enableGCDetails { 35201- gcReports, err := source.GCOptimizationDetails(ctx, snapshot, m) 35202- if err != nil { 35203- event.Error(ctx, "warning: gc details", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...) 35204- } 35205- s.gcOptimizationDetailsMu.Lock() 35206- _, enableGCDetails := s.gcOptimizationDetails[m.ID] 35207- 35208- // NOTE(golang/go#44826): hold the gcOptimizationDetails lock, and re-check 35209- // whether gc optimization details are enabled, while storing gc_details 35210- // results. This ensures that the toggling of GC details and clearing of 35211- // diagnostics does not race with storing the results here. 35212- if enableGCDetails { 35213- for uri, diags := range gcReports { 35214- fh := snapshot.FindFile(uri) 35215- // Don't publish gc details for unsaved buffers, since the underlying 35216- // logic operates on the file on disk. 35217- if fh == nil || !fh.Saved() { 35218- continue 35219- } 35220- s.storeDiagnostics(snapshot, uri, gcDetailsSource, diags, true) 35221- } 35222- } 35223- s.gcOptimizationDetailsMu.Unlock() 35224- } 35225-} 35226- 35227-// mustPublishDiagnostics marks the uri as needing publication, independent of 35228-// whether the published contents have changed. 35229-// 35230-// This can be used for ensuring gopls publishes diagnostics after certain file 35231-// events. 35232-func (s *Server) mustPublishDiagnostics(uri span.URI) { 35233- s.diagnosticsMu.Lock() 35234- defer s.diagnosticsMu.Unlock() 35235- 35236- if s.diagnostics[uri] == nil { 35237- s.diagnostics[uri] = &fileReports{ 35238- publishedHash: hashDiagnostics(), // Hash for 0 diagnostics. 35239- reports: map[diagnosticSource]diagnosticReport{}, 35240- } 35241- } 35242- s.diagnostics[uri].mustPublish = true 35243-} 35244- 35245-// storeDiagnostics stores results from a single diagnostic source. If merge is 35246-// true, it merges results into any existing results for this snapshot. 35247-// 35248-// TODO(hyangah): investigate whether we can unconditionally overwrite previous report.diags 35249-// with the new diags and eliminate the need for the `merge` flag. 35250-func (s *Server) storeDiagnostics(snapshot source.Snapshot, uri span.URI, dsource diagnosticSource, diags []*source.Diagnostic, merge bool) { 35251- // Safeguard: ensure that the file actually exists in the snapshot 35252- // (see golang.org/issues/38602). 35253- fh := snapshot.FindFile(uri) 35254- if fh == nil { 35255- return 35256- } 35257- 35258- s.diagnosticsMu.Lock() 35259- defer s.diagnosticsMu.Unlock() 35260- if s.diagnostics[uri] == nil { 35261- s.diagnostics[uri] = &fileReports{ 35262- publishedHash: hashDiagnostics(), // Hash for 0 diagnostics. 35263- reports: map[diagnosticSource]diagnosticReport{}, 35264- } 35265- } 35266- report := s.diagnostics[uri].reports[dsource] 35267- // Don't set obsolete diagnostics. 35268- if report.snapshotID > snapshot.GlobalID() { 35269- return 35270- } 35271- if report.diags == nil || report.snapshotID != snapshot.GlobalID() || !merge { 35272- report.diags = map[string]*source.Diagnostic{} 35273- } 35274- report.snapshotID = snapshot.GlobalID() 35275- for _, d := range diags { 35276- report.diags[hashDiagnostics(d)] = d 35277- } 35278- s.diagnostics[uri].reports[dsource] = report 35279-} 35280- 35281-// clearDiagnosticSource clears all diagnostics for a given source type. It is 35282-// necessary for cases where diagnostics have been invalidated by something 35283-// other than a snapshot change, for example when gc_details is toggled. 35284-func (s *Server) clearDiagnosticSource(dsource diagnosticSource) { 35285- s.diagnosticsMu.Lock() 35286- defer s.diagnosticsMu.Unlock() 35287- for _, reports := range s.diagnostics { 35288- delete(reports.reports, dsource) 35289- } 35290-} 35291- 35292-const WorkspaceLoadFailure = "Error loading workspace" 35293- 35294-// showCriticalErrorStatus shows the error as a progress report. 35295-// If the error is nil, it clears any existing error progress report. 35296-func (s *Server) showCriticalErrorStatus(ctx context.Context, snapshot source.Snapshot, err *source.CriticalError) { 35297- s.criticalErrorStatusMu.Lock() 35298- defer s.criticalErrorStatusMu.Unlock() 35299- 35300- // Remove all newlines so that the error message can be formatted in a 35301- // status bar. 35302- var errMsg string 35303- if err != nil { 35304- event.Error(ctx, "errors loading workspace", err.MainError, source.SnapshotLabels(snapshot)...) 35305- for _, d := range err.Diagnostics { 35306- s.storeDiagnostics(snapshot, d.URI, modSource, []*source.Diagnostic{d}, true) 35307- } 35308- errMsg = strings.ReplaceAll(err.MainError.Error(), "\n", " ") 35309- } 35310- 35311- if s.criticalErrorStatus == nil { 35312- if errMsg != "" { 35313- s.criticalErrorStatus = s.progress.Start(ctx, WorkspaceLoadFailure, errMsg, nil, nil) 35314- } 35315- return 35316- } 35317- 35318- // If an error is already shown to the user, update it or mark it as 35319- // resolved. 35320- if errMsg == "" { 35321- s.criticalErrorStatus.End(ctx, "Done.") 35322- s.criticalErrorStatus = nil 35323- } else { 35324- s.criticalErrorStatus.Report(ctx, errMsg, 0) 35325- } 35326-} 35327- 35328-// checkForOrphanedFile checks that the given URIs can be mapped to packages. 35329-// If they cannot and the workspace is not otherwise unloaded, it also surfaces 35330-// a warning, suggesting that the user check the file for build tags. 35331-func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) *source.Diagnostic { 35332- // TODO(rfindley): this function may fail to produce a diagnostic for a 35333- // variety of reasons, some of which should probably not be ignored. For 35334- // example, should this function be tolerant of the case where fh does not 35335- // exist, or does not have a package name? 35336- // 35337- // It would be better to panic or report a bug in several of the cases below, 35338- // so that we can move toward guaranteeing we show the user a meaningful 35339- // error whenever it makes sense. 35340- if snapshot.View().FileKind(fh) != source.Go { 35341- return nil 35342- } 35343- // builtin files won't have a package, but they are never orphaned. 35344- if snapshot.IsBuiltin(ctx, fh.URI()) { 35345- return nil 35346- } 35347- 35348- // This call has the effect of inserting fh into snapshot.files, 35349- // where for better or worse (actually: just worse) it influences 35350- // the sets of open, known, and orphaned files. 35351- snapshot.GetFile(ctx, fh.URI()) 35352- 35353- metas, _ := snapshot.MetadataForFile(ctx, fh.URI()) 35354- if len(metas) > 0 || ctx.Err() != nil { 35355- return nil // no package, or cancelled 35356- } 35357- // Inv: file does not belong to a package we know about. 35358- pgf, err := snapshot.ParseGo(ctx, fh, source.ParseHeader) 35359- if err != nil { 35360- return nil 35361- } 35362- if !pgf.File.Name.Pos().IsValid() { 35363- return nil 35364- } 35365- rng, err := pgf.NodeRange(pgf.File.Name) 35366- if err != nil { 35367- return nil 35368- } 35369- // If the file no longer has a name ending in .go, this diagnostic is wrong 35370- if filepath.Ext(fh.URI().Filename()) != ".go" { 35371- return nil 35372- } 35373- // TODO(rstambler): We should be able to parse the build tags in the 35374- // file and show a more specific error message. For now, put the diagnostic 35375- // on the package declaration. 35376- return &source.Diagnostic{ 35377- URI: fh.URI(), 35378- Range: rng, 35379- Severity: protocol.SeverityWarning, 35380- Source: source.ListError, 35381- Message: fmt.Sprintf(`No packages found for open file %s: %v. 35382-If this file contains build tags, try adding "-tags=<build tag>" to your gopls "buildFlags" configuration (see (https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags-string). 35383-Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md). 35384-`, fh.URI().Filename(), err), 35385- } 35386-} 35387- 35388-// publishDiagnostics collects and publishes any unpublished diagnostic reports. 35389-func (s *Server) publishDiagnostics(ctx context.Context, final bool, snapshot source.Snapshot) { 35390- ctx, done := event.Start(ctx, "Server.publishDiagnostics", source.SnapshotLabels(snapshot)...) 35391- defer done() 35392- 35393- s.diagnosticsMu.Lock() 35394- defer s.diagnosticsMu.Unlock() 35395- 35396- for uri, r := range s.diagnostics { 35397- // Global snapshot IDs are monotonic, so we use them to enforce an ordering 35398- // for diagnostics. 35399- // 35400- // If we've already delivered diagnostics for a future snapshot for this 35401- // file, do not deliver them. See golang/go#42837 for an example of why 35402- // this is necessary. 35403- // 35404- // TODO(rfindley): even using a global snapshot ID, this mechanism is 35405- // potentially racy: elsewhere in the code (e.g. invalidateContent) we 35406- // allow for multiple views track a given file. In this case, we should 35407- // either only report diagnostics for snapshots from the "best" view of a 35408- // URI, or somehow merge diagnostics from multiple views. 35409- if r.publishedSnapshotID > snapshot.GlobalID() { 35410- continue 35411- } 35412- 35413- anyReportsChanged := false 35414- reportHashes := map[diagnosticSource]string{} 35415- var diags []*source.Diagnostic 35416- for dsource, report := range r.reports { 35417- if report.snapshotID != snapshot.GlobalID() { 35418- continue 35419- } 35420- var reportDiags []*source.Diagnostic 35421- for _, d := range report.diags { 35422- diags = append(diags, d) 35423- reportDiags = append(reportDiags, d) 35424- } 35425- hash := hashDiagnostics(reportDiags...) 35426- if hash != report.publishedHash { 35427- anyReportsChanged = true 35428- } 35429- reportHashes[dsource] = hash 35430- } 35431- 35432- if !final && !anyReportsChanged { 35433- // Don't invalidate existing reports on the client if we haven't got any 35434- // new information. 35435- continue 35436- } 35437- 35438- source.SortDiagnostics(diags) 35439- hash := hashDiagnostics(diags...) 35440- if hash == r.publishedHash && !r.mustPublish { 35441- // Update snapshotID to be the latest snapshot for which this diagnostic 35442- // hash is valid. 35443- r.publishedSnapshotID = snapshot.GlobalID() 35444- continue 35445- } 35446- var version int32 35447- if fh := snapshot.FindFile(uri); fh != nil { // file may have been deleted 35448- version = fh.Version() 35449- } 35450- if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{ 35451- Diagnostics: toProtocolDiagnostics(diags), 35452- URI: protocol.URIFromSpanURI(uri), 35453- Version: version, 35454- }); err == nil { 35455- r.publishedHash = hash 35456- r.mustPublish = false // diagnostics have been successfully published 35457- r.publishedSnapshotID = snapshot.GlobalID() 35458- for dsource, hash := range reportHashes { 35459- report := r.reports[dsource] 35460- report.publishedHash = hash 35461- r.reports[dsource] = report 35462- } 35463- } else { 35464- if ctx.Err() != nil { 35465- // Publish may have failed due to a cancelled context. 35466- log.Trace.Log(ctx, "publish cancelled") 35467- return 35468- } 35469- event.Error(ctx, "publishReports: failed to deliver diagnostic", err, tag.URI.Of(uri)) 35470- } 35471- } 35472-} 35473- 35474-func toProtocolDiagnostics(diagnostics []*source.Diagnostic) []protocol.Diagnostic { 35475- reports := []protocol.Diagnostic{} 35476- for _, diag := range diagnostics { 35477- pdiag := protocol.Diagnostic{ 35478- // diag.Message might start with \n or \t 35479- Message: strings.TrimSpace(diag.Message), 35480- Range: diag.Range, 35481- Severity: diag.Severity, 35482- Source: string(diag.Source), 35483- Tags: diag.Tags, 35484- RelatedInformation: diag.Related, 35485- } 35486- if diag.Code != "" { 35487- pdiag.Code = diag.Code 35488- } 35489- if diag.CodeHref != "" { 35490- pdiag.CodeDescription = &protocol.CodeDescription{Href: diag.CodeHref} 35491- } 35492- reports = append(reports, pdiag) 35493- } 35494- return reports 35495-} 35496- 35497-func (s *Server) shouldIgnoreError(ctx context.Context, snapshot source.Snapshot, err error) bool { 35498- if err == nil { // if there is no error at all 35499- return false 35500- } 35501- if errors.Is(err, context.Canceled) { 35502- return true 35503- } 35504- // If the folder has no Go code in it, we shouldn't spam the user with a warning. 35505- var hasGo bool 35506- _ = filepath.Walk(snapshot.View().Folder().Filename(), func(path string, info os.FileInfo, err error) error { 35507- if err != nil { 35508- return err 35509- } 35510- if !strings.HasSuffix(info.Name(), ".go") { 35511- return nil 35512- } 35513- hasGo = true 35514- return errors.New("done") 35515- }) 35516- return !hasGo 35517-} 35518- 35519-// Diagnostics formattedfor the debug server 35520-// (all the relevant fields of Server are private) 35521-// (The alternative is to export them) 35522-func (s *Server) Diagnostics() map[string][]string { 35523- ans := make(map[string][]string) 35524- s.diagnosticsMu.Lock() 35525- defer s.diagnosticsMu.Unlock() 35526- for k, v := range s.diagnostics { 35527- fn := k.Filename() 35528- for typ, d := range v.reports { 35529- if len(d.diags) == 0 { 35530- continue 35531- } 35532- for _, dx := range d.diags { 35533- ans[fn] = append(ans[fn], auxStr(dx, d, typ)) 35534- } 35535- } 35536- } 35537- return ans 35538-} 35539- 35540-func auxStr(v *source.Diagnostic, d diagnosticReport, typ diagnosticSource) string { 35541- // Tags? RelatedInformation? 35542- msg := fmt.Sprintf("(%s)%q(source:%q,code:%q,severity:%s,snapshot:%d,type:%s)", 35543- v.Range, v.Message, v.Source, v.Code, v.Severity, d.snapshotID, typ) 35544- for _, r := range v.Related { 35545- msg += fmt.Sprintf(" [%s:%s,%q]", r.Location.URI.SpanURI().Filename(), r.Location.Range, r.Message) 35546- } 35547- return msg 35548-} 35549diff -urN a/gopls/internal/lsp/fake/client.go b/gopls/internal/lsp/fake/client.go 35550--- a/gopls/internal/lsp/fake/client.go 2000-01-01 00:00:00.000000000 -0000 35551+++ b/gopls/internal/lsp/fake/client.go 1970-01-01 00:00:00.000000000 +0000 35552@@ -1,187 +0,0 @@ 35553-// Copyright 2020 The Go Authors. All rights reserved. 35554-// Use of this source code is governed by a BSD-style 35555-// license that can be found in the LICENSE file. 35556- 35557-package fake 35558- 35559-import ( 35560- "context" 35561- "encoding/json" 35562- "fmt" 35563- 35564- "golang.org/x/tools/gopls/internal/lsp/glob" 35565- "golang.org/x/tools/gopls/internal/lsp/protocol" 35566-) 35567- 35568-// ClientHooks are a set of optional hooks called during handling of 35569-// the corresponding client method (see protocol.Client for the the 35570-// LSP server-to-client RPCs) in order to make test expectations 35571-// awaitable. 35572-type ClientHooks struct { 35573- OnLogMessage func(context.Context, *protocol.LogMessageParams) error 35574- OnDiagnostics func(context.Context, *protocol.PublishDiagnosticsParams) error 35575- OnWorkDoneProgressCreate func(context.Context, *protocol.WorkDoneProgressCreateParams) error 35576- OnProgress func(context.Context, *protocol.ProgressParams) error 35577- OnShowMessage func(context.Context, *protocol.ShowMessageParams) error 35578- OnShowMessageRequest func(context.Context, *protocol.ShowMessageRequestParams) error 35579- OnRegisterCapability func(context.Context, *protocol.RegistrationParams) error 35580- OnUnregisterCapability func(context.Context, *protocol.UnregistrationParams) error 35581- OnApplyEdit func(context.Context, *protocol.ApplyWorkspaceEditParams) error 35582-} 35583- 35584-// Client is an adapter that converts an *Editor into an LSP Client. It mostly 35585-// delegates functionality to hooks that can be configured by tests. 35586-type Client struct { 35587- editor *Editor 35588- hooks ClientHooks 35589- skipApplyEdits bool // don't apply edits from ApplyEdit downcalls to Editor 35590-} 35591- 35592-func (c *Client) CodeLensRefresh(context.Context) error { return nil } 35593- 35594-func (c *Client) InlayHintRefresh(context.Context) error { return nil } 35595- 35596-func (c *Client) DiagnosticRefresh(context.Context) error { return nil } 35597- 35598-func (c *Client) InlineValueRefresh(context.Context) error { return nil } 35599- 35600-func (c *Client) SemanticTokensRefresh(context.Context) error { return nil } 35601- 35602-func (c *Client) LogTrace(context.Context, *protocol.LogTraceParams) error { return nil } 35603- 35604-func (c *Client) ShowMessage(ctx context.Context, params *protocol.ShowMessageParams) error { 35605- if c.hooks.OnShowMessage != nil { 35606- return c.hooks.OnShowMessage(ctx, params) 35607- } 35608- return nil 35609-} 35610- 35611-func (c *Client) ShowMessageRequest(ctx context.Context, params *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error) { 35612- if c.hooks.OnShowMessageRequest != nil { 35613- if err := c.hooks.OnShowMessageRequest(ctx, params); err != nil { 35614- return nil, err 35615- } 35616- } 35617- if len(params.Actions) == 0 || len(params.Actions) > 1 { 35618- return nil, fmt.Errorf("fake editor cannot handle multiple action items") 35619- } 35620- return ¶ms.Actions[0], nil 35621-} 35622- 35623-func (c *Client) LogMessage(ctx context.Context, params *protocol.LogMessageParams) error { 35624- if c.hooks.OnLogMessage != nil { 35625- return c.hooks.OnLogMessage(ctx, params) 35626- } 35627- return nil 35628-} 35629- 35630-func (c *Client) Event(ctx context.Context, event *interface{}) error { 35631- return nil 35632-} 35633- 35634-func (c *Client) PublishDiagnostics(ctx context.Context, params *protocol.PublishDiagnosticsParams) error { 35635- if c.hooks.OnDiagnostics != nil { 35636- return c.hooks.OnDiagnostics(ctx, params) 35637- } 35638- return nil 35639-} 35640- 35641-func (c *Client) WorkspaceFolders(context.Context) ([]protocol.WorkspaceFolder, error) { 35642- return []protocol.WorkspaceFolder{}, nil 35643-} 35644- 35645-func (c *Client) Configuration(_ context.Context, p *protocol.ParamConfiguration) ([]interface{}, error) { 35646- results := make([]interface{}, len(p.Items)) 35647- for i, item := range p.Items { 35648- if item.Section == "gopls" { 35649- c.editor.mu.Lock() 35650- results[i] = c.editor.settingsLocked() 35651- c.editor.mu.Unlock() 35652- } 35653- } 35654- return results, nil 35655-} 35656- 35657-func (c *Client) RegisterCapability(ctx context.Context, params *protocol.RegistrationParams) error { 35658- if c.hooks.OnRegisterCapability != nil { 35659- if err := c.hooks.OnRegisterCapability(ctx, params); err != nil { 35660- return err 35661- } 35662- } 35663- // Update file watching patterns. 35664- // 35665- // TODO(rfindley): We could verify more here, like verify that the 35666- // registration ID is distinct, and that the capability is not currently 35667- // registered. 35668- for _, registration := range params.Registrations { 35669- if registration.Method == "workspace/didChangeWatchedFiles" { 35670- // Marshal and unmarshal to interpret RegisterOptions as 35671- // DidChangeWatchedFilesRegistrationOptions. 35672- raw, err := json.Marshal(registration.RegisterOptions) 35673- if err != nil { 35674- return fmt.Errorf("marshaling registration options: %v", err) 35675- } 35676- var opts protocol.DidChangeWatchedFilesRegistrationOptions 35677- if err := json.Unmarshal(raw, &opts); err != nil { 35678- return fmt.Errorf("unmarshaling registration options: %v", err) 35679- } 35680- var globs []*glob.Glob 35681- for _, watcher := range opts.Watchers { 35682- // TODO(rfindley): honor the watch kind. 35683- g, err := glob.Parse(watcher.GlobPattern) 35684- if err != nil { 35685- return fmt.Errorf("error parsing glob pattern %q: %v", watcher.GlobPattern, err) 35686- } 35687- globs = append(globs, g) 35688- } 35689- c.editor.mu.Lock() 35690- c.editor.watchPatterns = globs 35691- c.editor.mu.Unlock() 35692- } 35693- } 35694- return nil 35695-} 35696- 35697-func (c *Client) UnregisterCapability(ctx context.Context, params *protocol.UnregistrationParams) error { 35698- if c.hooks.OnUnregisterCapability != nil { 35699- return c.hooks.OnUnregisterCapability(ctx, params) 35700- } 35701- return nil 35702-} 35703- 35704-func (c *Client) Progress(ctx context.Context, params *protocol.ProgressParams) error { 35705- if c.hooks.OnProgress != nil { 35706- return c.hooks.OnProgress(ctx, params) 35707- } 35708- return nil 35709-} 35710- 35711-func (c *Client) WorkDoneProgressCreate(ctx context.Context, params *protocol.WorkDoneProgressCreateParams) error { 35712- if c.hooks.OnWorkDoneProgressCreate != nil { 35713- return c.hooks.OnWorkDoneProgressCreate(ctx, params) 35714- } 35715- return nil 35716-} 35717- 35718-func (c *Client) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) { 35719- return nil, nil 35720-} 35721- 35722-func (c *Client) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) { 35723- if len(params.Edit.Changes) != 0 { 35724- return &protocol.ApplyWorkspaceEditResult{FailureReason: "Edit.Changes is unsupported"}, nil 35725- } 35726- if c.hooks.OnApplyEdit != nil { 35727- if err := c.hooks.OnApplyEdit(ctx, params); err != nil { 35728- return nil, err 35729- } 35730- } 35731- if !c.skipApplyEdits { 35732- for _, change := range params.Edit.DocumentChanges { 35733- if err := c.editor.applyDocumentChange(ctx, change); err != nil { 35734- return nil, err 35735- } 35736- } 35737- } 35738- return &protocol.ApplyWorkspaceEditResult{Applied: true}, nil 35739-} 35740diff -urN a/gopls/internal/lsp/fake/doc.go b/gopls/internal/lsp/fake/doc.go 35741--- a/gopls/internal/lsp/fake/doc.go 2000-01-01 00:00:00.000000000 -0000 35742+++ b/gopls/internal/lsp/fake/doc.go 1970-01-01 00:00:00.000000000 +0000 35743@@ -1,19 +0,0 @@ 35744-// Copyright 2020 The Go Authors. All rights reserved. 35745-// Use of this source code is governed by a BSD-style 35746-// license that can be found in the LICENSE file. 35747- 35748-// Package fake provides fake implementations of a text editor, LSP client 35749-// plugin, and Sandbox environment for use in tests. 35750-// 35751-// The Editor type provides a high level API for text editor operations 35752-// (open/modify/save/close a buffer, jump to definition, etc.), and the Client 35753-// type exposes an LSP client for the editor that can be connected to a 35754-// language server. By default, the Editor and Client should be compliant with 35755-// the LSP spec: their intended use is to verify server compliance with the 35756-// spec in a variety of environment. Possible future enhancements of these 35757-// types may allow them to misbehave in configurable ways, but that is not 35758-// their primary use. 35759-// 35760-// The Sandbox type provides a facility for executing tests with a temporary 35761-// directory, module proxy, and GOPATH. 35762-package fake 35763diff -urN a/gopls/internal/lsp/fake/edit.go b/gopls/internal/lsp/fake/edit.go 35764--- a/gopls/internal/lsp/fake/edit.go 2000-01-01 00:00:00.000000000 -0000 35765+++ b/gopls/internal/lsp/fake/edit.go 1970-01-01 00:00:00.000000000 +0000 35766@@ -1,51 +0,0 @@ 35767-// Copyright 2020 The Go Authors. All rights reserved. 35768-// Use of this source code is governed by a BSD-style 35769-// license that can be found in the LICENSE file. 35770- 35771-package fake 35772- 35773-import ( 35774- "golang.org/x/tools/gopls/internal/lsp/protocol" 35775- "golang.org/x/tools/gopls/internal/lsp/source" 35776- "golang.org/x/tools/internal/diff" 35777-) 35778- 35779-// NewEdit creates an edit replacing all content between the 0-based 35780-// (startLine, startColumn) and (endLine, endColumn) with text. 35781-// 35782-// Columns measure UTF-16 codes. 35783-func NewEdit(startLine, startColumn, endLine, endColumn uint32, text string) protocol.TextEdit { 35784- return protocol.TextEdit{ 35785- Range: protocol.Range{ 35786- Start: protocol.Position{Line: startLine, Character: startColumn}, 35787- End: protocol.Position{Line: endLine, Character: endColumn}, 35788- }, 35789- NewText: text, 35790- } 35791-} 35792- 35793-func EditToChangeEvent(e protocol.TextEdit) protocol.TextDocumentContentChangeEvent { 35794- var rng protocol.Range = e.Range 35795- return protocol.TextDocumentContentChangeEvent{ 35796- Range: &rng, 35797- Text: e.NewText, 35798- } 35799-} 35800- 35801-// applyEdits applies the edits to a file with the specified lines, 35802-// and returns a new slice containing the lines of the patched file. 35803-// It is a wrapper around diff.Apply; see that function for preconditions. 35804-func applyEdits(mapper *protocol.Mapper, edits []protocol.TextEdit, windowsLineEndings bool) ([]byte, error) { 35805- diffEdits, err := source.FromProtocolEdits(mapper, edits) 35806- if err != nil { 35807- return nil, err 35808- } 35809- patched, err := diff.ApplyBytes(mapper.Content, diffEdits) 35810- if err != nil { 35811- return nil, err 35812- } 35813- if windowsLineEndings { 35814- patched = toWindowsLineEndings(patched) 35815- } 35816- return patched, nil 35817-} 35818diff -urN a/gopls/internal/lsp/fake/editor.go b/gopls/internal/lsp/fake/editor.go 35819--- a/gopls/internal/lsp/fake/editor.go 2000-01-01 00:00:00.000000000 -0000 35820+++ b/gopls/internal/lsp/fake/editor.go 1970-01-01 00:00:00.000000000 +0000 35821@@ -1,1464 +0,0 @@ 35822-// Copyright 2020 The Go Authors. All rights reserved. 35823-// Use of this source code is governed by a BSD-style 35824-// license that can be found in the LICENSE file. 35825- 35826-package fake 35827- 35828-import ( 35829- "bytes" 35830- "context" 35831- "errors" 35832- "fmt" 35833- "os" 35834- "path" 35835- "path/filepath" 35836- "regexp" 35837- "strings" 35838- "sync" 35839- 35840- "golang.org/x/tools/gopls/internal/lsp/command" 35841- "golang.org/x/tools/gopls/internal/lsp/glob" 35842- "golang.org/x/tools/gopls/internal/lsp/protocol" 35843- "golang.org/x/tools/gopls/internal/lsp/source" 35844- "golang.org/x/tools/gopls/internal/span" 35845- "golang.org/x/tools/internal/jsonrpc2" 35846- "golang.org/x/tools/internal/jsonrpc2/servertest" 35847- "golang.org/x/tools/internal/xcontext" 35848-) 35849- 35850-// Editor is a fake editor client. It keeps track of client state and can be 35851-// used for writing LSP tests. 35852-type Editor struct { 35853- 35854- // Server, client, and sandbox are concurrency safe and written only 35855- // at construction time, so do not require synchronization. 35856- Server protocol.Server 35857- cancelConn func() 35858- serverConn jsonrpc2.Conn 35859- client *Client 35860- sandbox *Sandbox 35861- defaultEnv map[string]string 35862- 35863- // TODO(adonovan): buffers should be keyed by protocol.DocumentURI. 35864- mu sync.Mutex 35865- config EditorConfig // editor configuration 35866- buffers map[string]buffer // open buffers (relative path -> buffer content) 35867- serverCapabilities protocol.ServerCapabilities // capabilities / options 35868- watchPatterns []*glob.Glob // glob patterns to watch 35869- 35870- // Call metrics for the purpose of expectations. This is done in an ad-hoc 35871- // manner for now. Perhaps in the future we should do something more 35872- // systematic. Guarded with a separate mutex as calls may need to be accessed 35873- // asynchronously via callbacks into the Editor. 35874- callsMu sync.Mutex 35875- calls CallCounts 35876-} 35877- 35878-// CallCounts tracks the number of protocol notifications of different types. 35879-type CallCounts struct { 35880- DidOpen, DidChange, DidSave, DidChangeWatchedFiles, DidClose uint64 35881-} 35882- 35883-// buffer holds information about an open buffer in the editor. 35884-type buffer struct { 35885- version int // monotonic version; incremented on edits 35886- path string // relative path in the workspace 35887- mapper *protocol.Mapper // buffer content 35888- dirty bool // if true, content is unsaved (TODO(rfindley): rename this field) 35889-} 35890- 35891-func (b buffer) text() string { 35892- return string(b.mapper.Content) 35893-} 35894- 35895-// EditorConfig configures the editor's LSP session. This is similar to 35896-// source.UserOptions, but we use a separate type here so that we expose only 35897-// that configuration which we support. 35898-// 35899-// The zero value for EditorConfig should correspond to its defaults. 35900-type EditorConfig struct { 35901- // Env holds environment variables to apply on top of the default editor 35902- // environment. When applying these variables, the special string 35903- // $SANDBOX_WORKDIR is replaced by the absolute path to the sandbox working 35904- // directory. 35905- Env map[string]string 35906- 35907- // WorkspaceFolders is the workspace folders to configure on the LSP server, 35908- // relative to the sandbox workdir. 35909- // 35910- // As a special case, if WorkspaceFolders is nil the editor defaults to 35911- // configuring a single workspace folder corresponding to the workdir root. 35912- // To explicitly send no workspace folders, use an empty (non-nil) slice. 35913- WorkspaceFolders []string 35914- 35915- // Whether to edit files with windows line endings. 35916- WindowsLineEndings bool 35917- 35918- // Map of language ID -> regexp to match, used to set the file type of new 35919- // buffers. Applied as an overlay on top of the following defaults: 35920- // "go" -> ".*\.go" 35921- // "go.mod" -> "go\.mod" 35922- // "go.sum" -> "go\.sum" 35923- // "gotmpl" -> ".*tmpl" 35924- FileAssociations map[string]string 35925- 35926- // Settings holds user-provided configuration for the LSP server. 35927- Settings map[string]interface{} 35928-} 35929- 35930-// NewEditor creates a new Editor. 35931-func NewEditor(sandbox *Sandbox, config EditorConfig) *Editor { 35932- return &Editor{ 35933- buffers: make(map[string]buffer), 35934- sandbox: sandbox, 35935- defaultEnv: sandbox.GoEnv(), 35936- config: config, 35937- } 35938-} 35939- 35940-// Connect configures the editor to communicate with an LSP server on conn. It 35941-// is not concurrency safe, and should be called at most once, before using the 35942-// editor. 35943-// 35944-// It returns the editor, so that it may be called as follows: 35945-// 35946-// editor, err := NewEditor(s).Connect(ctx, conn, hooks) 35947-func (e *Editor) Connect(ctx context.Context, connector servertest.Connector, hooks ClientHooks, skipApplyEdits bool) (*Editor, error) { 35948- bgCtx, cancelConn := context.WithCancel(xcontext.Detach(ctx)) 35949- conn := connector.Connect(bgCtx) 35950- e.cancelConn = cancelConn 35951- 35952- e.serverConn = conn 35953- e.Server = protocol.ServerDispatcher(conn) 35954- e.client = &Client{editor: e, hooks: hooks, skipApplyEdits: skipApplyEdits} 35955- conn.Go(bgCtx, 35956- protocol.Handlers( 35957- protocol.ClientHandler(e.client, 35958- jsonrpc2.MethodNotFound))) 35959- 35960- if err := e.initialize(ctx); err != nil { 35961- return nil, err 35962- } 35963- e.sandbox.Workdir.AddWatcher(e.onFileChanges) 35964- return e, nil 35965-} 35966- 35967-func (e *Editor) Stats() CallCounts { 35968- e.callsMu.Lock() 35969- defer e.callsMu.Unlock() 35970- return e.calls 35971-} 35972- 35973-// Shutdown issues the 'shutdown' LSP notification. 35974-func (e *Editor) Shutdown(ctx context.Context) error { 35975- if e.Server != nil { 35976- if err := e.Server.Shutdown(ctx); err != nil { 35977- return fmt.Errorf("Shutdown: %w", err) 35978- } 35979- } 35980- return nil 35981-} 35982- 35983-// Exit issues the 'exit' LSP notification. 35984-func (e *Editor) Exit(ctx context.Context) error { 35985- if e.Server != nil { 35986- // Not all LSP clients issue the exit RPC, but we do so here to ensure that 35987- // we gracefully handle it on multi-session servers. 35988- if err := e.Server.Exit(ctx); err != nil { 35989- return fmt.Errorf("Exit: %w", err) 35990- } 35991- } 35992- return nil 35993-} 35994- 35995-// Close issues the shutdown and exit sequence an editor should. 35996-func (e *Editor) Close(ctx context.Context) error { 35997- if err := e.Shutdown(ctx); err != nil { 35998- return err 35999- } 36000- if err := e.Exit(ctx); err != nil { 36001- return err 36002- } 36003- defer func() { 36004- e.cancelConn() 36005- }() 36006- 36007- // called close on the editor should result in the connection closing 36008- select { 36009- case <-e.serverConn.Done(): 36010- // connection closed itself 36011- return nil 36012- case <-ctx.Done(): 36013- return fmt.Errorf("connection not closed: %w", ctx.Err()) 36014- } 36015-} 36016- 36017-// Client returns the LSP client for this editor. 36018-func (e *Editor) Client() *Client { 36019- return e.client 36020-} 36021- 36022-// settingsLocked builds the settings map for use in LSP settings RPCs. 36023-// 36024-// e.mu must be held while calling this function. 36025-func (e *Editor) settingsLocked() map[string]interface{} { 36026- env := make(map[string]string) 36027- for k, v := range e.defaultEnv { 36028- env[k] = v 36029- } 36030- for k, v := range e.config.Env { 36031- env[k] = v 36032- } 36033- for k, v := range env { 36034- v = strings.ReplaceAll(v, "$SANDBOX_WORKDIR", e.sandbox.Workdir.RootURI().SpanURI().Filename()) 36035- env[k] = v 36036- } 36037- 36038- settings := map[string]interface{}{ 36039- "env": env, 36040- 36041- // Use verbose progress reporting so that regtests can assert on 36042- // asynchronous operations being completed (such as diagnosing a snapshot). 36043- "verboseWorkDoneProgress": true, 36044- 36045- // Set a generous completion budget, so that tests don't flake because 36046- // completions are too slow. 36047- "completionBudget": "10s", 36048- 36049- // Shorten the diagnostic delay to speed up test execution (else we'd add 36050- // the default delay to each assertion about diagnostics) 36051- "diagnosticsDelay": "10ms", 36052- } 36053- 36054- for k, v := range e.config.Settings { 36055- if k == "env" { 36056- panic("must not provide env via the EditorConfig.Settings field: use the EditorConfig.Env field instead") 36057- } 36058- settings[k] = v 36059- } 36060- 36061- return settings 36062-} 36063- 36064-func (e *Editor) initialize(ctx context.Context) error { 36065- params := &protocol.ParamInitialize{} 36066- params.ClientInfo = &protocol.Msg_XInitializeParams_clientInfo{} 36067- params.ClientInfo.Name = "fakeclient" 36068- params.ClientInfo.Version = "v1.0.0" 36069- e.mu.Lock() 36070- params.WorkspaceFolders = e.makeWorkspaceFoldersLocked() 36071- params.InitializationOptions = e.settingsLocked() 36072- e.mu.Unlock() 36073- params.Capabilities.Workspace.Configuration = true 36074- params.Capabilities.Window.WorkDoneProgress = true 36075- 36076- // TODO: set client capabilities 36077- params.Capabilities.TextDocument.Completion.CompletionItem.TagSupport.ValueSet = []protocol.CompletionItemTag{protocol.ComplDeprecated} 36078- 36079- params.Capabilities.TextDocument.Completion.CompletionItem.SnippetSupport = true 36080- params.Capabilities.TextDocument.SemanticTokens.Requests.Full.Value = true 36081- // copied from lsp/semantic.go to avoid import cycle in tests 36082- params.Capabilities.TextDocument.SemanticTokens.TokenTypes = []string{ 36083- "namespace", "type", "class", "enum", "interface", 36084- "struct", "typeParameter", "parameter", "variable", "property", "enumMember", 36085- "event", "function", "method", "macro", "keyword", "modifier", "comment", 36086- "string", "number", "regexp", "operator", 36087- } 36088- params.Capabilities.TextDocument.SemanticTokens.TokenModifiers = []string{ 36089- "declaration", "definition", "readonly", "static", 36090- "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary", 36091- } 36092- 36093- // This is a bit of a hack, since the fake editor doesn't actually support 36094- // watching changed files that match a specific glob pattern. However, the 36095- // editor does send didChangeWatchedFiles notifications, so set this to 36096- // true. 36097- params.Capabilities.Workspace.DidChangeWatchedFiles.DynamicRegistration = true 36098- params.Capabilities.Workspace.WorkspaceEdit = &protocol.WorkspaceEditClientCapabilities{ 36099- ResourceOperations: []protocol.ResourceOperationKind{ 36100- "rename", 36101- }, 36102- } 36103- 36104- trace := protocol.TraceValues("messages") 36105- params.Trace = &trace 36106- // TODO: support workspace folders. 36107- if e.Server != nil { 36108- resp, err := e.Server.Initialize(ctx, params) 36109- if err != nil { 36110- return fmt.Errorf("initialize: %w", err) 36111- } 36112- e.mu.Lock() 36113- e.serverCapabilities = resp.Capabilities 36114- e.mu.Unlock() 36115- 36116- if err := e.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil { 36117- return fmt.Errorf("initialized: %w", err) 36118- } 36119- } 36120- // TODO: await initial configuration here, or expect gopls to manage that? 36121- return nil 36122-} 36123- 36124-// makeWorkspaceFoldersLocked creates a slice of workspace folders to use for 36125-// this editing session, based on the editor configuration. 36126-// 36127-// e.mu must be held while calling this function. 36128-func (e *Editor) makeWorkspaceFoldersLocked() (folders []protocol.WorkspaceFolder) { 36129- paths := e.config.WorkspaceFolders 36130- if len(paths) == 0 { 36131- paths = append(paths, string(e.sandbox.Workdir.RelativeTo)) 36132- } 36133- 36134- for _, path := range paths { 36135- uri := string(e.sandbox.Workdir.URI(path)) 36136- folders = append(folders, protocol.WorkspaceFolder{ 36137- URI: uri, 36138- Name: filepath.Base(uri), 36139- }) 36140- } 36141- 36142- return folders 36143-} 36144- 36145-// onFileChanges is registered to be called by the Workdir on any writes that 36146-// go through the Workdir API. It is called synchronously by the Workdir. 36147-func (e *Editor) onFileChanges(ctx context.Context, evts []protocol.FileEvent) { 36148- if e.Server == nil { 36149- return 36150- } 36151- 36152- // e may be locked when onFileChanges is called, but it is important that we 36153- // synchronously increment this counter so that we can subsequently assert on 36154- // the number of expected DidChangeWatchedFiles calls. 36155- e.callsMu.Lock() 36156- e.calls.DidChangeWatchedFiles++ 36157- e.callsMu.Unlock() 36158- 36159- // Since e may be locked, we must run this mutation asynchronously. 36160- go func() { 36161- e.mu.Lock() 36162- defer e.mu.Unlock() 36163- for _, evt := range evts { 36164- // Always send an on-disk change, even for events that seem useless 36165- // because they're shadowed by an open buffer. 36166- path := e.sandbox.Workdir.URIToPath(evt.URI) 36167- if buf, ok := e.buffers[path]; ok { 36168- // Following VS Code, don't honor deletions or changes to dirty buffers. 36169- if buf.dirty || evt.Type == protocol.Deleted { 36170- continue 36171- } 36172- 36173- content, err := e.sandbox.Workdir.ReadFile(path) 36174- if err != nil { 36175- continue // A race with some other operation. 36176- } 36177- // No need to update if the buffer content hasn't changed. 36178- if string(content) == buf.text() { 36179- continue 36180- } 36181- // During shutdown, this call will fail. Ignore the error. 36182- _ = e.setBufferContentLocked(ctx, path, false, content, nil) 36183- } 36184- } 36185- var matchedEvts []protocol.FileEvent 36186- for _, evt := range evts { 36187- filename := filepath.ToSlash(evt.URI.SpanURI().Filename()) 36188- for _, g := range e.watchPatterns { 36189- if g.Match(filename) { 36190- matchedEvts = append(matchedEvts, evt) 36191- break 36192- } 36193- } 36194- } 36195- 36196- // TODO(rfindley): don't send notifications while locked. 36197- e.Server.DidChangeWatchedFiles(ctx, &protocol.DidChangeWatchedFilesParams{ 36198- Changes: matchedEvts, 36199- }) 36200- }() 36201-} 36202- 36203-// OpenFile creates a buffer for the given workdir-relative file. 36204-// 36205-// If the file is already open, it is a no-op. 36206-func (e *Editor) OpenFile(ctx context.Context, path string) error { 36207- if e.HasBuffer(path) { 36208- return nil 36209- } 36210- content, err := e.sandbox.Workdir.ReadFile(path) 36211- if err != nil { 36212- return err 36213- } 36214- if e.Config().WindowsLineEndings { 36215- content = toWindowsLineEndings(content) 36216- } 36217- return e.createBuffer(ctx, path, false, content) 36218-} 36219- 36220-// toWindowsLineEndings checks whether content has windows line endings. 36221-// 36222-// If so, it returns content unmodified. If not, it returns a new byte slice modified to use CRLF line endings. 36223-func toWindowsLineEndings(content []byte) []byte { 36224- abnormal := false 36225- for i, b := range content { 36226- if b == '\n' && (i == 0 || content[i-1] != '\r') { 36227- abnormal = true 36228- break 36229- } 36230- } 36231- if !abnormal { 36232- return content 36233- } 36234- var buf bytes.Buffer 36235- for i, b := range content { 36236- if b == '\n' && (i == 0 || content[i-1] != '\r') { 36237- buf.WriteByte('\r') 36238- } 36239- buf.WriteByte(b) 36240- } 36241- return buf.Bytes() 36242-} 36243- 36244-// CreateBuffer creates a new unsaved buffer corresponding to the workdir path, 36245-// containing the given textual content. 36246-func (e *Editor) CreateBuffer(ctx context.Context, path, content string) error { 36247- return e.createBuffer(ctx, path, true, []byte(content)) 36248-} 36249- 36250-func (e *Editor) createBuffer(ctx context.Context, path string, dirty bool, content []byte) error { 36251- e.mu.Lock() 36252- 36253- if _, ok := e.buffers[path]; ok { 36254- e.mu.Unlock() 36255- return fmt.Errorf("buffer %q already exists", path) 36256- } 36257- 36258- uri := e.sandbox.Workdir.URI(path).SpanURI() 36259- buf := buffer{ 36260- version: 1, 36261- path: path, 36262- mapper: protocol.NewMapper(uri, content), 36263- dirty: dirty, 36264- } 36265- e.buffers[path] = buf 36266- 36267- item := e.textDocumentItem(buf) 36268- e.mu.Unlock() 36269- 36270- return e.sendDidOpen(ctx, item) 36271-} 36272- 36273-// textDocumentItem builds a protocol.TextDocumentItem for the given buffer. 36274-// 36275-// Precondition: e.mu must be held. 36276-func (e *Editor) textDocumentItem(buf buffer) protocol.TextDocumentItem { 36277- return protocol.TextDocumentItem{ 36278- URI: e.sandbox.Workdir.URI(buf.path), 36279- LanguageID: languageID(buf.path, e.config.FileAssociations), 36280- Version: int32(buf.version), 36281- Text: buf.text(), 36282- } 36283-} 36284- 36285-func (e *Editor) sendDidOpen(ctx context.Context, item protocol.TextDocumentItem) error { 36286- if e.Server != nil { 36287- if err := e.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ 36288- TextDocument: item, 36289- }); err != nil { 36290- return fmt.Errorf("DidOpen: %w", err) 36291- } 36292- e.callsMu.Lock() 36293- e.calls.DidOpen++ 36294- e.callsMu.Unlock() 36295- } 36296- return nil 36297-} 36298- 36299-var defaultFileAssociations = map[string]*regexp.Regexp{ 36300- "go": regexp.MustCompile(`^.*\.go$`), // '$' is important: don't match .gotmpl! 36301- "go.mod": regexp.MustCompile(`^go\.mod$`), 36302- "go.sum": regexp.MustCompile(`^go(\.work)?\.sum$`), 36303- "go.work": regexp.MustCompile(`^go\.work$`), 36304- "gotmpl": regexp.MustCompile(`^.*tmpl$`), 36305-} 36306- 36307-// languageID returns the language identifier for the path p given the user 36308-// configured fileAssociations. 36309-func languageID(p string, fileAssociations map[string]string) string { 36310- base := path.Base(p) 36311- for lang, re := range fileAssociations { 36312- re := regexp.MustCompile(re) 36313- if re.MatchString(base) { 36314- return lang 36315- } 36316- } 36317- for lang, re := range defaultFileAssociations { 36318- if re.MatchString(base) { 36319- return lang 36320- } 36321- } 36322- return "" 36323-} 36324- 36325-// CloseBuffer removes the current buffer (regardless of whether it is saved). 36326-func (e *Editor) CloseBuffer(ctx context.Context, path string) error { 36327- e.mu.Lock() 36328- _, ok := e.buffers[path] 36329- if !ok { 36330- e.mu.Unlock() 36331- return ErrUnknownBuffer 36332- } 36333- delete(e.buffers, path) 36334- e.mu.Unlock() 36335- 36336- return e.sendDidClose(ctx, e.TextDocumentIdentifier(path)) 36337-} 36338- 36339-func (e *Editor) sendDidClose(ctx context.Context, doc protocol.TextDocumentIdentifier) error { 36340- if e.Server != nil { 36341- if err := e.Server.DidClose(ctx, &protocol.DidCloseTextDocumentParams{ 36342- TextDocument: doc, 36343- }); err != nil { 36344- return fmt.Errorf("DidClose: %w", err) 36345- } 36346- e.callsMu.Lock() 36347- e.calls.DidClose++ 36348- e.callsMu.Unlock() 36349- } 36350- return nil 36351-} 36352- 36353-func (e *Editor) TextDocumentIdentifier(path string) protocol.TextDocumentIdentifier { 36354- return protocol.TextDocumentIdentifier{ 36355- URI: e.sandbox.Workdir.URI(path), 36356- } 36357-} 36358- 36359-// SaveBuffer writes the content of the buffer specified by the given path to 36360-// the filesystem. 36361-func (e *Editor) SaveBuffer(ctx context.Context, path string) error { 36362- if err := e.OrganizeImports(ctx, path); err != nil { 36363- return fmt.Errorf("organizing imports before save: %w", err) 36364- } 36365- if err := e.FormatBuffer(ctx, path); err != nil { 36366- return fmt.Errorf("formatting before save: %w", err) 36367- } 36368- return e.SaveBufferWithoutActions(ctx, path) 36369-} 36370- 36371-func (e *Editor) SaveBufferWithoutActions(ctx context.Context, path string) error { 36372- e.mu.Lock() 36373- defer e.mu.Unlock() 36374- buf, ok := e.buffers[path] 36375- if !ok { 36376- return fmt.Errorf(fmt.Sprintf("unknown buffer: %q", path)) 36377- } 36378- content := buf.text() 36379- includeText := false 36380- syncOptions, ok := e.serverCapabilities.TextDocumentSync.(protocol.TextDocumentSyncOptions) 36381- if ok { 36382- includeText = syncOptions.Save.IncludeText 36383- } 36384- 36385- docID := e.TextDocumentIdentifier(buf.path) 36386- if e.Server != nil { 36387- if err := e.Server.WillSave(ctx, &protocol.WillSaveTextDocumentParams{ 36388- TextDocument: docID, 36389- Reason: protocol.Manual, 36390- }); err != nil { 36391- return fmt.Errorf("WillSave: %w", err) 36392- } 36393- } 36394- if err := e.sandbox.Workdir.WriteFile(ctx, path, content); err != nil { 36395- return fmt.Errorf("writing %q: %w", path, err) 36396- } 36397- 36398- buf.dirty = false 36399- e.buffers[path] = buf 36400- 36401- if e.Server != nil { 36402- params := &protocol.DidSaveTextDocumentParams{ 36403- TextDocument: docID, 36404- } 36405- if includeText { 36406- params.Text = &content 36407- } 36408- if err := e.Server.DidSave(ctx, params); err != nil { 36409- return fmt.Errorf("DidSave: %w", err) 36410- } 36411- e.callsMu.Lock() 36412- e.calls.DidSave++ 36413- e.callsMu.Unlock() 36414- } 36415- return nil 36416-} 36417- 36418-// ErrNoMatch is returned if a regexp search fails. 36419-var ( 36420- ErrNoMatch = errors.New("no match") 36421- ErrUnknownBuffer = errors.New("unknown buffer") 36422-) 36423- 36424-// regexpLocation returns the location of the first occurrence of either re 36425-// or its singular subgroup. It returns ErrNoMatch if the regexp doesn't match. 36426-func regexpLocation(mapper *protocol.Mapper, re string) (protocol.Location, error) { 36427- var start, end int 36428- rec, err := regexp.Compile(re) 36429- if err != nil { 36430- return protocol.Location{}, err 36431- } 36432- indexes := rec.FindSubmatchIndex(mapper.Content) 36433- if indexes == nil { 36434- return protocol.Location{}, ErrNoMatch 36435- } 36436- switch len(indexes) { 36437- case 2: 36438- // no subgroups: return the range of the regexp expression 36439- start, end = indexes[0], indexes[1] 36440- case 4: 36441- // one subgroup: return its range 36442- start, end = indexes[2], indexes[3] 36443- default: 36444- return protocol.Location{}, fmt.Errorf("invalid search regexp %q: expect either 0 or 1 subgroups, got %d", re, len(indexes)/2-1) 36445- } 36446- return mapper.OffsetLocation(start, end) 36447-} 36448- 36449-// RegexpSearch returns the Location of the first match for re in the buffer 36450-// bufName. For convenience, RegexpSearch supports the following two modes: 36451-// 1. If re has no subgroups, return the position of the match for re itself. 36452-// 2. If re has one subgroup, return the position of the first subgroup. 36453-// 36454-// It returns an error re is invalid, has more than one subgroup, or doesn't 36455-// match the buffer. 36456-func (e *Editor) RegexpSearch(bufName, re string) (protocol.Location, error) { 36457- e.mu.Lock() 36458- buf, ok := e.buffers[bufName] 36459- e.mu.Unlock() 36460- if !ok { 36461- return protocol.Location{}, ErrUnknownBuffer 36462- } 36463- return regexpLocation(buf.mapper, re) 36464-} 36465- 36466-// RegexpReplace edits the buffer corresponding to path by replacing the first 36467-// instance of re, or its first subgroup, with the replace text. See 36468-// RegexpSearch for more explanation of these two modes. 36469-// It returns an error if re is invalid, has more than one subgroup, or doesn't 36470-// match the buffer. 36471-func (e *Editor) RegexpReplace(ctx context.Context, path, re, replace string) error { 36472- e.mu.Lock() 36473- defer e.mu.Unlock() 36474- buf, ok := e.buffers[path] 36475- if !ok { 36476- return ErrUnknownBuffer 36477- } 36478- loc, err := regexpLocation(buf.mapper, re) 36479- if err != nil { 36480- return err 36481- } 36482- edits := []protocol.TextEdit{{ 36483- Range: loc.Range, 36484- NewText: replace, 36485- }} 36486- patched, err := applyEdits(buf.mapper, edits, e.config.WindowsLineEndings) 36487- if err != nil { 36488- return fmt.Errorf("editing %q: %v", path, err) 36489- } 36490- return e.setBufferContentLocked(ctx, path, true, patched, edits) 36491-} 36492- 36493-// EditBuffer applies the given test edits to the buffer identified by path. 36494-func (e *Editor) EditBuffer(ctx context.Context, path string, edits []protocol.TextEdit) error { 36495- e.mu.Lock() 36496- defer e.mu.Unlock() 36497- return e.editBufferLocked(ctx, path, edits) 36498-} 36499- 36500-func (e *Editor) SetBufferContent(ctx context.Context, path, content string) error { 36501- e.mu.Lock() 36502- defer e.mu.Unlock() 36503- return e.setBufferContentLocked(ctx, path, true, []byte(content), nil) 36504-} 36505- 36506-// HasBuffer reports whether the file name is open in the editor. 36507-func (e *Editor) HasBuffer(name string) bool { 36508- e.mu.Lock() 36509- defer e.mu.Unlock() 36510- _, ok := e.buffers[name] 36511- return ok 36512-} 36513- 36514-// BufferText returns the content of the buffer with the given name, or "" if 36515-// the file at that path is not open. The second return value reports whether 36516-// the file is open. 36517-func (e *Editor) BufferText(name string) (string, bool) { 36518- e.mu.Lock() 36519- defer e.mu.Unlock() 36520- buf, ok := e.buffers[name] 36521- if !ok { 36522- return "", false 36523- } 36524- return buf.text(), true 36525-} 36526- 36527-// Mapper returns the protocol.Mapper for the given buffer name, if it is open. 36528-func (e *Editor) Mapper(name string) (*protocol.Mapper, error) { 36529- e.mu.Lock() 36530- defer e.mu.Unlock() 36531- buf, ok := e.buffers[name] 36532- if !ok { 36533- return nil, fmt.Errorf("no mapper for %q", name) 36534- } 36535- return buf.mapper, nil 36536-} 36537- 36538-// BufferVersion returns the current version of the buffer corresponding to 36539-// name (or 0 if it is not being edited). 36540-func (e *Editor) BufferVersion(name string) int { 36541- e.mu.Lock() 36542- defer e.mu.Unlock() 36543- return e.buffers[name].version 36544-} 36545- 36546-func (e *Editor) editBufferLocked(ctx context.Context, path string, edits []protocol.TextEdit) error { 36547- buf, ok := e.buffers[path] 36548- if !ok { 36549- return fmt.Errorf("unknown buffer %q", path) 36550- } 36551- content, err := applyEdits(buf.mapper, edits, e.config.WindowsLineEndings) 36552- if err != nil { 36553- return fmt.Errorf("editing %q: %v; edits:\n%v", path, err, edits) 36554- } 36555- return e.setBufferContentLocked(ctx, path, true, content, edits) 36556-} 36557- 36558-func (e *Editor) setBufferContentLocked(ctx context.Context, path string, dirty bool, content []byte, fromEdits []protocol.TextEdit) error { 36559- buf, ok := e.buffers[path] 36560- if !ok { 36561- return fmt.Errorf("unknown buffer %q", path) 36562- } 36563- buf.mapper = protocol.NewMapper(buf.mapper.URI, content) 36564- buf.version++ 36565- buf.dirty = dirty 36566- e.buffers[path] = buf 36567- // A simple heuristic: if there is only one edit, send it incrementally. 36568- // Otherwise, send the entire content. 36569- var evts []protocol.TextDocumentContentChangeEvent 36570- if len(fromEdits) == 1 { 36571- evts = append(evts, EditToChangeEvent(fromEdits[0])) 36572- } else { 36573- evts = append(evts, protocol.TextDocumentContentChangeEvent{ 36574- Text: buf.text(), 36575- }) 36576- } 36577- params := &protocol.DidChangeTextDocumentParams{ 36578- TextDocument: protocol.VersionedTextDocumentIdentifier{ 36579- Version: int32(buf.version), 36580- TextDocumentIdentifier: e.TextDocumentIdentifier(buf.path), 36581- }, 36582- ContentChanges: evts, 36583- } 36584- if e.Server != nil { 36585- if err := e.Server.DidChange(ctx, params); err != nil { 36586- return fmt.Errorf("DidChange: %w", err) 36587- } 36588- e.callsMu.Lock() 36589- e.calls.DidChange++ 36590- e.callsMu.Unlock() 36591- } 36592- return nil 36593-} 36594- 36595-// GoToDefinition jumps to the definition of the symbol at the given position 36596-// in an open buffer. It returns the location of the resulting jump. 36597-// 36598-// TODO(rfindley): rename to "Definition", to be consistent with LSP 36599-// terminology. 36600-func (e *Editor) GoToDefinition(ctx context.Context, loc protocol.Location) (protocol.Location, error) { 36601- if err := e.checkBufferLocation(loc); err != nil { 36602- return protocol.Location{}, err 36603- } 36604- params := &protocol.DefinitionParams{} 36605- params.TextDocument.URI = loc.URI 36606- params.Position = loc.Range.Start 36607- 36608- resp, err := e.Server.Definition(ctx, params) 36609- if err != nil { 36610- return protocol.Location{}, fmt.Errorf("definition: %w", err) 36611- } 36612- return e.extractFirstLocation(ctx, resp) 36613-} 36614- 36615-// GoToTypeDefinition jumps to the type definition of the symbol at the given location 36616-// in an open buffer. 36617-func (e *Editor) GoToTypeDefinition(ctx context.Context, loc protocol.Location) (protocol.Location, error) { 36618- if err := e.checkBufferLocation(loc); err != nil { 36619- return protocol.Location{}, err 36620- } 36621- params := &protocol.TypeDefinitionParams{} 36622- params.TextDocument.URI = loc.URI 36623- params.Position = loc.Range.Start 36624- 36625- resp, err := e.Server.TypeDefinition(ctx, params) 36626- if err != nil { 36627- return protocol.Location{}, fmt.Errorf("type definition: %w", err) 36628- } 36629- return e.extractFirstLocation(ctx, resp) 36630-} 36631- 36632-// extractFirstLocation returns the first location. 36633-// It opens the file if needed. 36634-func (e *Editor) extractFirstLocation(ctx context.Context, locs []protocol.Location) (protocol.Location, error) { 36635- if len(locs) == 0 { 36636- return protocol.Location{}, nil 36637- } 36638- 36639- newPath := e.sandbox.Workdir.URIToPath(locs[0].URI) 36640- if !e.HasBuffer(newPath) { 36641- if err := e.OpenFile(ctx, newPath); err != nil { 36642- return protocol.Location{}, fmt.Errorf("OpenFile: %w", err) 36643- } 36644- } 36645- return locs[0], nil 36646-} 36647- 36648-// Symbol performs a workspace symbol search using query 36649-func (e *Editor) Symbol(ctx context.Context, query string) ([]protocol.SymbolInformation, error) { 36650- params := &protocol.WorkspaceSymbolParams{Query: query} 36651- return e.Server.Symbol(ctx, params) 36652-} 36653- 36654-// OrganizeImports requests and performs the source.organizeImports codeAction. 36655-func (e *Editor) OrganizeImports(ctx context.Context, path string) error { 36656- loc := protocol.Location{URI: e.sandbox.Workdir.URI(path)} // zero Range => whole file 36657- _, err := e.applyCodeActions(ctx, loc, nil, protocol.SourceOrganizeImports) 36658- return err 36659-} 36660- 36661-// RefactorRewrite requests and performs the source.refactorRewrite codeAction. 36662-func (e *Editor) RefactorRewrite(ctx context.Context, loc protocol.Location) error { 36663- applied, err := e.applyCodeActions(ctx, loc, nil, protocol.RefactorRewrite) 36664- if err != nil { 36665- return err 36666- } 36667- if applied == 0 { 36668- return fmt.Errorf("no refactorings were applied") 36669- } 36670- return nil 36671-} 36672- 36673-// ApplyQuickFixes requests and performs the quickfix codeAction. 36674-func (e *Editor) ApplyQuickFixes(ctx context.Context, loc protocol.Location, diagnostics []protocol.Diagnostic) error { 36675- applied, err := e.applyCodeActions(ctx, loc, diagnostics, protocol.SourceFixAll, protocol.QuickFix) 36676- if applied == 0 { 36677- return fmt.Errorf("no quick fixes were applied") 36678- } 36679- return err 36680-} 36681- 36682-// ApplyCodeAction applies the given code action. 36683-func (e *Editor) ApplyCodeAction(ctx context.Context, action protocol.CodeAction) error { 36684- if action.Edit != nil { 36685- for _, change := range action.Edit.DocumentChanges { 36686- if change.TextDocumentEdit != nil { 36687- path := e.sandbox.Workdir.URIToPath(change.TextDocumentEdit.TextDocument.URI) 36688- if int32(e.buffers[path].version) != change.TextDocumentEdit.TextDocument.Version { 36689- // Skip edits for old versions. 36690- continue 36691- } 36692- if err := e.EditBuffer(ctx, path, change.TextDocumentEdit.Edits); err != nil { 36693- return fmt.Errorf("editing buffer %q: %w", path, err) 36694- } 36695- } 36696- } 36697- } 36698- // Execute any commands. The specification says that commands are 36699- // executed after edits are applied. 36700- if action.Command != nil { 36701- if _, err := e.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{ 36702- Command: action.Command.Command, 36703- Arguments: action.Command.Arguments, 36704- }); err != nil { 36705- return err 36706- } 36707- } 36708- // Some commands may edit files on disk. 36709- return e.sandbox.Workdir.CheckForFileChanges(ctx) 36710-} 36711- 36712-// GetQuickFixes returns the available quick fix code actions. 36713-func (e *Editor) GetQuickFixes(ctx context.Context, loc protocol.Location, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) { 36714- return e.getCodeActions(ctx, loc, diagnostics, protocol.QuickFix, protocol.SourceFixAll) 36715-} 36716- 36717-func (e *Editor) applyCodeActions(ctx context.Context, loc protocol.Location, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) (int, error) { 36718- actions, err := e.getCodeActions(ctx, loc, diagnostics, only...) 36719- if err != nil { 36720- return 0, err 36721- } 36722- applied := 0 36723- for _, action := range actions { 36724- if action.Title == "" { 36725- return 0, fmt.Errorf("empty title for code action") 36726- } 36727- var match bool 36728- for _, o := range only { 36729- if action.Kind == o { 36730- match = true 36731- break 36732- } 36733- } 36734- if !match { 36735- continue 36736- } 36737- applied++ 36738- if err := e.ApplyCodeAction(ctx, action); err != nil { 36739- return 0, err 36740- } 36741- } 36742- return applied, nil 36743-} 36744- 36745-func (e *Editor) getCodeActions(ctx context.Context, loc protocol.Location, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) ([]protocol.CodeAction, error) { 36746- if e.Server == nil { 36747- return nil, nil 36748- } 36749- params := &protocol.CodeActionParams{} 36750- params.TextDocument.URI = loc.URI 36751- params.Context.Only = only 36752- params.Range = loc.Range // may be zero => whole file 36753- if diagnostics != nil { 36754- params.Context.Diagnostics = diagnostics 36755- } 36756- return e.Server.CodeAction(ctx, params) 36757-} 36758- 36759-func (e *Editor) ExecuteCommand(ctx context.Context, params *protocol.ExecuteCommandParams) (interface{}, error) { 36760- if e.Server == nil { 36761- return nil, nil 36762- } 36763- var match bool 36764- if e.serverCapabilities.ExecuteCommandProvider != nil { 36765- // Ensure that this command was actually listed as a supported command. 36766- for _, command := range e.serverCapabilities.ExecuteCommandProvider.Commands { 36767- if command == params.Command { 36768- match = true 36769- break 36770- } 36771- } 36772- } 36773- if !match { 36774- return nil, fmt.Errorf("unsupported command %q", params.Command) 36775- } 36776- result, err := e.Server.ExecuteCommand(ctx, params) 36777- if err != nil { 36778- return nil, err 36779- } 36780- // Some commands use the go command, which writes directly to disk. 36781- // For convenience, check for those changes. 36782- if err := e.sandbox.Workdir.CheckForFileChanges(ctx); err != nil { 36783- return nil, fmt.Errorf("checking for file changes: %v", err) 36784- } 36785- return result, nil 36786-} 36787- 36788-// FormatBuffer gofmts a Go file. 36789-func (e *Editor) FormatBuffer(ctx context.Context, path string) error { 36790- if e.Server == nil { 36791- return nil 36792- } 36793- e.mu.Lock() 36794- version := e.buffers[path].version 36795- e.mu.Unlock() 36796- params := &protocol.DocumentFormattingParams{} 36797- params.TextDocument.URI = e.sandbox.Workdir.URI(path) 36798- edits, err := e.Server.Formatting(ctx, params) 36799- if err != nil { 36800- return fmt.Errorf("textDocument/formatting: %w", err) 36801- } 36802- e.mu.Lock() 36803- defer e.mu.Unlock() 36804- if versionAfter := e.buffers[path].version; versionAfter != version { 36805- return fmt.Errorf("before receipt of formatting edits, buffer version changed from %d to %d", version, versionAfter) 36806- } 36807- if len(edits) == 0 { 36808- return nil 36809- } 36810- return e.editBufferLocked(ctx, path, edits) 36811-} 36812- 36813-func (e *Editor) checkBufferLocation(loc protocol.Location) error { 36814- e.mu.Lock() 36815- defer e.mu.Unlock() 36816- path := e.sandbox.Workdir.URIToPath(loc.URI) 36817- buf, ok := e.buffers[path] 36818- if !ok { 36819- return fmt.Errorf("buffer %q is not open", path) 36820- } 36821- 36822- _, _, err := buf.mapper.RangeOffsets(loc.Range) 36823- return err 36824-} 36825- 36826-// RunGenerate runs `go generate` non-recursively in the workdir-relative dir 36827-// path. It does not report any resulting file changes as a watched file 36828-// change, so must be followed by a call to Workdir.CheckForFileChanges once 36829-// the generate command has completed. 36830-// TODO(rFindley): this shouldn't be necessary anymore. Delete it. 36831-func (e *Editor) RunGenerate(ctx context.Context, dir string) error { 36832- if e.Server == nil { 36833- return nil 36834- } 36835- absDir := e.sandbox.Workdir.AbsPath(dir) 36836- cmd, err := command.NewGenerateCommand("", command.GenerateArgs{ 36837- Dir: protocol.URIFromSpanURI(span.URIFromPath(absDir)), 36838- Recursive: false, 36839- }) 36840- if err != nil { 36841- return err 36842- } 36843- params := &protocol.ExecuteCommandParams{ 36844- Command: cmd.Command, 36845- Arguments: cmd.Arguments, 36846- } 36847- if _, err := e.ExecuteCommand(ctx, params); err != nil { 36848- return fmt.Errorf("running generate: %v", err) 36849- } 36850- // Unfortunately we can't simply poll the workdir for file changes here, 36851- // because server-side command may not have completed. In regtests, we can 36852- // Await this state change, but here we must delegate that responsibility to 36853- // the caller. 36854- return nil 36855-} 36856- 36857-// CodeLens executes a codelens request on the server. 36858-func (e *Editor) CodeLens(ctx context.Context, path string) ([]protocol.CodeLens, error) { 36859- if e.Server == nil { 36860- return nil, nil 36861- } 36862- e.mu.Lock() 36863- _, ok := e.buffers[path] 36864- e.mu.Unlock() 36865- if !ok { 36866- return nil, fmt.Errorf("buffer %q is not open", path) 36867- } 36868- params := &protocol.CodeLensParams{ 36869- TextDocument: e.TextDocumentIdentifier(path), 36870- } 36871- lens, err := e.Server.CodeLens(ctx, params) 36872- if err != nil { 36873- return nil, err 36874- } 36875- return lens, nil 36876-} 36877- 36878-// Completion executes a completion request on the server. 36879-func (e *Editor) Completion(ctx context.Context, loc protocol.Location) (*protocol.CompletionList, error) { 36880- if e.Server == nil { 36881- return nil, nil 36882- } 36883- path := e.sandbox.Workdir.URIToPath(loc.URI) 36884- e.mu.Lock() 36885- _, ok := e.buffers[path] 36886- e.mu.Unlock() 36887- if !ok { 36888- return nil, fmt.Errorf("buffer %q is not open", path) 36889- } 36890- params := &protocol.CompletionParams{ 36891- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 36892- } 36893- completions, err := e.Server.Completion(ctx, params) 36894- if err != nil { 36895- return nil, err 36896- } 36897- return completions, nil 36898-} 36899- 36900-// AcceptCompletion accepts a completion for the given item at the given 36901-// position. 36902-func (e *Editor) AcceptCompletion(ctx context.Context, loc protocol.Location, item protocol.CompletionItem) error { 36903- if e.Server == nil { 36904- return nil 36905- } 36906- e.mu.Lock() 36907- defer e.mu.Unlock() 36908- path := e.sandbox.Workdir.URIToPath(loc.URI) 36909- _, ok := e.buffers[path] 36910- if !ok { 36911- return fmt.Errorf("buffer %q is not open", path) 36912- } 36913- return e.editBufferLocked(ctx, path, append([]protocol.TextEdit{ 36914- *item.TextEdit, 36915- }, item.AdditionalTextEdits...)) 36916-} 36917- 36918-// Symbols executes a workspace/symbols request on the server. 36919-func (e *Editor) Symbols(ctx context.Context, sym string) ([]protocol.SymbolInformation, error) { 36920- if e.Server == nil { 36921- return nil, nil 36922- } 36923- params := &protocol.WorkspaceSymbolParams{Query: sym} 36924- ans, err := e.Server.Symbol(ctx, params) 36925- return ans, err 36926-} 36927- 36928-// CodeLens executes a codelens request on the server. 36929-func (e *Editor) InlayHint(ctx context.Context, path string) ([]protocol.InlayHint, error) { 36930- if e.Server == nil { 36931- return nil, nil 36932- } 36933- e.mu.Lock() 36934- _, ok := e.buffers[path] 36935- e.mu.Unlock() 36936- if !ok { 36937- return nil, fmt.Errorf("buffer %q is not open", path) 36938- } 36939- params := &protocol.InlayHintParams{ 36940- TextDocument: e.TextDocumentIdentifier(path), 36941- } 36942- hints, err := e.Server.InlayHint(ctx, params) 36943- if err != nil { 36944- return nil, err 36945- } 36946- return hints, nil 36947-} 36948- 36949-// References returns references to the object at loc, as returned by 36950-// the connected LSP server. If no server is connected, it returns (nil, nil). 36951-func (e *Editor) References(ctx context.Context, loc protocol.Location) ([]protocol.Location, error) { 36952- if e.Server == nil { 36953- return nil, nil 36954- } 36955- path := e.sandbox.Workdir.URIToPath(loc.URI) 36956- e.mu.Lock() 36957- _, ok := e.buffers[path] 36958- e.mu.Unlock() 36959- if !ok { 36960- return nil, fmt.Errorf("buffer %q is not open", path) 36961- } 36962- params := &protocol.ReferenceParams{ 36963- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 36964- Context: protocol.ReferenceContext{ 36965- IncludeDeclaration: true, 36966- }, 36967- } 36968- locations, err := e.Server.References(ctx, params) 36969- if err != nil { 36970- return nil, err 36971- } 36972- return locations, nil 36973-} 36974- 36975-// Rename performs a rename of the object at loc to newName, using the 36976-// connected LSP server. If no server is connected, it returns nil. 36977-func (e *Editor) Rename(ctx context.Context, loc protocol.Location, newName string) error { 36978- if e.Server == nil { 36979- return nil 36980- } 36981- path := e.sandbox.Workdir.URIToPath(loc.URI) 36982- 36983- // Verify that PrepareRename succeeds. 36984- prepareParams := &protocol.PrepareRenameParams{} 36985- prepareParams.TextDocument = e.TextDocumentIdentifier(path) 36986- prepareParams.Position = loc.Range.Start 36987- if _, err := e.Server.PrepareRename(ctx, prepareParams); err != nil { 36988- return fmt.Errorf("preparing rename: %v", err) 36989- } 36990- 36991- params := &protocol.RenameParams{ 36992- TextDocument: e.TextDocumentIdentifier(path), 36993- Position: loc.Range.Start, 36994- NewName: newName, 36995- } 36996- wsEdits, err := e.Server.Rename(ctx, params) 36997- if err != nil { 36998- return err 36999- } 37000- for _, change := range wsEdits.DocumentChanges { 37001- if err := e.applyDocumentChange(ctx, change); err != nil { 37002- return err 37003- } 37004- } 37005- return nil 37006-} 37007- 37008-// Implementations returns implementations for the object at loc, as 37009-// returned by the connected LSP server. If no server is connected, it returns 37010-// (nil, nil). 37011-func (e *Editor) Implementations(ctx context.Context, loc protocol.Location) ([]protocol.Location, error) { 37012- if e.Server == nil { 37013- return nil, nil 37014- } 37015- path := e.sandbox.Workdir.URIToPath(loc.URI) 37016- e.mu.Lock() 37017- _, ok := e.buffers[path] 37018- e.mu.Unlock() 37019- if !ok { 37020- return nil, fmt.Errorf("buffer %q is not open", path) 37021- } 37022- params := &protocol.ImplementationParams{ 37023- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 37024- } 37025- return e.Server.Implementation(ctx, params) 37026-} 37027- 37028-func (e *Editor) SignatureHelp(ctx context.Context, loc protocol.Location) (*protocol.SignatureHelp, error) { 37029- if e.Server == nil { 37030- return nil, nil 37031- } 37032- path := e.sandbox.Workdir.URIToPath(loc.URI) 37033- e.mu.Lock() 37034- _, ok := e.buffers[path] 37035- e.mu.Unlock() 37036- if !ok { 37037- return nil, fmt.Errorf("buffer %q is not open", path) 37038- } 37039- params := &protocol.SignatureHelpParams{ 37040- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 37041- } 37042- return e.Server.SignatureHelp(ctx, params) 37043-} 37044- 37045-func (e *Editor) RenameFile(ctx context.Context, oldPath, newPath string) error { 37046- closed, opened, err := e.renameBuffers(ctx, oldPath, newPath) 37047- if err != nil { 37048- return err 37049- } 37050- 37051- for _, c := range closed { 37052- if err := e.sendDidClose(ctx, c); err != nil { 37053- return err 37054- } 37055- } 37056- for _, o := range opened { 37057- if err := e.sendDidOpen(ctx, o); err != nil { 37058- return err 37059- } 37060- } 37061- 37062- // Finally, perform the renaming on disk. 37063- if err := e.sandbox.Workdir.RenameFile(ctx, oldPath, newPath); err != nil { 37064- return fmt.Errorf("renaming sandbox file: %w", err) 37065- } 37066- return nil 37067-} 37068- 37069-// renameBuffers renames in-memory buffers affected by the renaming of 37070-// oldPath->newPath, returning the resulting text documents that must be closed 37071-// and opened over the LSP. 37072-func (e *Editor) renameBuffers(ctx context.Context, oldPath, newPath string) (closed []protocol.TextDocumentIdentifier, opened []protocol.TextDocumentItem, _ error) { 37073- e.mu.Lock() 37074- defer e.mu.Unlock() 37075- 37076- // In case either oldPath or newPath is absolute, convert to absolute paths 37077- // before checking for containment. 37078- oldAbs := e.sandbox.Workdir.AbsPath(oldPath) 37079- newAbs := e.sandbox.Workdir.AbsPath(newPath) 37080- 37081- // Collect buffers that are affected by the given file or directory renaming. 37082- buffersToRename := make(map[string]string) // old path -> new path 37083- 37084- for path := range e.buffers { 37085- abs := e.sandbox.Workdir.AbsPath(path) 37086- if oldAbs == abs || source.InDir(oldAbs, abs) { 37087- rel, err := filepath.Rel(oldAbs, abs) 37088- if err != nil { 37089- return nil, nil, fmt.Errorf("filepath.Rel(%q, %q): %v", oldAbs, abs, err) 37090- } 37091- nabs := filepath.Join(newAbs, rel) 37092- newPath := e.sandbox.Workdir.RelPath(nabs) 37093- buffersToRename[path] = newPath 37094- } 37095- } 37096- 37097- // Update buffers, and build protocol changes. 37098- for old, new := range buffersToRename { 37099- buf := e.buffers[old] 37100- delete(e.buffers, old) 37101- buf.version = 1 37102- buf.path = new 37103- e.buffers[new] = buf 37104- 37105- closed = append(closed, e.TextDocumentIdentifier(old)) 37106- opened = append(opened, e.textDocumentItem(buf)) 37107- } 37108- 37109- return closed, opened, nil 37110-} 37111- 37112-func (e *Editor) applyDocumentChange(ctx context.Context, change protocol.DocumentChanges) error { 37113- if change.RenameFile != nil { 37114- oldPath := e.sandbox.Workdir.URIToPath(change.RenameFile.OldURI) 37115- newPath := e.sandbox.Workdir.URIToPath(change.RenameFile.NewURI) 37116- 37117- return e.RenameFile(ctx, oldPath, newPath) 37118- } 37119- if change.TextDocumentEdit != nil { 37120- return e.applyTextDocumentEdit(ctx, *change.TextDocumentEdit) 37121- } 37122- panic("Internal error: one of RenameFile or TextDocumentEdit must be set") 37123-} 37124- 37125-func (e *Editor) applyTextDocumentEdit(ctx context.Context, change protocol.TextDocumentEdit) error { 37126- path := e.sandbox.Workdir.URIToPath(change.TextDocument.URI) 37127- if ver := int32(e.BufferVersion(path)); ver != change.TextDocument.Version { 37128- return fmt.Errorf("buffer versions for %q do not match: have %d, editing %d", path, ver, change.TextDocument.Version) 37129- } 37130- if !e.HasBuffer(path) { 37131- err := e.OpenFile(ctx, path) 37132- if os.IsNotExist(err) { 37133- // TODO: it's unclear if this is correct. Here we create the buffer (with 37134- // version 1), then apply edits. Perhaps we should apply the edits before 37135- // sending the didOpen notification. 37136- e.CreateBuffer(ctx, path, "") 37137- err = nil 37138- } 37139- if err != nil { 37140- return err 37141- } 37142- } 37143- return e.EditBuffer(ctx, path, change.Edits) 37144-} 37145- 37146-// Config returns the current editor configuration. 37147-func (e *Editor) Config() EditorConfig { 37148- e.mu.Lock() 37149- defer e.mu.Unlock() 37150- return e.config 37151-} 37152- 37153-// ChangeConfiguration sets the new editor configuration, and if applicable 37154-// sends a didChangeConfiguration notification. 37155-// 37156-// An error is returned if the change notification failed to send. 37157-func (e *Editor) ChangeConfiguration(ctx context.Context, newConfig EditorConfig) error { 37158- e.mu.Lock() 37159- e.config = newConfig 37160- e.mu.Unlock() // don't hold e.mu during server calls 37161- if e.Server != nil { 37162- var params protocol.DidChangeConfigurationParams // empty: gopls ignores the Settings field 37163- if err := e.Server.DidChangeConfiguration(ctx, ¶ms); err != nil { 37164- return err 37165- } 37166- } 37167- return nil 37168-} 37169- 37170-// ChangeWorkspaceFolders sets the new workspace folders, and sends a 37171-// didChangeWorkspaceFolders notification to the server. 37172-// 37173-// The given folders must all be unique. 37174-func (e *Editor) ChangeWorkspaceFolders(ctx context.Context, folders []string) error { 37175- // capture existing folders so that we can compute the change. 37176- e.mu.Lock() 37177- oldFolders := e.makeWorkspaceFoldersLocked() 37178- e.config.WorkspaceFolders = folders 37179- newFolders := e.makeWorkspaceFoldersLocked() 37180- e.mu.Unlock() 37181- 37182- if e.Server == nil { 37183- return nil 37184- } 37185- 37186- var params protocol.DidChangeWorkspaceFoldersParams 37187- 37188- // Keep track of old workspace folders that must be removed. 37189- toRemove := make(map[protocol.URI]protocol.WorkspaceFolder) 37190- for _, folder := range oldFolders { 37191- toRemove[folder.URI] = folder 37192- } 37193- 37194- // Sanity check: if we see a folder twice the algorithm below doesn't work, 37195- // so track seen folders to ensure that we panic in that case. 37196- seen := make(map[protocol.URI]protocol.WorkspaceFolder) 37197- for _, folder := range newFolders { 37198- if _, ok := seen[folder.URI]; ok { 37199- panic(fmt.Sprintf("folder %s seen twice", folder.URI)) 37200- } 37201- 37202- // If this folder already exists, we don't want to remove it. 37203- // Otherwise, we need to add it. 37204- if _, ok := toRemove[folder.URI]; ok { 37205- delete(toRemove, folder.URI) 37206- } else { 37207- params.Event.Added = append(params.Event.Added, folder) 37208- } 37209- } 37210- 37211- for _, v := range toRemove { 37212- params.Event.Removed = append(params.Event.Removed, v) 37213- } 37214- 37215- return e.Server.DidChangeWorkspaceFolders(ctx, ¶ms) 37216-} 37217- 37218-// CodeAction executes a codeAction request on the server. 37219-// If loc.Range is zero, the whole file is implied. 37220-func (e *Editor) CodeAction(ctx context.Context, loc protocol.Location, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) { 37221- if e.Server == nil { 37222- return nil, nil 37223- } 37224- path := e.sandbox.Workdir.URIToPath(loc.URI) 37225- e.mu.Lock() 37226- _, ok := e.buffers[path] 37227- e.mu.Unlock() 37228- if !ok { 37229- return nil, fmt.Errorf("buffer %q is not open", path) 37230- } 37231- params := &protocol.CodeActionParams{ 37232- TextDocument: e.TextDocumentIdentifier(path), 37233- Context: protocol.CodeActionContext{ 37234- Diagnostics: diagnostics, 37235- }, 37236- Range: loc.Range, // may be zero 37237- } 37238- lens, err := e.Server.CodeAction(ctx, params) 37239- if err != nil { 37240- return nil, err 37241- } 37242- return lens, nil 37243-} 37244- 37245-// Hover triggers a hover at the given position in an open buffer. 37246-func (e *Editor) Hover(ctx context.Context, loc protocol.Location) (*protocol.MarkupContent, protocol.Location, error) { 37247- if err := e.checkBufferLocation(loc); err != nil { 37248- return nil, protocol.Location{}, err 37249- } 37250- params := &protocol.HoverParams{} 37251- params.TextDocument.URI = loc.URI 37252- params.Position = loc.Range.Start 37253- 37254- resp, err := e.Server.Hover(ctx, params) 37255- if err != nil { 37256- return nil, protocol.Location{}, fmt.Errorf("hover: %w", err) 37257- } 37258- if resp == nil { 37259- return nil, protocol.Location{}, nil 37260- } 37261- return &resp.Contents, protocol.Location{URI: loc.URI, Range: resp.Range}, nil 37262-} 37263- 37264-func (e *Editor) DocumentLink(ctx context.Context, path string) ([]protocol.DocumentLink, error) { 37265- if e.Server == nil { 37266- return nil, nil 37267- } 37268- params := &protocol.DocumentLinkParams{} 37269- params.TextDocument.URI = e.sandbox.Workdir.URI(path) 37270- return e.Server.DocumentLink(ctx, params) 37271-} 37272- 37273-func (e *Editor) DocumentHighlight(ctx context.Context, loc protocol.Location) ([]protocol.DocumentHighlight, error) { 37274- if e.Server == nil { 37275- return nil, nil 37276- } 37277- if err := e.checkBufferLocation(loc); err != nil { 37278- return nil, err 37279- } 37280- params := &protocol.DocumentHighlightParams{} 37281- params.TextDocument.URI = loc.URI 37282- params.Position = loc.Range.Start 37283- 37284- return e.Server.DocumentHighlight(ctx, params) 37285-} 37286diff -urN a/gopls/internal/lsp/fake/editor_test.go b/gopls/internal/lsp/fake/editor_test.go 37287--- a/gopls/internal/lsp/fake/editor_test.go 2000-01-01 00:00:00.000000000 -0000 37288+++ b/gopls/internal/lsp/fake/editor_test.go 1970-01-01 00:00:00.000000000 +0000 37289@@ -1,61 +0,0 @@ 37290-// Copyright 2020 The Go Authors. All rights reserved. 37291-// Use of this source code is governed by a BSD-style 37292-// license that can be found in the LICENSE file. 37293- 37294-package fake 37295- 37296-import ( 37297- "context" 37298- "testing" 37299- 37300- "golang.org/x/tools/gopls/internal/lsp/protocol" 37301-) 37302- 37303-const exampleProgram = ` 37304--- go.mod -- 37305-go 1.12 37306--- main.go -- 37307-package main 37308- 37309-import "fmt" 37310- 37311-func main() { 37312- fmt.Println("Hello World.") 37313-} 37314-` 37315- 37316-func TestClientEditing(t *testing.T) { 37317- ws, err := NewSandbox(&SandboxConfig{Files: UnpackTxt(exampleProgram)}) 37318- if err != nil { 37319- t.Fatal(err) 37320- } 37321- defer ws.Close() 37322- ctx := context.Background() 37323- editor := NewEditor(ws, EditorConfig{}) 37324- if err := editor.OpenFile(ctx, "main.go"); err != nil { 37325- t.Fatal(err) 37326- } 37327- if err := editor.EditBuffer(ctx, "main.go", []protocol.TextEdit{ 37328- { 37329- Range: protocol.Range{ 37330- Start: protocol.Position{Line: 5, Character: 14}, 37331- End: protocol.Position{Line: 5, Character: 26}, 37332- }, 37333- NewText: "Hola, mundo.", 37334- }, 37335- }); err != nil { 37336- t.Fatal(err) 37337- } 37338- got := editor.buffers["main.go"].text() 37339- want := `package main 37340- 37341-import "fmt" 37342- 37343-func main() { 37344- fmt.Println("Hola, mundo.") 37345-} 37346-` 37347- if got != want { 37348- t.Errorf("got text %q, want %q", got, want) 37349- } 37350-} 37351diff -urN a/gopls/internal/lsp/fake/edit_test.go b/gopls/internal/lsp/fake/edit_test.go 37352--- a/gopls/internal/lsp/fake/edit_test.go 2000-01-01 00:00:00.000000000 -0000 37353+++ b/gopls/internal/lsp/fake/edit_test.go 1970-01-01 00:00:00.000000000 +0000 37354@@ -1,96 +0,0 @@ 37355-// Copyright 2020 The Go Authors. All rights reserved. 37356-// Use of this source code is governed by a BSD-style 37357-// license that can be found in the LICENSE file. 37358- 37359-package fake 37360- 37361-import ( 37362- "testing" 37363- 37364- "golang.org/x/tools/gopls/internal/lsp/protocol" 37365-) 37366- 37367-func TestApplyEdits(t *testing.T) { 37368- tests := []struct { 37369- label string 37370- content string 37371- edits []protocol.TextEdit 37372- want string 37373- wantErr bool 37374- }{ 37375- { 37376- label: "empty content", 37377- }, 37378- { 37379- label: "empty edit", 37380- content: "hello", 37381- edits: []protocol.TextEdit{}, 37382- want: "hello", 37383- }, 37384- { 37385- label: "unicode edit", 37386- content: "hello, 日本語", 37387- edits: []protocol.TextEdit{ 37388- NewEdit(0, 7, 0, 10, "world"), 37389- }, 37390- want: "hello, world", 37391- }, 37392- { 37393- label: "range edit", 37394- content: "ABC\nDEF\nGHI\nJKL", 37395- edits: []protocol.TextEdit{ 37396- NewEdit(1, 1, 2, 3, "12\n345"), 37397- }, 37398- want: "ABC\nD12\n345\nJKL", 37399- }, 37400- { 37401- label: "regression test for issue #57627", 37402- content: "go 1.18\nuse moda/a", 37403- edits: []protocol.TextEdit{ 37404- NewEdit(1, 0, 1, 0, "\n"), 37405- NewEdit(2, 0, 2, 0, "\n"), 37406- }, 37407- want: "go 1.18\n\nuse moda/a\n", 37408- }, 37409- { 37410- label: "end before start", 37411- content: "ABC\nDEF\nGHI\nJKL", 37412- edits: []protocol.TextEdit{ 37413- NewEdit(2, 3, 1, 1, "12\n345"), 37414- }, 37415- wantErr: true, 37416- }, 37417- { 37418- label: "out of bounds line", 37419- content: "ABC\nDEF\nGHI\nJKL", 37420- edits: []protocol.TextEdit{ 37421- NewEdit(1, 1, 4, 3, "12\n345"), 37422- }, 37423- wantErr: true, 37424- }, 37425- { 37426- label: "out of bounds column", 37427- content: "ABC\nDEF\nGHI\nJKL", 37428- edits: []protocol.TextEdit{ 37429- NewEdit(1, 4, 2, 3, "12\n345"), 37430- }, 37431- wantErr: true, 37432- }, 37433- } 37434- 37435- for _, test := range tests { 37436- test := test 37437- t.Run(test.label, func(t *testing.T) { 37438- got, err := applyEdits(protocol.NewMapper("", []byte(test.content)), test.edits, false) 37439- if (err != nil) != test.wantErr { 37440- t.Errorf("got err %v, want error: %t", err, test.wantErr) 37441- } 37442- if err != nil { 37443- return 37444- } 37445- if got := string(got); got != test.want { 37446- t.Errorf("got %q, want %q", got, test.want) 37447- } 37448- }) 37449- } 37450-} 37451diff -urN a/gopls/internal/lsp/fake/proxy.go b/gopls/internal/lsp/fake/proxy.go 37452--- a/gopls/internal/lsp/fake/proxy.go 2000-01-01 00:00:00.000000000 -0000 37453+++ b/gopls/internal/lsp/fake/proxy.go 1970-01-01 00:00:00.000000000 +0000 37454@@ -1,35 +0,0 @@ 37455-// Copyright 2020 The Go Authors. All rights reserved. 37456-// Use of this source code is governed by a BSD-style 37457-// license that can be found in the LICENSE file. 37458- 37459-package fake 37460- 37461-import ( 37462- "fmt" 37463- 37464- "golang.org/x/tools/internal/proxydir" 37465-) 37466- 37467-// WriteProxy creates a new proxy file tree using the txtar-encoded content, 37468-// and returns its URL. 37469-func WriteProxy(tmpdir string, files map[string][]byte) (string, error) { 37470- type moduleVersion struct { 37471- modulePath, version string 37472- } 37473- // Transform into the format expected by the proxydir package. 37474- filesByModule := make(map[moduleVersion]map[string][]byte) 37475- for name, data := range files { 37476- modulePath, version, suffix := splitModuleVersionPath(name) 37477- mv := moduleVersion{modulePath, version} 37478- if _, ok := filesByModule[mv]; !ok { 37479- filesByModule[mv] = make(map[string][]byte) 37480- } 37481- filesByModule[mv][suffix] = data 37482- } 37483- for mv, files := range filesByModule { 37484- if err := proxydir.WriteModuleVersion(tmpdir, mv.modulePath, mv.version, files); err != nil { 37485- return "", fmt.Errorf("error writing %s@%s: %v", mv.modulePath, mv.version, err) 37486- } 37487- } 37488- return proxydir.ToURL(tmpdir), nil 37489-} 37490diff -urN a/gopls/internal/lsp/fake/sandbox.go b/gopls/internal/lsp/fake/sandbox.go 37491--- a/gopls/internal/lsp/fake/sandbox.go 2000-01-01 00:00:00.000000000 -0000 37492+++ b/gopls/internal/lsp/fake/sandbox.go 1970-01-01 00:00:00.000000000 +0000 37493@@ -1,299 +0,0 @@ 37494-// Copyright 2020 The Go Authors. All rights reserved. 37495-// Use of this source code is governed by a BSD-style 37496-// license that can be found in the LICENSE file. 37497- 37498-package fake 37499- 37500-import ( 37501- "context" 37502- "errors" 37503- "fmt" 37504- "io/ioutil" 37505- "os" 37506- "path/filepath" 37507- "strings" 37508- 37509- "golang.org/x/tools/internal/gocommand" 37510- "golang.org/x/tools/internal/robustio" 37511- "golang.org/x/tools/internal/testenv" 37512- "golang.org/x/tools/txtar" 37513-) 37514- 37515-// Sandbox holds a collection of temporary resources to use for working with Go 37516-// code in tests. 37517-type Sandbox struct { 37518- gopath string 37519- rootdir string 37520- goproxy string 37521- Workdir *Workdir 37522- goCommandRunner gocommand.Runner 37523-} 37524- 37525-// SandboxConfig controls the behavior of a test sandbox. The zero value 37526-// defines a reasonable default. 37527-type SandboxConfig struct { 37528- // RootDir sets the base directory to use when creating temporary 37529- // directories. If not specified, defaults to a new temporary directory. 37530- RootDir string 37531- // Files holds a txtar-encoded archive of files to populate the initial state 37532- // of the working directory. 37533- // 37534- // For convenience, the special substring "$SANDBOX_WORKDIR" is replaced with 37535- // the sandbox's resolved working directory before writing files. 37536- Files map[string][]byte 37537- // InGoPath specifies that the working directory should be within the 37538- // temporary GOPATH. 37539- InGoPath bool 37540- // Workdir configures the working directory of the Sandbox. It behaves as 37541- // follows: 37542- // - if set to an absolute path, use that path as the working directory. 37543- // - if set to a relative path, create and use that path relative to the 37544- // sandbox. 37545- // - if unset, default to a the 'work' subdirectory of the sandbox. 37546- // 37547- // This option is incompatible with InGoPath or Files. 37548- Workdir string 37549- // ProxyFiles holds a txtar-encoded archive of files to populate a file-based 37550- // Go proxy. 37551- ProxyFiles map[string][]byte 37552- // GOPROXY is the explicit GOPROXY value that should be used for the sandbox. 37553- // 37554- // This option is incompatible with ProxyFiles. 37555- GOPROXY string 37556-} 37557- 37558-// NewSandbox creates a collection of named temporary resources, with a 37559-// working directory populated by the txtar-encoded content in srctxt, and a 37560-// file-based module proxy populated with the txtar-encoded content in 37561-// proxytxt. 37562-// 37563-// If rootDir is non-empty, it will be used as the root of temporary 37564-// directories created for the sandbox. Otherwise, a new temporary directory 37565-// will be used as root. 37566-// 37567-// TODO(rfindley): the sandbox abstraction doesn't seem to carry its weight. 37568-// Sandboxes should be composed out of their building-blocks, rather than via a 37569-// monolithic configuration. 37570-func NewSandbox(config *SandboxConfig) (_ *Sandbox, err error) { 37571- if config == nil { 37572- config = new(SandboxConfig) 37573- } 37574- if err := validateConfig(*config); err != nil { 37575- return nil, fmt.Errorf("invalid SandboxConfig: %v", err) 37576- } 37577- 37578- sb := &Sandbox{} 37579- defer func() { 37580- // Clean up if we fail at any point in this constructor. 37581- if err != nil { 37582- sb.Close() 37583- } 37584- }() 37585- 37586- rootDir := config.RootDir 37587- if rootDir == "" { 37588- rootDir, err = ioutil.TempDir(config.RootDir, "gopls-sandbox-") 37589- if err != nil { 37590- return nil, fmt.Errorf("creating temporary workdir: %v", err) 37591- } 37592- } 37593- sb.rootdir = rootDir 37594- sb.gopath = filepath.Join(sb.rootdir, "gopath") 37595- if err := os.Mkdir(sb.gopath, 0755); err != nil { 37596- return nil, err 37597- } 37598- if config.GOPROXY != "" { 37599- sb.goproxy = config.GOPROXY 37600- } else { 37601- proxydir := filepath.Join(sb.rootdir, "proxy") 37602- if err := os.Mkdir(proxydir, 0755); err != nil { 37603- return nil, err 37604- } 37605- sb.goproxy, err = WriteProxy(proxydir, config.ProxyFiles) 37606- if err != nil { 37607- return nil, err 37608- } 37609- } 37610- // Short-circuit writing the workdir if we're given an absolute path, since 37611- // this is used for running in an existing directory. 37612- // TODO(findleyr): refactor this to be less of a workaround. 37613- if filepath.IsAbs(config.Workdir) { 37614- sb.Workdir, err = NewWorkdir(config.Workdir, nil) 37615- if err != nil { 37616- return nil, err 37617- } 37618- return sb, nil 37619- } 37620- var workdir string 37621- if config.Workdir == "" { 37622- if config.InGoPath { 37623- // Set the working directory as $GOPATH/src. 37624- workdir = filepath.Join(sb.gopath, "src") 37625- } else if workdir == "" { 37626- workdir = filepath.Join(sb.rootdir, "work") 37627- } 37628- } else { 37629- // relative path 37630- workdir = filepath.Join(sb.rootdir, config.Workdir) 37631- } 37632- if err := os.MkdirAll(workdir, 0755); err != nil { 37633- return nil, err 37634- } 37635- sb.Workdir, err = NewWorkdir(workdir, config.Files) 37636- if err != nil { 37637- return nil, err 37638- } 37639- return sb, nil 37640-} 37641- 37642-// Tempdir creates a new temp directory with the given txtar-encoded files. It 37643-// is the responsibility of the caller to call os.RemoveAll on the returned 37644-// file path when it is no longer needed. 37645-func Tempdir(files map[string][]byte) (string, error) { 37646- dir, err := ioutil.TempDir("", "gopls-tempdir-") 37647- if err != nil { 37648- return "", err 37649- } 37650- for name, data := range files { 37651- if err := writeFileData(name, data, RelativeTo(dir)); err != nil { 37652- return "", fmt.Errorf("writing to tempdir: %w", err) 37653- } 37654- } 37655- return dir, nil 37656-} 37657- 37658-func UnpackTxt(txt string) map[string][]byte { 37659- dataMap := make(map[string][]byte) 37660- archive := txtar.Parse([]byte(txt)) 37661- for _, f := range archive.Files { 37662- if _, ok := dataMap[f.Name]; ok { 37663- panic(fmt.Sprintf("found file %q twice", f.Name)) 37664- } 37665- dataMap[f.Name] = f.Data 37666- } 37667- return dataMap 37668-} 37669- 37670-func validateConfig(config SandboxConfig) error { 37671- if filepath.IsAbs(config.Workdir) && (len(config.Files) > 0 || config.InGoPath) { 37672- return errors.New("absolute Workdir cannot be set in conjunction with Files or InGoPath") 37673- } 37674- if config.Workdir != "" && config.InGoPath { 37675- return errors.New("Workdir cannot be set in conjunction with InGoPath") 37676- } 37677- if config.GOPROXY != "" && config.ProxyFiles != nil { 37678- return errors.New("GOPROXY cannot be set in conjunction with ProxyFiles") 37679- } 37680- return nil 37681-} 37682- 37683-// splitModuleVersionPath extracts module information from files stored in the 37684-// directory structure modulePath@version/suffix. 37685-// For example: 37686-// 37687-// splitModuleVersionPath("[email protected]/package") = ("mod.com", "v1.2.3", "package") 37688-func splitModuleVersionPath(path string) (modulePath, version, suffix string) { 37689- parts := strings.Split(path, "/") 37690- var modulePathParts []string 37691- for i, p := range parts { 37692- if strings.Contains(p, "@") { 37693- mv := strings.SplitN(p, "@", 2) 37694- modulePathParts = append(modulePathParts, mv[0]) 37695- return strings.Join(modulePathParts, "/"), mv[1], strings.Join(parts[i+1:], "/") 37696- } 37697- modulePathParts = append(modulePathParts, p) 37698- } 37699- // Default behavior: this is just a module path. 37700- return path, "", "" 37701-} 37702- 37703-func (sb *Sandbox) RootDir() string { 37704- return sb.rootdir 37705-} 37706- 37707-// GOPATH returns the value of the Sandbox GOPATH. 37708-func (sb *Sandbox) GOPATH() string { 37709- return sb.gopath 37710-} 37711- 37712-// GoEnv returns the default environment variables that can be used for 37713-// invoking Go commands in the sandbox. 37714-func (sb *Sandbox) GoEnv() map[string]string { 37715- vars := map[string]string{ 37716- "GOPATH": sb.GOPATH(), 37717- "GOPROXY": sb.goproxy, 37718- "GO111MODULE": "", 37719- "GOSUMDB": "off", 37720- "GOPACKAGESDRIVER": "off", 37721- } 37722- if testenv.Go1Point() >= 5 { 37723- vars["GOMODCACHE"] = "" 37724- } 37725- return vars 37726-} 37727- 37728-// goCommandInvocation returns a new gocommand.Invocation initialized with the 37729-// sandbox environment variables and working directory. 37730-func (sb *Sandbox) goCommandInvocation() gocommand.Invocation { 37731- var vars []string 37732- for k, v := range sb.GoEnv() { 37733- vars = append(vars, fmt.Sprintf("%s=%s", k, v)) 37734- } 37735- inv := gocommand.Invocation{ 37736- Env: vars, 37737- } 37738- // sb.Workdir may be nil if we exited the constructor with errors (we call 37739- // Close to clean up any partial state from the constructor, which calls 37740- // RunGoCommand). 37741- if sb.Workdir != nil { 37742- inv.WorkingDir = string(sb.Workdir.RelativeTo) 37743- } 37744- return inv 37745-} 37746- 37747-// RunGoCommand executes a go command in the sandbox. If checkForFileChanges is 37748-// true, the sandbox scans the working directory and emits file change events 37749-// for any file changes it finds. 37750-func (sb *Sandbox) RunGoCommand(ctx context.Context, dir, verb string, args []string, checkForFileChanges bool) error { 37751- inv := sb.goCommandInvocation() 37752- inv.Verb = verb 37753- inv.Args = args 37754- if dir != "" { 37755- inv.WorkingDir = sb.Workdir.AbsPath(dir) 37756- } 37757- stdout, stderr, _, err := sb.goCommandRunner.RunRaw(ctx, inv) 37758- if err != nil { 37759- return fmt.Errorf("go command failed (stdout: %s) (stderr: %s): %v", stdout.String(), stderr.String(), err) 37760- } 37761- // Since running a go command may result in changes to workspace files, 37762- // check if we need to send any any "watched" file events. 37763- // 37764- // TODO(rFindley): this side-effect can impact the usability of the sandbox 37765- // for benchmarks. Consider refactoring. 37766- if sb.Workdir != nil && checkForFileChanges { 37767- if err := sb.Workdir.CheckForFileChanges(ctx); err != nil { 37768- return fmt.Errorf("checking for file changes: %w", err) 37769- } 37770- } 37771- return nil 37772-} 37773- 37774-// GoVersion checks the version of the go command. 37775-// It returns the X in Go 1.X. 37776-func (sb *Sandbox) GoVersion(ctx context.Context) (int, error) { 37777- inv := sb.goCommandInvocation() 37778- return gocommand.GoVersion(ctx, inv, &sb.goCommandRunner) 37779-} 37780- 37781-// Close removes all state associated with the sandbox. 37782-func (sb *Sandbox) Close() error { 37783- var goCleanErr error 37784- if sb.gopath != "" { 37785- goCleanErr = sb.RunGoCommand(context.Background(), "", "clean", []string{"-modcache"}, false) 37786- } 37787- err := robustio.RemoveAll(sb.rootdir) 37788- if err != nil || goCleanErr != nil { 37789- return fmt.Errorf("error(s) cleaning sandbox: cleaning modcache: %v; removing files: %v", goCleanErr, err) 37790- } 37791- return nil 37792-} 37793diff -urN a/gopls/internal/lsp/fake/workdir.go b/gopls/internal/lsp/fake/workdir.go 37794--- a/gopls/internal/lsp/fake/workdir.go 2000-01-01 00:00:00.000000000 -0000 37795+++ b/gopls/internal/lsp/fake/workdir.go 1970-01-01 00:00:00.000000000 +0000 37796@@ -1,438 +0,0 @@ 37797-// Copyright 2020 The Go Authors. All rights reserved. 37798-// Use of this source code is governed by a BSD-style 37799-// license that can be found in the LICENSE file. 37800- 37801-package fake 37802- 37803-import ( 37804- "bytes" 37805- "context" 37806- "crypto/sha256" 37807- "fmt" 37808- "io/fs" 37809- "io/ioutil" 37810- "os" 37811- "path/filepath" 37812- "runtime" 37813- "sort" 37814- "strings" 37815- "sync" 37816- "time" 37817- 37818- "golang.org/x/tools/gopls/internal/lsp/protocol" 37819- "golang.org/x/tools/gopls/internal/span" 37820- "golang.org/x/tools/internal/robustio" 37821-) 37822- 37823-// RelativeTo is a helper for operations relative to a given directory. 37824-type RelativeTo string 37825- 37826-// AbsPath returns an absolute filesystem path for the workdir-relative path. 37827-func (r RelativeTo) AbsPath(path string) string { 37828- fp := filepath.FromSlash(path) 37829- if filepath.IsAbs(fp) { 37830- return fp 37831- } 37832- return filepath.Join(string(r), filepath.FromSlash(path)) 37833-} 37834- 37835-// RelPath returns a '/'-encoded path relative to the working directory (or an 37836-// absolute path if the file is outside of workdir) 37837-func (r RelativeTo) RelPath(fp string) string { 37838- root := string(r) 37839- if rel, err := filepath.Rel(root, fp); err == nil && !strings.HasPrefix(rel, "..") { 37840- return filepath.ToSlash(rel) 37841- } 37842- return filepath.ToSlash(fp) 37843-} 37844- 37845-// writeFileData writes content to the relative path, replacing the special 37846-// token $SANDBOX_WORKDIR with the relative root given by rel. It does not 37847-// trigger any file events. 37848-func writeFileData(path string, content []byte, rel RelativeTo) error { 37849- content = bytes.ReplaceAll(content, []byte("$SANDBOX_WORKDIR"), []byte(rel)) 37850- fp := rel.AbsPath(path) 37851- if err := os.MkdirAll(filepath.Dir(fp), 0755); err != nil { 37852- return fmt.Errorf("creating nested directory: %w", err) 37853- } 37854- backoff := 1 * time.Millisecond 37855- for { 37856- err := ioutil.WriteFile(fp, []byte(content), 0644) 37857- if err != nil { 37858- // This lock file violation is not handled by the robustio package, as it 37859- // indicates a real race condition that could be avoided. 37860- if isWindowsErrLockViolation(err) { 37861- time.Sleep(backoff) 37862- backoff *= 2 37863- continue 37864- } 37865- return fmt.Errorf("writing %q: %w", path, err) 37866- } 37867- return nil 37868- } 37869-} 37870- 37871-// isWindowsErrLockViolation reports whether err is ERROR_LOCK_VIOLATION 37872-// on Windows. 37873-var isWindowsErrLockViolation = func(err error) bool { return false } 37874- 37875-// Workdir is a temporary working directory for tests. It exposes file 37876-// operations in terms of relative paths, and fakes file watching by triggering 37877-// events on file operations. 37878-type Workdir struct { 37879- RelativeTo 37880- 37881- watcherMu sync.Mutex 37882- watchers []func(context.Context, []protocol.FileEvent) 37883- 37884- fileMu sync.Mutex 37885- // File identities we know about, for the purpose of detecting changes. 37886- // 37887- // Since files is only used for detecting _changes_, we are tolerant of 37888- // fileIDs that may have hash and mtime coming from different states of the 37889- // file: if either are out of sync, then the next poll should detect a 37890- // discrepancy. It is OK if we detect too many changes, but not OK if we miss 37891- // changes. 37892- // 37893- // For that matter, this mechanism for detecting changes can still be flaky 37894- // on platforms where mtime is very coarse (such as older versions of WSL). 37895- // It would be much better to use a proper fs event library, but we can't 37896- // currently import those into x/tools. 37897- // 37898- // TODO(golang/go#52284): replace this polling mechanism with a 37899- // cross-platform library for filesystem notifications. 37900- files map[string]fileID 37901-} 37902- 37903-// NewWorkdir writes the txtar-encoded file data in txt to dir, and returns a 37904-// Workir for operating on these files using 37905-func NewWorkdir(dir string, files map[string][]byte) (*Workdir, error) { 37906- w := &Workdir{RelativeTo: RelativeTo(dir)} 37907- for name, data := range files { 37908- if err := writeFileData(name, data, w.RelativeTo); err != nil { 37909- return nil, fmt.Errorf("writing to workdir: %w", err) 37910- } 37911- } 37912- _, err := w.pollFiles() // poll files to populate the files map. 37913- return w, err 37914-} 37915- 37916-// fileID identifies a file version on disk. 37917-type fileID struct { 37918- mtime time.Time 37919- hash string // empty if mtime is old enough to be reliabe; otherwise a file digest 37920-} 37921- 37922-func hashFile(data []byte) string { 37923- return fmt.Sprintf("%x", sha256.Sum256(data)) 37924-} 37925- 37926-// RootURI returns the root URI for this working directory of this scratch 37927-// environment. 37928-func (w *Workdir) RootURI() protocol.DocumentURI { 37929- return toURI(string(w.RelativeTo)) 37930-} 37931- 37932-// AddWatcher registers the given func to be called on any file change. 37933-func (w *Workdir) AddWatcher(watcher func(context.Context, []protocol.FileEvent)) { 37934- w.watcherMu.Lock() 37935- w.watchers = append(w.watchers, watcher) 37936- w.watcherMu.Unlock() 37937-} 37938- 37939-// URI returns the URI to a the workdir-relative path. 37940-func (w *Workdir) URI(path string) protocol.DocumentURI { 37941- return toURI(w.AbsPath(path)) 37942-} 37943- 37944-// URIToPath converts a uri to a workdir-relative path (or an absolute path, 37945-// if the uri is outside of the workdir). 37946-func (w *Workdir) URIToPath(uri protocol.DocumentURI) string { 37947- fp := uri.SpanURI().Filename() 37948- return w.RelPath(fp) 37949-} 37950- 37951-func toURI(fp string) protocol.DocumentURI { 37952- return protocol.DocumentURI(span.URIFromPath(fp)) 37953-} 37954- 37955-// ReadFile reads a text file specified by a workdir-relative path. 37956-func (w *Workdir) ReadFile(path string) ([]byte, error) { 37957- backoff := 1 * time.Millisecond 37958- for { 37959- b, err := ioutil.ReadFile(w.AbsPath(path)) 37960- if err != nil { 37961- if runtime.GOOS == "plan9" && strings.HasSuffix(err.Error(), " exclusive use file already open") { 37962- // Plan 9 enforces exclusive access to locked files. 37963- // Give the owner time to unlock it and retry. 37964- time.Sleep(backoff) 37965- backoff *= 2 37966- continue 37967- } 37968- return nil, err 37969- } 37970- return b, nil 37971- } 37972-} 37973- 37974-// RegexpSearch searches the file corresponding to path for the first position 37975-// matching re. 37976-func (w *Workdir) RegexpSearch(path string, re string) (protocol.Location, error) { 37977- content, err := w.ReadFile(path) 37978- if err != nil { 37979- return protocol.Location{}, err 37980- } 37981- mapper := protocol.NewMapper(w.URI(path).SpanURI(), content) 37982- return regexpLocation(mapper, re) 37983-} 37984- 37985-// RemoveFile removes a workdir-relative file path and notifies watchers of the 37986-// change. 37987-func (w *Workdir) RemoveFile(ctx context.Context, path string) error { 37988- fp := w.AbsPath(path) 37989- if err := robustio.RemoveAll(fp); err != nil { 37990- return fmt.Errorf("removing %q: %w", path, err) 37991- } 37992- 37993- return w.CheckForFileChanges(ctx) 37994-} 37995- 37996-// WriteFiles writes the text file content to workdir-relative paths and 37997-// notifies watchers of the changes. 37998-func (w *Workdir) WriteFiles(ctx context.Context, files map[string]string) error { 37999- for path, content := range files { 38000- fp := w.AbsPath(path) 38001- _, err := os.Stat(fp) 38002- if err != nil && !os.IsNotExist(err) { 38003- return fmt.Errorf("checking if %q exists: %w", path, err) 38004- } 38005- if err := writeFileData(path, []byte(content), w.RelativeTo); err != nil { 38006- return err 38007- } 38008- } 38009- return w.CheckForFileChanges(ctx) 38010-} 38011- 38012-// WriteFile writes text file content to a workdir-relative path and notifies 38013-// watchers of the change. 38014-func (w *Workdir) WriteFile(ctx context.Context, path, content string) error { 38015- return w.WriteFiles(ctx, map[string]string{path: content}) 38016-} 38017- 38018-func (w *Workdir) fileEvent(path string, changeType protocol.FileChangeType) protocol.FileEvent { 38019- return protocol.FileEvent{ 38020- URI: w.URI(path), 38021- Type: changeType, 38022- } 38023-} 38024- 38025-// RenameFile performs an on disk-renaming of the workdir-relative oldPath to 38026-// workdir-relative newPath, and notifies watchers of the changes. 38027-// 38028-// oldPath must either be a regular file or in the same directory as newPath. 38029-func (w *Workdir) RenameFile(ctx context.Context, oldPath, newPath string) error { 38030- oldAbs := w.AbsPath(oldPath) 38031- newAbs := w.AbsPath(newPath) 38032- 38033- // For os.Rename, “OS-specific restrictions may apply when oldpath and newpath 38034- // are in different directories.” If that applies here, we may fall back to 38035- // ReadFile, WriteFile, and RemoveFile to perform the rename non-atomically. 38036- // 38037- // However, the fallback path only works for regular files: renaming a 38038- // directory would be much more complex and isn't needed for our tests. 38039- fallbackOk := false 38040- if filepath.Dir(oldAbs) != filepath.Dir(newAbs) { 38041- fi, err := os.Stat(oldAbs) 38042- if err == nil && !fi.Mode().IsRegular() { 38043- return &os.PathError{ 38044- Op: "RenameFile", 38045- Path: oldPath, 38046- Err: fmt.Errorf("%w: file is not regular and not in the same directory as %s", os.ErrInvalid, newPath), 38047- } 38048- } 38049- fallbackOk = true 38050- } 38051- 38052- var renameErr error 38053- const debugFallback = false 38054- if fallbackOk && debugFallback { 38055- renameErr = fmt.Errorf("%w: debugging fallback path", os.ErrInvalid) 38056- } else { 38057- renameErr = robustio.Rename(oldAbs, newAbs) 38058- } 38059- if renameErr != nil { 38060- if !fallbackOk { 38061- return renameErr // The OS-specific Rename restrictions do not apply. 38062- } 38063- 38064- content, err := w.ReadFile(oldPath) 38065- if err != nil { 38066- // If we can't even read the file, the error from Rename may be accurate. 38067- return renameErr 38068- } 38069- fi, err := os.Stat(newAbs) 38070- if err == nil { 38071- if fi.IsDir() { 38072- // “If newpath already exists and is not a directory, Rename replaces it.” 38073- // But if it is a directory, maybe not? 38074- return renameErr 38075- } 38076- // On most platforms, Rename replaces the named file with a new file, 38077- // rather than overwriting the existing file it in place. Mimic that 38078- // behavior here. 38079- if err := robustio.RemoveAll(newAbs); err != nil { 38080- // Maybe we don't have permission to replace newPath? 38081- return renameErr 38082- } 38083- } else if !os.IsNotExist(err) { 38084- // If the destination path already exists or there is some problem with it, 38085- // the error from Rename may be accurate. 38086- return renameErr 38087- } 38088- if writeErr := writeFileData(newPath, []byte(content), w.RelativeTo); writeErr != nil { 38089- // At this point we have tried to actually write the file. 38090- // If it still doesn't exist, assume that the error from Rename was accurate: 38091- // for example, maybe we don't have permission to create the new path. 38092- // Otherwise, return the error from the write, which may indicate some 38093- // other problem (such as a full disk). 38094- if _, statErr := os.Stat(newAbs); !os.IsNotExist(statErr) { 38095- return writeErr 38096- } 38097- return renameErr 38098- } 38099- if err := robustio.RemoveAll(oldAbs); err != nil { 38100- // If we failed to remove the old file, that may explain the Rename error too. 38101- // Make a best effort to back out the write to the new path. 38102- robustio.RemoveAll(newAbs) 38103- return renameErr 38104- } 38105- } 38106- 38107- return w.CheckForFileChanges(ctx) 38108-} 38109- 38110-// ListFiles returns a new sorted list of the relative paths of files in dir, 38111-// recursively. 38112-func (w *Workdir) ListFiles(dir string) ([]string, error) { 38113- absDir := w.AbsPath(dir) 38114- var paths []string 38115- if err := filepath.Walk(absDir, func(fp string, info os.FileInfo, err error) error { 38116- if err != nil { 38117- return err 38118- } 38119- if info.Mode()&(fs.ModeDir|fs.ModeSymlink) == 0 { 38120- paths = append(paths, w.RelPath(fp)) 38121- } 38122- return nil 38123- }); err != nil { 38124- return nil, err 38125- } 38126- sort.Strings(paths) 38127- return paths, nil 38128-} 38129- 38130-// CheckForFileChanges walks the working directory and checks for any files 38131-// that have changed since the last poll. 38132-func (w *Workdir) CheckForFileChanges(ctx context.Context) error { 38133- evts, err := w.pollFiles() 38134- if err != nil { 38135- return err 38136- } 38137- if len(evts) == 0 { 38138- return nil 38139- } 38140- w.watcherMu.Lock() 38141- watchers := make([]func(context.Context, []protocol.FileEvent), len(w.watchers)) 38142- copy(watchers, w.watchers) 38143- w.watcherMu.Unlock() 38144- for _, w := range watchers { 38145- w(ctx, evts) 38146- } 38147- return nil 38148-} 38149- 38150-// pollFiles updates w.files and calculates FileEvents corresponding to file 38151-// state changes since the last poll. It does not call sendEvents. 38152-func (w *Workdir) pollFiles() ([]protocol.FileEvent, error) { 38153- w.fileMu.Lock() 38154- defer w.fileMu.Unlock() 38155- 38156- newFiles := make(map[string]fileID) 38157- var evts []protocol.FileEvent 38158- if err := filepath.Walk(string(w.RelativeTo), func(fp string, info os.FileInfo, err error) error { 38159- if err != nil { 38160- return err 38161- } 38162- // Skip directories and symbolic links (which may be links to directories). 38163- // 38164- // The latter matters for repos like Kubernetes, which use symlinks. 38165- if info.Mode()&(fs.ModeDir|fs.ModeSymlink) != 0 { 38166- return nil 38167- } 38168- 38169- // Opt: avoid reading the file if mtime is sufficently old to be reliable. 38170- // 38171- // If mtime is recent, it may not sufficiently identify the file contents: 38172- // a subsequent write could result in the same mtime. For these cases, we 38173- // must read the file contents. 38174- id := fileID{mtime: info.ModTime()} 38175- if time.Since(info.ModTime()) < 2*time.Second { 38176- data, err := ioutil.ReadFile(fp) 38177- if err != nil { 38178- return err 38179- } 38180- id.hash = hashFile(data) 38181- } 38182- path := w.RelPath(fp) 38183- newFiles[path] = id 38184- 38185- if w.files != nil { 38186- oldID, ok := w.files[path] 38187- delete(w.files, path) 38188- switch { 38189- case !ok: 38190- evts = append(evts, protocol.FileEvent{ 38191- URI: w.URI(path), 38192- Type: protocol.Created, 38193- }) 38194- case oldID != id: 38195- changed := true 38196- 38197- // Check whether oldID and id do not match because oldID was polled at 38198- // a recent enough to time such as to require hashing. 38199- // 38200- // In this case, read the content to check whether the file actually 38201- // changed. 38202- if oldID.mtime.Equal(id.mtime) && oldID.hash != "" && id.hash == "" { 38203- data, err := ioutil.ReadFile(fp) 38204- if err != nil { 38205- return err 38206- } 38207- if hashFile(data) == oldID.hash { 38208- changed = false 38209- } 38210- } 38211- if changed { 38212- evts = append(evts, protocol.FileEvent{ 38213- URI: w.URI(path), 38214- Type: protocol.Changed, 38215- }) 38216- } 38217- } 38218- } 38219- 38220- return nil 38221- }); err != nil { 38222- return nil, err 38223- } 38224- 38225- // Any remaining files must have been deleted. 38226- for path := range w.files { 38227- evts = append(evts, protocol.FileEvent{ 38228- URI: w.URI(path), 38229- Type: protocol.Deleted, 38230- }) 38231- } 38232- w.files = newFiles 38233- return evts, nil 38234-} 38235diff -urN a/gopls/internal/lsp/fake/workdir_test.go b/gopls/internal/lsp/fake/workdir_test.go 38236--- a/gopls/internal/lsp/fake/workdir_test.go 2000-01-01 00:00:00.000000000 -0000 38237+++ b/gopls/internal/lsp/fake/workdir_test.go 1970-01-01 00:00:00.000000000 +0000 38238@@ -1,220 +0,0 @@ 38239-// Copyright 2020 The Go Authors. All rights reserved. 38240-// Use of this source code is governed by a BSD-style 38241-// license that can be found in the LICENSE file. 38242- 38243-package fake 38244- 38245-import ( 38246- "context" 38247- "io/ioutil" 38248- "os" 38249- "sync" 38250- "testing" 38251- 38252- "github.com/google/go-cmp/cmp" 38253- "golang.org/x/tools/gopls/internal/lsp/protocol" 38254-) 38255- 38256-const sharedData = ` 38257--- go.mod -- 38258-go 1.12 38259--- nested/README.md -- 38260-Hello World! 38261-` 38262- 38263-// newWorkdir sets up a temporary Workdir with the given txtar-encoded content. 38264-// It also configures an eventBuffer to receive file event notifications. These 38265-// notifications are sent synchronously for each operation, such that once a 38266-// workdir file operation has returned the caller can expect that any relevant 38267-// file notifications are present in the buffer. 38268-// 38269-// It is the caller's responsibility to call the returned cleanup function. 38270-func newWorkdir(t *testing.T, txt string) (*Workdir, *eventBuffer, func()) { 38271- t.Helper() 38272- 38273- tmpdir, err := ioutil.TempDir("", "goplstest-workdir-") 38274- if err != nil { 38275- t.Fatal(err) 38276- } 38277- wd, err := NewWorkdir(tmpdir, UnpackTxt(txt)) 38278- if err != nil { 38279- t.Fatal(err) 38280- } 38281- cleanup := func() { 38282- if err := os.RemoveAll(tmpdir); err != nil { 38283- t.Error(err) 38284- } 38285- } 38286- 38287- buf := new(eventBuffer) 38288- wd.AddWatcher(buf.onEvents) 38289- return wd, buf, cleanup 38290-} 38291- 38292-// eventBuffer collects events from a file watcher. 38293-type eventBuffer struct { 38294- mu sync.Mutex 38295- events []protocol.FileEvent 38296-} 38297- 38298-// onEvents collects adds events to the buffer; to be used with Workdir.AddWatcher. 38299-func (c *eventBuffer) onEvents(_ context.Context, events []protocol.FileEvent) { 38300- c.mu.Lock() 38301- defer c.mu.Unlock() 38302- 38303- c.events = append(c.events, events...) 38304-} 38305- 38306-// take empties the buffer, returning its previous contents. 38307-func (c *eventBuffer) take() []protocol.FileEvent { 38308- c.mu.Lock() 38309- defer c.mu.Unlock() 38310- 38311- evts := c.events 38312- c.events = nil 38313- return evts 38314-} 38315- 38316-func TestWorkdir_ReadFile(t *testing.T) { 38317- wd, _, cleanup := newWorkdir(t, sharedData) 38318- defer cleanup() 38319- 38320- got, err := wd.ReadFile("nested/README.md") 38321- if err != nil { 38322- t.Fatal(err) 38323- } 38324- want := "Hello World!\n" 38325- if got := string(got); got != want { 38326- t.Errorf("reading workdir file, got %q, want %q", got, want) 38327- } 38328-} 38329- 38330-func TestWorkdir_WriteFile(t *testing.T) { 38331- wd, events, cleanup := newWorkdir(t, sharedData) 38332- defer cleanup() 38333- ctx := context.Background() 38334- 38335- tests := []struct { 38336- path string 38337- wantType protocol.FileChangeType 38338- }{ 38339- {"data.txt", protocol.Created}, 38340- {"nested/README.md", protocol.Changed}, 38341- } 38342- 38343- for _, test := range tests { 38344- if err := wd.WriteFile(ctx, test.path, "42"); err != nil { 38345- t.Fatal(err) 38346- } 38347- es := events.take() 38348- if got := len(es); got != 1 { 38349- t.Fatalf("len(events) = %d, want 1", got) 38350- } 38351- path := wd.URIToPath(es[0].URI) 38352- if path != test.path { 38353- t.Errorf("event path = %q, want %q", path, test.path) 38354- } 38355- if es[0].Type != test.wantType { 38356- t.Errorf("event type = %v, want %v", es[0].Type, test.wantType) 38357- } 38358- got, err := wd.ReadFile(test.path) 38359- if err != nil { 38360- t.Fatal(err) 38361- } 38362- want := "42" 38363- if got := string(got); got != want { 38364- t.Errorf("ws.ReadFile(%q) = %q, want %q", test.path, got, want) 38365- } 38366- } 38367-} 38368- 38369-// Test for file notifications following file operations. 38370-func TestWorkdir_FileWatching(t *testing.T) { 38371- wd, events, cleanup := newWorkdir(t, "") 38372- defer cleanup() 38373- ctx := context.Background() 38374- 38375- must := func(err error) { 38376- if err != nil { 38377- t.Fatal(err) 38378- } 38379- } 38380- 38381- type changeMap map[string]protocol.FileChangeType 38382- checkEvent := func(wantChanges changeMap) { 38383- gotChanges := make(changeMap) 38384- for _, e := range events.take() { 38385- gotChanges[wd.URIToPath(e.URI)] = e.Type 38386- } 38387- if diff := cmp.Diff(wantChanges, gotChanges); diff != "" { 38388- t.Errorf("mismatching file events (-want +got):\n%s", diff) 38389- } 38390- } 38391- 38392- must(wd.WriteFile(ctx, "foo.go", "package foo")) 38393- checkEvent(changeMap{"foo.go": protocol.Created}) 38394- 38395- must(wd.RenameFile(ctx, "foo.go", "bar.go")) 38396- checkEvent(changeMap{"foo.go": protocol.Deleted, "bar.go": protocol.Created}) 38397- 38398- must(wd.RemoveFile(ctx, "bar.go")) 38399- checkEvent(changeMap{"bar.go": protocol.Deleted}) 38400-} 38401- 38402-func TestWorkdir_CheckForFileChanges(t *testing.T) { 38403- t.Skip("broken on darwin-amd64-10_12") 38404- wd, events, cleanup := newWorkdir(t, sharedData) 38405- defer cleanup() 38406- ctx := context.Background() 38407- 38408- checkChange := func(wantPath string, wantType protocol.FileChangeType) { 38409- if err := wd.CheckForFileChanges(ctx); err != nil { 38410- t.Fatal(err) 38411- } 38412- ev := events.take() 38413- if len(ev) == 0 { 38414- t.Fatal("no file events received") 38415- } 38416- gotEvt := ev[0] 38417- gotPath := wd.URIToPath(gotEvt.URI) 38418- // Only check relative path and Type 38419- if gotPath != wantPath || gotEvt.Type != wantType { 38420- t.Errorf("file events: got %v, want {Path: %s, Type: %v}", gotEvt, wantPath, wantType) 38421- } 38422- } 38423- // Sleep some positive amount of time to ensure a distinct mtime. 38424- if err := writeFileData("go.mod", []byte("module foo.test\n"), wd.RelativeTo); err != nil { 38425- t.Fatal(err) 38426- } 38427- checkChange("go.mod", protocol.Changed) 38428- if err := writeFileData("newFile", []byte("something"), wd.RelativeTo); err != nil { 38429- t.Fatal(err) 38430- } 38431- checkChange("newFile", protocol.Created) 38432- fp := wd.AbsPath("newFile") 38433- if err := os.Remove(fp); err != nil { 38434- t.Fatal(err) 38435- } 38436- checkChange("newFile", protocol.Deleted) 38437-} 38438- 38439-func TestSplitModuleVersionPath(t *testing.T) { 38440- tests := []struct { 38441- path string 38442- wantModule, wantVersion, wantSuffix string 38443- }{ 38444- {"[email protected]/bar", "foo.com", "v1.2.3", "bar"}, 38445- {"foo.com/module@v1.2.3/bar", "foo.com/module", "v1.2.3", "bar"}, 38446- {"[email protected]", "foo.com", "v1.2.3", ""}, 38447- {"[email protected]", "std", "v1.14.0", ""}, 38448- {"another/module/path", "another/module/path", "", ""}, 38449- } 38450- 38451- for _, test := range tests { 38452- module, version, suffix := splitModuleVersionPath(test.path) 38453- if module != test.wantModule || version != test.wantVersion || suffix != test.wantSuffix { 38454- t.Errorf("splitModuleVersionPath(%q) =\n\t(%q, %q, %q)\nwant\n\t(%q, %q, %q)", 38455- test.path, module, version, suffix, test.wantModule, test.wantVersion, test.wantSuffix) 38456- } 38457- } 38458-} 38459diff -urN a/gopls/internal/lsp/fake/workdir_windows.go b/gopls/internal/lsp/fake/workdir_windows.go 38460--- a/gopls/internal/lsp/fake/workdir_windows.go 2000-01-01 00:00:00.000000000 -0000 38461+++ b/gopls/internal/lsp/fake/workdir_windows.go 1970-01-01 00:00:00.000000000 +0000 38462@@ -1,21 +0,0 @@ 38463-// Copyright 2021 The Go Authors. All rights reserved. 38464-// Use of this source code is governed by a BSD-style 38465-// license that can be found in the LICENSE file. 38466- 38467-package fake 38468- 38469-import ( 38470- "errors" 38471- "syscall" 38472-) 38473- 38474-func init() { 38475- // constants copied from GOROOT/src/internal/syscall/windows/syscall_windows.go 38476- const ( 38477- ERROR_LOCK_VIOLATION syscall.Errno = 33 38478- ) 38479- 38480- isWindowsErrLockViolation = func(err error) bool { 38481- return errors.Is(err, ERROR_LOCK_VIOLATION) 38482- } 38483-} 38484diff -urN a/gopls/internal/lsp/filecache/filecache.go b/gopls/internal/lsp/filecache/filecache.go 38485--- a/gopls/internal/lsp/filecache/filecache.go 2000-01-01 00:00:00.000000000 -0000 38486+++ b/gopls/internal/lsp/filecache/filecache.go 1970-01-01 00:00:00.000000000 +0000 38487@@ -1,369 +0,0 @@ 38488-// Copyright 2022 The Go Authors. All rights reserved. 38489-// Use of this source code is governed by a BSD-style 38490-// license that can be found in the LICENSE file. 38491- 38492-// The filecache package provides a file-based shared durable blob cache. 38493-// 38494-// The cache is a machine-global mapping from (kind string, key 38495-// [32]byte) to []byte, where kind is an identifier describing the 38496-// namespace or purpose (e.g. "analysis"), and key is a SHA-256 digest 38497-// of the recipe of the value. (It need not be the digest of the value 38498-// itself, so you can query the cache without knowing what value the 38499-// recipe would produce.) 38500-// 38501-// The space budget of the cache can be controlled by [SetBudget]. 38502-// Cache entries may be evicted at any time or in any order. 38503-// Note that "du -sh $GOPLSCACHE" may report a disk usage 38504-// figure that is rather larger (e.g. 50%) than the budget because 38505-// it rounds up partial disk blocks. 38506-// 38507-// The Get and Set operations are concurrency-safe. 38508-package filecache 38509- 38510-import ( 38511- "bytes" 38512- "crypto/sha256" 38513- "encoding/binary" 38514- "errors" 38515- "fmt" 38516- "io" 38517- "log" 38518- "os" 38519- "path/filepath" 38520- "sort" 38521- "sync" 38522- "sync/atomic" 38523- "time" 38524- 38525- "golang.org/x/tools/internal/lockedfile" 38526-) 38527- 38528-// Get retrieves from the cache and returns a newly allocated 38529-// copy of the value most recently supplied to Set(kind, key), 38530-// possibly by another process. 38531-// Get returns ErrNotFound if the value was not found. 38532-func Get(kind string, key [32]byte) ([]byte, error) { 38533- name := filename(kind, key) 38534- data, err := lockedfile.Read(name) 38535- if err != nil { 38536- if errors.Is(err, os.ErrNotExist) { 38537- return nil, ErrNotFound 38538- } 38539- return nil, err 38540- } 38541- 38542- // Verify that the Write was complete 38543- // by checking the recorded length. 38544- if len(data) < 8 { 38545- return nil, ErrNotFound // cache entry is incomplete 38546- } 38547- if length := binary.LittleEndian.Uint64(data); int(length) != len(data)-8 { 38548- return nil, ErrNotFound // cache entry is incomplete (or too long!) 38549- } 38550- data = data[8:] 38551- 38552- // Update file time for use by LRU eviction. 38553- // (This turns every read into a write operation. 38554- // If this is a performance problem, we should 38555- // touch the files aynchronously.) 38556- // 38557- // (Traditionally the access time would be updated 38558- // automatically, but for efficiency most POSIX systems have 38559- // for many years set the noatime mount option to avoid every 38560- // open or read operation entailing a metadata write.) 38561- now := time.Now() 38562- if err := os.Chtimes(name, now, now); err != nil { 38563- return nil, fmt.Errorf("failed to update access time: %w", err) 38564- } 38565- 38566- return data, nil 38567-} 38568- 38569-// ErrNotFound is the distinguished error 38570-// returned by Get when the key is not found. 38571-var ErrNotFound = fmt.Errorf("not found") 38572- 38573-// Set updates the value in the cache. 38574-func Set(kind string, key [32]byte, value []byte) error { 38575- name := filename(kind, key) 38576- if err := os.MkdirAll(filepath.Dir(name), 0700); err != nil { 38577- return err 38578- } 38579- 38580- // In the unlikely event of a short write (e.g. ENOSPC) 38581- // followed by process termination (e.g. a power cut), we 38582- // don't want a reader to see a short file, so we record 38583- // the expected length first and verify it in Get. 38584- var length [8]byte 38585- binary.LittleEndian.PutUint64(length[:], uint64(len(value))) 38586- header := bytes.NewReader(length[:]) 38587- payload := bytes.NewReader(value) 38588- 38589- // Windows doesn't support atomic rename--we tried MoveFile, 38590- // MoveFileEx, ReplaceFileEx, and SetFileInformationByHandle 38591- // of RenameFileInfo, all to no avail--so instead we use 38592- // advisory file locking, which is only about 2x slower even 38593- // on POSIX platforms with atomic rename. 38594- return lockedfile.Write(name, io.MultiReader(header, payload), 0600) 38595-} 38596- 38597-var budget int64 = 1e9 // 1GB 38598- 38599-// SetBudget sets a soft limit on disk usage of the cache (in bytes) 38600-// and returns the previous value. Supplying a negative value queries 38601-// the current value without changing it. 38602-// 38603-// If two gopls processes have different budgets, the one with the 38604-// lower budget will collect garbage more actively, but both will 38605-// observe the effect. 38606-func SetBudget(new int64) (old int64) { 38607- if new < 0 { 38608- return atomic.LoadInt64(&budget) 38609- } 38610- return atomic.SwapInt64(&budget, new) 38611-} 38612- 38613-// --- implementation ---- 38614- 38615-// filename returns the cache entry of the specified kind and key. 38616-// 38617-// A typical cache entry is a file name such as: 38618-// 38619-// $HOME/Library/Caches / gopls / VVVVVVVV / kind / KK / KKKK...KKKK 38620-// 38621-// The portions separated by spaces are as follows: 38622-// - The user's preferred cache directory; the default value varies by OS. 38623-// - The constant "gopls". 38624-// - The "version", 32 bits of the digest of the gopls executable. 38625-// - The kind or purpose of this cache subtree (e.g. "analysis"). 38626-// - The first 8 bits of the key, to avoid huge directories. 38627-// - The full 256 bits of the key. 38628-// 38629-// Once a file is written its contents are never modified, though it 38630-// may be atomically replaced or removed. 38631-// 38632-// New versions of gopls are free to reorganize the contents of the 38633-// version directory as needs evolve. But all versions of gopls must 38634-// in perpetuity treat the "gopls" directory in a common fashion. 38635-// 38636-// In particular, each gopls process attempts to garbage collect 38637-// the entire gopls directory so that newer binaries can clean up 38638-// after older ones: in the development cycle especially, new 38639-// new versions may be created frequently. 38640-func filename(kind string, key [32]byte) string { 38641- hex := fmt.Sprintf("%x", key) 38642- return filepath.Join(getCacheDir(), kind, hex[:2], hex) 38643-} 38644- 38645-// getCacheDir returns the persistent cache directory of all processes 38646-// running this version of the gopls executable. 38647-// 38648-// It must incorporate the hash of the executable so that we needn't 38649-// worry about incompatible changes to the file format or changes to 38650-// the algorithm that produced the index. 38651-func getCacheDir() string { 38652- cacheDirOnce.Do(func() { 38653- // Use user's preferred cache directory. 38654- userDir := os.Getenv("GOPLSCACHE") 38655- if userDir == "" { 38656- var err error 38657- userDir, err = os.UserCacheDir() 38658- if err != nil { 38659- userDir = os.TempDir() 38660- } 38661- } 38662- goplsDir := filepath.Join(userDir, "gopls") 38663- 38664- // UserCacheDir may return a nonexistent directory 38665- // (in which case we must create it, which may fail), 38666- // or it may return a non-writable directory, in 38667- // which case we should ideally respect the user's express 38668- // wishes (e.g. XDG_CACHE_HOME) and not write somewhere else. 38669- // Sadly UserCacheDir doesn't currently let us distinguish 38670- // such intent from accidental misconfiguraton such as HOME=/ 38671- // in a CI builder. So, we check whether the gopls subdirectory 38672- // can be created (or already exists) and not fall back to /tmp. 38673- // See also https://github.com/golang/go/issues/57638. 38674- if os.MkdirAll(goplsDir, 0700) != nil { 38675- goplsDir = filepath.Join(os.TempDir(), "gopls") 38676- } 38677- 38678- // Start the garbage collector. 38679- go gc(goplsDir) 38680- 38681- // Compute the hash of this executable (~20ms) and create a subdirectory. 38682- hash, err := hashExecutable() 38683- if err != nil { 38684- log.Fatalf("can't hash gopls executable: %v", err) 38685- } 38686- // Use only 32 bits of the digest to avoid unwieldy filenames. 38687- // It's not an adversarial situation. 38688- cacheDir = filepath.Join(goplsDir, fmt.Sprintf("%x", hash[:4])) 38689- if err := os.MkdirAll(cacheDir, 0700); err != nil { 38690- log.Fatalf("can't create cache: %v", err) 38691- } 38692- }) 38693- return cacheDir 38694-} 38695- 38696-var ( 38697- cacheDirOnce sync.Once 38698- cacheDir string // only accessed by getCacheDir 38699-) 38700- 38701-func hashExecutable() (hash [32]byte, err error) { 38702- exe, err := os.Executable() 38703- if err != nil { 38704- return hash, err 38705- } 38706- f, err := os.Open(exe) 38707- if err != nil { 38708- return hash, err 38709- } 38710- defer f.Close() 38711- h := sha256.New() 38712- if _, err := io.Copy(h, f); err != nil { 38713- return hash, fmt.Errorf("can't read executable: %w", err) 38714- } 38715- h.Sum(hash[:0]) 38716- return hash, nil 38717-} 38718- 38719-// gc runs forever, periodically deleting files from the gopls 38720-// directory until the space budget is no longer exceeded, and also 38721-// deleting files older than the maximum age, regardless of budget. 38722-// 38723-// One gopls process may delete garbage created by a different gopls 38724-// process, possibly running a different version of gopls, possibly 38725-// running concurrently. 38726-func gc(goplsDir string) { 38727- const period = 1 * time.Minute // period between collections 38728- // Sleep statDelay*batchSize between stats to smooth out I/O. 38729- // 38730- // The constants below were chosen using the following heuristics: 38731- // - 1GB of filecache is on the order of ~100-200k files, in which case 38732- // 100μs delay per file introduces 10-20s of additional walk time, less 38733- // than the 1m gc period. 38734- // - Processing batches of stats at once is much more efficient than 38735- // sleeping after every stat (due to OS optimizations). 38736- const statDelay = 100 * time.Microsecond // average delay between stats, to smooth out I/O 38737- const batchSize = 1000 // # of stats to process before sleeping 38738- const maxAge = 5 * 24 * time.Hour // max time since last access before file is deleted 38739- 38740- // The macOS filesystem is strikingly slow, at least on some machines. 38741- // /usr/bin/find achieves only about 25,000 stats per second 38742- // at full speed (no pause between items), meaning a large 38743- // cache may take several minutes to scan. 38744- // We must ensure that short-lived processes (crucially, 38745- // tests) are able to make progress sweeping garbage. 38746- // 38747- // (gopls' caches should never actually get this big in 38748- // practice: the example mentioned above resulted from a bug 38749- // that caused filecache to fail to delete any files.) 38750- 38751- const debug = false 38752- 38753- // Names of all directories found in first pass; nil thereafter. 38754- dirs := make(map[string]bool) 38755- 38756- for { 38757- // Enumerate all files in the cache. 38758- type item struct { 38759- path string 38760- stat os.FileInfo 38761- } 38762- var files []item 38763- start := time.Now() 38764- var total int64 // bytes 38765- _ = filepath.Walk(goplsDir, func(path string, stat os.FileInfo, err error) error { 38766- if err != nil { 38767- return nil // ignore errors 38768- } 38769- if stat.IsDir() { 38770- // Collect (potentially empty) directories. 38771- if dirs != nil { 38772- dirs[path] = true 38773- } 38774- } else { 38775- // Unconditionally delete files we haven't used in ages. 38776- // (We do this here, not in the second loop, so that we 38777- // perform age-based collection even in short-lived processes.) 38778- age := time.Since(stat.ModTime()) 38779- if age > maxAge { 38780- if debug { 38781- log.Printf("age: deleting stale file %s (%dB, age %v)", 38782- path, stat.Size(), age) 38783- } 38784- os.Remove(path) // ignore error 38785- } else { 38786- files = append(files, item{path, stat}) 38787- total += stat.Size() 38788- if debug && len(files)%1000 == 0 { 38789- log.Printf("filecache: checked %d files in %v", len(files), time.Since(start)) 38790- } 38791- if len(files)%batchSize == 0 { 38792- time.Sleep(batchSize * statDelay) 38793- } 38794- } 38795- } 38796- return nil 38797- }) 38798- 38799- // Sort oldest files first. 38800- sort.Slice(files, func(i, j int) bool { 38801- return files[i].stat.ModTime().Before(files[j].stat.ModTime()) 38802- }) 38803- 38804- // Delete oldest files until we're under budget. 38805- budget := atomic.LoadInt64(&budget) 38806- for _, file := range files { 38807- if total < budget { 38808- break 38809- } 38810- if debug { 38811- age := time.Since(file.stat.ModTime()) 38812- log.Printf("budget: deleting stale file %s (%dB, age %v)", 38813- file.path, file.stat.Size(), age) 38814- } 38815- os.Remove(file.path) // ignore error 38816- total -= file.stat.Size() 38817- } 38818- 38819- time.Sleep(period) 38820- 38821- // Once only, delete all directories. 38822- // This will succeed only for the empty ones, 38823- // and ensures that stale directories (whose 38824- // files have been deleted) are removed eventually. 38825- // They don't take up much space but they do slow 38826- // down the traversal. 38827- // 38828- // We do this after the sleep to minimize the 38829- // race against Set, which may create a directory 38830- // that is momentarily empty. 38831- // 38832- // (Test processes don't live that long, so 38833- // this may not be reached on the CI builders.) 38834- if dirs != nil { 38835- dirnames := make([]string, 0, len(dirs)) 38836- for dir := range dirs { 38837- dirnames = append(dirnames, dir) 38838- } 38839- dirs = nil 38840- 38841- // Descending length order => children before parents. 38842- sort.Slice(dirnames, func(i, j int) bool { 38843- return len(dirnames[i]) > len(dirnames[j]) 38844- }) 38845- var deleted int 38846- for _, dir := range dirnames { 38847- if os.Remove(dir) == nil { // ignore error 38848- deleted++ 38849- } 38850- } 38851- if debug { 38852- log.Printf("deleted %d empty directories", deleted) 38853- } 38854- } 38855- } 38856-} 38857diff -urN a/gopls/internal/lsp/filecache/filecache_test.go b/gopls/internal/lsp/filecache/filecache_test.go 38858--- a/gopls/internal/lsp/filecache/filecache_test.go 2000-01-01 00:00:00.000000000 -0000 38859+++ b/gopls/internal/lsp/filecache/filecache_test.go 1970-01-01 00:00:00.000000000 +0000 38860@@ -1,215 +0,0 @@ 38861-// Copyright 2022 The Go Authors. All rights reserved. 38862-// Use of this source code is governed by a BSD-style 38863-// license that can be found in the LICENSE file. 38864- 38865-package filecache_test 38866- 38867-// This file defines tests of the API of the filecache package. 38868-// 38869-// Some properties (e.g. garbage collection) cannot be exercised 38870-// through the API, so this test does not attempt to do so. 38871- 38872-import ( 38873- "bytes" 38874- cryptorand "crypto/rand" 38875- "fmt" 38876- "log" 38877- mathrand "math/rand" 38878- "os" 38879- "os/exec" 38880- "strconv" 38881- "testing" 38882- 38883- "golang.org/x/sync/errgroup" 38884- "golang.org/x/tools/gopls/internal/lsp/filecache" 38885-) 38886- 38887-func TestBasics(t *testing.T) { 38888- const kind = "TestBasics" 38889- key := uniqueKey() // never used before 38890- value := []byte("hello") 38891- 38892- // Get of a never-seen key returns not found. 38893- if _, err := filecache.Get(kind, key); err != filecache.ErrNotFound { 38894- t.Errorf("Get of random key returned err=%q, want not found", err) 38895- } 38896- 38897- // Set of a never-seen key and a small value succeeds. 38898- if err := filecache.Set(kind, key, value); err != nil { 38899- t.Errorf("Set failed: %v", err) 38900- } 38901- 38902- // Get of the key returns a copy of the value. 38903- if got, err := filecache.Get(kind, key); err != nil { 38904- t.Errorf("Get after Set failed: %v", err) 38905- } else if string(got) != string(value) { 38906- t.Errorf("Get after Set returned different value: got %q, want %q", got, value) 38907- } 38908- 38909- // The kind is effectively part of the key. 38910- if _, err := filecache.Get("different-kind", key); err != filecache.ErrNotFound { 38911- t.Errorf("Get with wrong kind returned err=%q, want not found", err) 38912- } 38913-} 38914- 38915-// TestConcurrency exercises concurrent access to the same entry. 38916-func TestConcurrency(t *testing.T) { 38917- const kind = "TestConcurrency" 38918- key := uniqueKey() 38919- const N = 100 // concurrency level 38920- 38921- // Construct N distinct values, each larger 38922- // than a typical 4KB OS file buffer page. 38923- var values [N][8192]byte 38924- for i := range values { 38925- if _, err := mathrand.Read(values[i][:]); err != nil { 38926- t.Fatalf("rand: %v", err) 38927- } 38928- } 38929- 38930- // get calls Get and verifies that the cache entry 38931- // matches one of the values passed to Set. 38932- get := func(mustBeFound bool) error { 38933- got, err := filecache.Get(kind, key) 38934- if err != nil { 38935- if err == filecache.ErrNotFound && !mustBeFound { 38936- return nil // not found 38937- } 38938- return err 38939- } 38940- for _, want := range values { 38941- if bytes.Equal(want[:], got) { 38942- return nil // a match 38943- } 38944- } 38945- return fmt.Errorf("Get returned a value that was never Set") 38946- } 38947- 38948- // Perform N concurrent calls to Set and Get. 38949- // All sets must succeed. 38950- // All gets must return nothing, or one of the Set values; 38951- // there is no third possibility. 38952- var group errgroup.Group 38953- for i := range values { 38954- i := i 38955- group.Go(func() error { return filecache.Set(kind, key, values[i][:]) }) 38956- group.Go(func() error { return get(false) }) 38957- } 38958- if err := group.Wait(); err != nil { 38959- t.Fatal(err) 38960- } 38961- 38962- // A final Get must report one of the values that was Set. 38963- if err := get(true); err != nil { 38964- t.Fatalf("final Get failed: %v", err) 38965- } 38966-} 38967- 38968-const ( 38969- testIPCKind = "TestIPC" 38970- testIPCValueA = "hello" 38971- testIPCValueB = "world" 38972-) 38973- 38974-// TestIPC exercises interprocess communication through the cache. 38975-// It calls Set(A) in the parent, { Get(A); Set(B) } in the child 38976-// process, then Get(B) in the parent. 38977-func TestIPC(t *testing.T) { 38978- keyA := uniqueKey() 38979- keyB := uniqueKey() 38980- value := []byte(testIPCValueA) 38981- 38982- // Set keyA. 38983- if err := filecache.Set(testIPCKind, keyA, value); err != nil { 38984- t.Fatalf("Set: %v", err) 38985- } 38986- 38987- // Call ipcChild in a child process, 38988- // passing it the keys in the environment 38989- // (quoted, to avoid NUL termination of C strings). 38990- // It will Get(A) then Set(B). 38991- cmd := exec.Command(os.Args[0], os.Args[1:]...) 38992- cmd.Env = append(os.Environ(), 38993- "ENTRYPOINT=ipcChild", 38994- fmt.Sprintf("KEYA=%q", keyA), 38995- fmt.Sprintf("KEYB=%q", keyB)) 38996- cmd.Stdout = os.Stderr 38997- cmd.Stderr = os.Stderr 38998- if err := cmd.Run(); err != nil { 38999- t.Fatal(err) 39000- } 39001- 39002- // Verify keyB. 39003- got, err := filecache.Get(testIPCKind, keyB) 39004- if err != nil { 39005- t.Fatal(err) 39006- } 39007- if string(got) != "world" { 39008- t.Fatalf("Get(keyB) = %q, want %q", got, "world") 39009- } 39010-} 39011- 39012-// We define our own main function so that portions of 39013-// some tests can run in a separate (child) process. 39014-func TestMain(m *testing.M) { 39015- switch os.Getenv("ENTRYPOINT") { 39016- case "ipcChild": 39017- ipcChild() 39018- default: 39019- os.Exit(m.Run()) 39020- } 39021-} 39022- 39023-// ipcChild is the portion of TestIPC that runs in a child process. 39024-func ipcChild() { 39025- getenv := func(name string) (key [32]byte) { 39026- s, _ := strconv.Unquote(os.Getenv(name)) 39027- copy(key[:], []byte(s)) 39028- return 39029- } 39030- 39031- // Verify key A. 39032- got, err := filecache.Get(testIPCKind, getenv("KEYA")) 39033- if err != nil || string(got) != testIPCValueA { 39034- log.Fatalf("child: Get(key) = %q, %v; want %q", got, err, testIPCValueA) 39035- } 39036- 39037- // Set key B. 39038- if err := filecache.Set(testIPCKind, getenv("KEYB"), []byte(testIPCValueB)); err != nil { 39039- log.Fatalf("child: Set(keyB) failed: %v", err) 39040- } 39041-} 39042- 39043-// uniqueKey returns a key that has never been used before. 39044-func uniqueKey() (key [32]byte) { 39045- if _, err := cryptorand.Read(key[:]); err != nil { 39046- log.Fatalf("rand: %v", err) 39047- } 39048- return 39049-} 39050- 39051-func BenchmarkUncontendedGet(b *testing.B) { 39052- const kind = "BenchmarkUncontendedGet" 39053- key := uniqueKey() 39054- 39055- var value [8192]byte 39056- if _, err := mathrand.Read(value[:]); err != nil { 39057- b.Fatalf("rand: %v", err) 39058- } 39059- if err := filecache.Set(kind, key, value[:]); err != nil { 39060- b.Fatal(err) 39061- } 39062- b.ResetTimer() 39063- 39064- var group errgroup.Group 39065- group.SetLimit(50) 39066- for i := 0; i < b.N; i++ { 39067- group.Go(func() error { 39068- _, err := filecache.Get(kind, key) 39069- return err 39070- }) 39071- } 39072- if err := group.Wait(); err != nil { 39073- b.Fatal(err) 39074- } 39075-} 39076diff -urN a/gopls/internal/lsp/folding_range.go b/gopls/internal/lsp/folding_range.go 39077--- a/gopls/internal/lsp/folding_range.go 2000-01-01 00:00:00.000000000 -0000 39078+++ b/gopls/internal/lsp/folding_range.go 1970-01-01 00:00:00.000000000 +0000 39079@@ -1,41 +0,0 @@ 39080-// Copyright 2019 The Go Authors. All rights reserved. 39081-// Use of this source code is governed by a BSD-style 39082-// license that can be found in the LICENSE file. 39083- 39084-package lsp 39085- 39086-import ( 39087- "context" 39088- 39089- "golang.org/x/tools/gopls/internal/lsp/protocol" 39090- "golang.org/x/tools/gopls/internal/lsp/source" 39091-) 39092- 39093-func (s *Server) foldingRange(ctx context.Context, params *protocol.FoldingRangeParams) ([]protocol.FoldingRange, error) { 39094- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 39095- defer release() 39096- if !ok { 39097- return nil, err 39098- } 39099- 39100- ranges, err := source.FoldingRange(ctx, snapshot, fh, snapshot.View().Options().LineFoldingOnly) 39101- if err != nil { 39102- return nil, err 39103- } 39104- return toProtocolFoldingRanges(ranges) 39105-} 39106- 39107-func toProtocolFoldingRanges(ranges []*source.FoldingRangeInfo) ([]protocol.FoldingRange, error) { 39108- result := make([]protocol.FoldingRange, 0, len(ranges)) 39109- for _, info := range ranges { 39110- rng := info.MappedRange.Range() 39111- result = append(result, protocol.FoldingRange{ 39112- StartLine: rng.Start.Line, 39113- StartCharacter: rng.Start.Character, 39114- EndLine: rng.End.Line, 39115- EndCharacter: rng.End.Character, 39116- Kind: string(info.Kind), 39117- }) 39118- } 39119- return result, nil 39120-} 39121diff -urN a/gopls/internal/lsp/format.go b/gopls/internal/lsp/format.go 39122--- a/gopls/internal/lsp/format.go 2000-01-01 00:00:00.000000000 -0000 39123+++ b/gopls/internal/lsp/format.go 1970-01-01 00:00:00.000000000 +0000 39124@@ -1,31 +0,0 @@ 39125-// Copyright 2018 The Go Authors. All rights reserved. 39126-// Use of this source code is governed by a BSD-style 39127-// license that can be found in the LICENSE file. 39128- 39129-package lsp 39130- 39131-import ( 39132- "context" 39133- 39134- "golang.org/x/tools/gopls/internal/lsp/mod" 39135- "golang.org/x/tools/gopls/internal/lsp/protocol" 39136- "golang.org/x/tools/gopls/internal/lsp/source" 39137- "golang.org/x/tools/gopls/internal/lsp/work" 39138-) 39139- 39140-func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) { 39141- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 39142- defer release() 39143- if !ok { 39144- return nil, err 39145- } 39146- switch snapshot.View().FileKind(fh) { 39147- case source.Mod: 39148- return mod.Format(ctx, snapshot, fh) 39149- case source.Go: 39150- return source.Format(ctx, snapshot, fh) 39151- case source.Work: 39152- return work.Format(ctx, snapshot, fh) 39153- } 39154- return nil, nil 39155-} 39156diff -urN a/gopls/internal/lsp/general.go b/gopls/internal/lsp/general.go 39157--- a/gopls/internal/lsp/general.go 2000-01-01 00:00:00.000000000 -0000 39158+++ b/gopls/internal/lsp/general.go 1970-01-01 00:00:00.000000000 +0000 39159@@ -1,619 +0,0 @@ 39160-// Copyright 2019 The Go Authors. All rights reserved. 39161-// Use of this source code is governed by a BSD-style 39162-// license that can be found in the LICENSE file. 39163- 39164-package lsp 39165- 39166-import ( 39167- "context" 39168- "encoding/json" 39169- "fmt" 39170- "log" 39171- "os" 39172- "path" 39173- "path/filepath" 39174- "sort" 39175- "strings" 39176- "sync" 39177- 39178- "golang.org/x/tools/gopls/internal/lsp/debug" 39179- "golang.org/x/tools/gopls/internal/lsp/protocol" 39180- "golang.org/x/tools/gopls/internal/lsp/source" 39181- "golang.org/x/tools/gopls/internal/span" 39182- "golang.org/x/tools/internal/bug" 39183- "golang.org/x/tools/internal/event" 39184- "golang.org/x/tools/internal/jsonrpc2" 39185-) 39186- 39187-func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) { 39188- s.stateMu.Lock() 39189- if s.state >= serverInitializing { 39190- defer s.stateMu.Unlock() 39191- return nil, fmt.Errorf("%w: initialize called while server in %v state", jsonrpc2.ErrInvalidRequest, s.state) 39192- } 39193- s.state = serverInitializing 39194- s.stateMu.Unlock() 39195- 39196- // For uniqueness, use the gopls PID rather than params.ProcessID (the client 39197- // pid). Some clients might start multiple gopls servers, though they 39198- // probably shouldn't. 39199- pid := os.Getpid() 39200- s.tempDir = filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.%s", pid, s.session.ID())) 39201- err := os.Mkdir(s.tempDir, 0700) 39202- if err != nil { 39203- // MkdirTemp could fail due to permissions issues. This is a problem with 39204- // the user's environment, but should not block gopls otherwise behaving. 39205- // All usage of s.tempDir should be predicated on having a non-empty 39206- // s.tempDir. 39207- event.Error(ctx, "creating temp dir", err) 39208- s.tempDir = "" 39209- } 39210- s.progress.SetSupportsWorkDoneProgress(params.Capabilities.Window.WorkDoneProgress) 39211- 39212- options := s.session.Options() 39213- defer func() { s.session.SetOptions(options) }() 39214- 39215- if err := s.handleOptionResults(ctx, source.SetOptions(options, params.InitializationOptions)); err != nil { 39216- return nil, err 39217- } 39218- options.ForClientCapabilities(params.Capabilities) 39219- 39220- if options.ShowBugReports { 39221- // Report the next bug that occurs on the server. 39222- bugCh := bug.Notify() 39223- go func() { 39224- b := <-bugCh 39225- msg := &protocol.ShowMessageParams{ 39226- Type: protocol.Error, 39227- Message: fmt.Sprintf("A bug occurred on the server: %s\nLocation:%s", b.Description, b.Key), 39228- } 39229- if err := s.eventuallyShowMessage(context.Background(), msg); err != nil { 39230- log.Printf("error showing bug: %v", err) 39231- } 39232- }() 39233- } 39234- 39235- folders := params.WorkspaceFolders 39236- if len(folders) == 0 { 39237- if params.RootURI != "" { 39238- folders = []protocol.WorkspaceFolder{{ 39239- URI: string(params.RootURI), 39240- Name: path.Base(params.RootURI.SpanURI().Filename()), 39241- }} 39242- } 39243- } 39244- for _, folder := range folders { 39245- uri := span.URIFromURI(folder.URI) 39246- if !uri.IsFile() { 39247- continue 39248- } 39249- s.pendingFolders = append(s.pendingFolders, folder) 39250- } 39251- // gopls only supports URIs with a file:// scheme, so if we have no 39252- // workspace folders with a supported scheme, fail to initialize. 39253- if len(folders) > 0 && len(s.pendingFolders) == 0 { 39254- return nil, fmt.Errorf("unsupported URI schemes: %v (gopls only supports file URIs)", folders) 39255- } 39256- 39257- var codeActionProvider interface{} = true 39258- if ca := params.Capabilities.TextDocument.CodeAction; len(ca.CodeActionLiteralSupport.CodeActionKind.ValueSet) > 0 { 39259- // If the client has specified CodeActionLiteralSupport, 39260- // send the code actions we support. 39261- // 39262- // Using CodeActionOptions is only valid if codeActionLiteralSupport is set. 39263- codeActionProvider = &protocol.CodeActionOptions{ 39264- CodeActionKinds: s.getSupportedCodeActions(), 39265- } 39266- } 39267- var renameOpts interface{} = true 39268- if r := params.Capabilities.TextDocument.Rename; r != nil && r.PrepareSupport { 39269- renameOpts = protocol.RenameOptions{ 39270- PrepareProvider: r.PrepareSupport, 39271- } 39272- } 39273- 39274- versionInfo := debug.VersionInfo() 39275- 39276- // golang/go#45732: Warn users who've installed sergi/go-diff@v1.2.0, since 39277- // it will corrupt the formatting of their files. 39278- for _, dep := range versionInfo.Deps { 39279- if dep.Path == "github.com/sergi/go-diff" && dep.Version == "v1.2.0" { 39280- if err := s.eventuallyShowMessage(ctx, &protocol.ShowMessageParams{ 39281- Message: `It looks like you have a bad gopls installation. 39282-Please reinstall gopls by running 'GO111MODULE=on go install golang.org/x/tools/gopls@latest'. 39283-See https://github.com/golang/go/issues/45732 for more information.`, 39284- Type: protocol.Error, 39285- }); err != nil { 39286- return nil, err 39287- } 39288- } 39289- } 39290- 39291- goplsVersion, err := json.Marshal(versionInfo) 39292- if err != nil { 39293- return nil, err 39294- } 39295- 39296- return &protocol.InitializeResult{ 39297- Capabilities: protocol.ServerCapabilities{ 39298- CallHierarchyProvider: &protocol.Or_ServerCapabilities_callHierarchyProvider{Value: true}, 39299- CodeActionProvider: codeActionProvider, 39300- CodeLensProvider: &protocol.CodeLensOptions{}, // must be non-nil to enable the code lens capability 39301- CompletionProvider: &protocol.CompletionOptions{ 39302- TriggerCharacters: []string{"."}, 39303- }, 39304- DefinitionProvider: &protocol.Or_ServerCapabilities_definitionProvider{Value: true}, 39305- TypeDefinitionProvider: &protocol.Or_ServerCapabilities_typeDefinitionProvider{Value: true}, 39306- ImplementationProvider: &protocol.Or_ServerCapabilities_implementationProvider{Value: true}, 39307- DocumentFormattingProvider: &protocol.Or_ServerCapabilities_documentFormattingProvider{Value: true}, 39308- DocumentSymbolProvider: &protocol.Or_ServerCapabilities_documentSymbolProvider{Value: true}, 39309- WorkspaceSymbolProvider: &protocol.Or_ServerCapabilities_workspaceSymbolProvider{Value: true}, 39310- ExecuteCommandProvider: &protocol.ExecuteCommandOptions{ 39311- Commands: options.SupportedCommands, 39312- }, 39313- FoldingRangeProvider: &protocol.Or_ServerCapabilities_foldingRangeProvider{Value: true}, 39314- HoverProvider: &protocol.Or_ServerCapabilities_hoverProvider{Value: true}, 39315- DocumentHighlightProvider: &protocol.Or_ServerCapabilities_documentHighlightProvider{Value: true}, 39316- DocumentLinkProvider: &protocol.DocumentLinkOptions{}, 39317- InlayHintProvider: protocol.InlayHintOptions{}, 39318- ReferencesProvider: &protocol.Or_ServerCapabilities_referencesProvider{Value: true}, 39319- RenameProvider: renameOpts, 39320- SelectionRangeProvider: &protocol.Or_ServerCapabilities_selectionRangeProvider{Value: true}, 39321- SemanticTokensProvider: protocol.SemanticTokensOptions{ 39322- Range: &protocol.Or_SemanticTokensOptions_range{Value: true}, 39323- Full: &protocol.Or_SemanticTokensOptions_full{Value: true}, 39324- Legend: protocol.SemanticTokensLegend{ 39325- TokenTypes: s.session.Options().SemanticTypes, 39326- TokenModifiers: s.session.Options().SemanticMods, 39327- }, 39328- }, 39329- SignatureHelpProvider: &protocol.SignatureHelpOptions{ 39330- TriggerCharacters: []string{"(", ","}, 39331- }, 39332- TextDocumentSync: &protocol.TextDocumentSyncOptions{ 39333- Change: protocol.Incremental, 39334- OpenClose: true, 39335- Save: &protocol.SaveOptions{ 39336- IncludeText: false, 39337- }, 39338- }, 39339- Workspace: &protocol.Workspace6Gn{ 39340- WorkspaceFolders: &protocol.WorkspaceFolders5Gn{ 39341- Supported: true, 39342- ChangeNotifications: "workspace/didChangeWorkspaceFolders", 39343- }, 39344- }, 39345- }, 39346- ServerInfo: &protocol.PServerInfoMsg_initialize{ 39347- Name: "gopls", 39348- Version: string(goplsVersion), 39349- }, 39350- }, nil 39351-} 39352- 39353-func (s *Server) initialized(ctx context.Context, params *protocol.InitializedParams) error { 39354- s.stateMu.Lock() 39355- if s.state >= serverInitialized { 39356- defer s.stateMu.Unlock() 39357- return fmt.Errorf("%w: initialized called while server in %v state", jsonrpc2.ErrInvalidRequest, s.state) 39358- } 39359- s.state = serverInitialized 39360- s.stateMu.Unlock() 39361- 39362- for _, not := range s.notifications { 39363- s.client.ShowMessage(ctx, not) 39364- } 39365- s.notifications = nil 39366- 39367- options := s.session.Options() 39368- defer func() { s.session.SetOptions(options) }() 39369- 39370- if err := s.addFolders(ctx, s.pendingFolders); err != nil { 39371- return err 39372- } 39373- s.pendingFolders = nil 39374- s.checkViewGoVersions() 39375- 39376- var registrations []protocol.Registration 39377- if options.ConfigurationSupported && options.DynamicConfigurationSupported { 39378- registrations = append(registrations, protocol.Registration{ 39379- ID: "workspace/didChangeConfiguration", 39380- Method: "workspace/didChangeConfiguration", 39381- }) 39382- } 39383- if len(registrations) > 0 { 39384- if err := s.client.RegisterCapability(ctx, &protocol.RegistrationParams{ 39385- Registrations: registrations, 39386- }); err != nil { 39387- return err 39388- } 39389- } 39390- return nil 39391-} 39392- 39393-// GoVersionTable maps Go versions to the gopls version in which support will 39394-// be deprecated, and the final gopls version supporting them without warnings. 39395-// Keep this in sync with gopls/README.md 39396-// 39397-// Must be sorted in ascending order of Go version. 39398-// 39399-// Mutable for testing. 39400-var GoVersionTable = []GoVersionSupport{ 39401- {12, "", "v0.7.5"}, 39402- {15, "v0.11.0", "v0.9.5"}, 39403-} 39404- 39405-// GoVersionSupport holds information about end-of-life Go version support. 39406-type GoVersionSupport struct { 39407- GoVersion int 39408- DeprecatedVersion string // if unset, the version is already deprecated 39409- InstallGoplsVersion string 39410-} 39411- 39412-// OldestSupportedGoVersion is the last X in Go 1.X that this version of gopls 39413-// supports. 39414-func OldestSupportedGoVersion() int { 39415- return GoVersionTable[len(GoVersionTable)-1].GoVersion + 1 39416-} 39417- 39418-// versionMessage returns the warning/error message to display if the user is 39419-// on the given Go version, if any. The goVersion variable is the X in Go 1.X. 39420-// 39421-// If goVersion is invalid (< 0), it returns "", 0. 39422-func versionMessage(goVersion int) (string, protocol.MessageType) { 39423- if goVersion < 0 { 39424- return "", 0 39425- } 39426- 39427- for _, v := range GoVersionTable { 39428- if goVersion <= v.GoVersion { 39429- var msgBuilder strings.Builder 39430- 39431- mType := protocol.Error 39432- fmt.Fprintf(&msgBuilder, "Found Go version 1.%d", goVersion) 39433- if v.DeprecatedVersion != "" { 39434- // not deprecated yet, just a warning 39435- fmt.Fprintf(&msgBuilder, ", which will be unsupported by gopls %s. ", v.DeprecatedVersion) 39436- mType = protocol.Warning 39437- } else { 39438- fmt.Fprint(&msgBuilder, ", which is not supported by this version of gopls. ") 39439- } 39440- fmt.Fprintf(&msgBuilder, "Please upgrade to Go 1.%d or later and reinstall gopls. ", OldestSupportedGoVersion()) 39441- fmt.Fprintf(&msgBuilder, "If you can't upgrade and want this message to go away, please install gopls %s. ", v.InstallGoplsVersion) 39442- fmt.Fprint(&msgBuilder, "See https://go.dev/s/gopls-support-policy for more details.") 39443- 39444- return msgBuilder.String(), mType 39445- } 39446- } 39447- return "", 0 39448-} 39449- 39450-// checkViewGoVersions checks whether any Go version used by a view is too old, 39451-// raising a showMessage notification if so. 39452-// 39453-// It should be called after views change. 39454-func (s *Server) checkViewGoVersions() { 39455- oldestVersion := -1 39456- for _, view := range s.session.Views() { 39457- viewVersion := view.GoVersion() 39458- if oldestVersion == -1 || viewVersion < oldestVersion { 39459- oldestVersion = viewVersion 39460- } 39461- } 39462- 39463- if msg, mType := versionMessage(oldestVersion); msg != "" { 39464- s.eventuallyShowMessage(context.Background(), &protocol.ShowMessageParams{ 39465- Type: mType, 39466- Message: msg, 39467- }) 39468- } 39469-} 39470- 39471-func (s *Server) addFolders(ctx context.Context, folders []protocol.WorkspaceFolder) error { 39472- originalViews := len(s.session.Views()) 39473- viewErrors := make(map[span.URI]error) 39474- 39475- var ndiagnose sync.WaitGroup // number of unfinished diagnose calls 39476- if s.session.Options().VerboseWorkDoneProgress { 39477- work := s.progress.Start(ctx, DiagnosticWorkTitle(FromInitialWorkspaceLoad), "Calculating diagnostics for initial workspace load...", nil, nil) 39478- defer func() { 39479- go func() { 39480- ndiagnose.Wait() 39481- work.End(ctx, "Done.") 39482- }() 39483- }() 39484- } 39485- // Only one view gets to have a workspace. 39486- var nsnapshots sync.WaitGroup // number of unfinished snapshot initializations 39487- for _, folder := range folders { 39488- uri := span.URIFromURI(folder.URI) 39489- // Ignore non-file URIs. 39490- if !uri.IsFile() { 39491- continue 39492- } 39493- work := s.progress.Start(ctx, "Setting up workspace", "Loading packages...", nil, nil) 39494- snapshot, release, err := s.addView(ctx, folder.Name, uri) 39495- if err != nil { 39496- if err == source.ErrViewExists { 39497- continue 39498- } 39499- viewErrors[uri] = err 39500- work.End(ctx, fmt.Sprintf("Error loading packages: %s", err)) 39501- continue 39502- } 39503- // Inv: release() must be called once. 39504- 39505- // Initialize snapshot asynchronously. 39506- initialized := make(chan struct{}) 39507- nsnapshots.Add(1) 39508- go func() { 39509- snapshot.AwaitInitialized(ctx) 39510- work.End(ctx, "Finished loading packages.") 39511- nsnapshots.Done() 39512- close(initialized) // signal 39513- }() 39514- 39515- // Diagnose the newly created view asynchronously. 39516- ndiagnose.Add(1) 39517- go func() { 39518- s.diagnoseDetached(snapshot) 39519- <-initialized 39520- release() 39521- ndiagnose.Done() 39522- }() 39523- } 39524- 39525- // Wait for snapshots to be initialized so that all files are known. 39526- // (We don't need to wait for diagnosis to finish.) 39527- nsnapshots.Wait() 39528- 39529- // Register for file watching notifications, if they are supported. 39530- if err := s.updateWatchedDirectories(ctx); err != nil { 39531- event.Error(ctx, "failed to register for file watching notifications", err) 39532- } 39533- 39534- if len(viewErrors) > 0 { 39535- errMsg := fmt.Sprintf("Error loading workspace folders (expected %v, got %v)\n", len(folders), len(s.session.Views())-originalViews) 39536- for uri, err := range viewErrors { 39537- errMsg += fmt.Sprintf("failed to load view for %s: %v\n", uri, err) 39538- } 39539- return s.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 39540- Type: protocol.Error, 39541- Message: errMsg, 39542- }) 39543- } 39544- return nil 39545-} 39546- 39547-// updateWatchedDirectories compares the current set of directories to watch 39548-// with the previously registered set of directories. If the set of directories 39549-// has changed, we unregister and re-register for file watching notifications. 39550-// updatedSnapshots is the set of snapshots that have been updated. 39551-func (s *Server) updateWatchedDirectories(ctx context.Context) error { 39552- patterns := s.session.FileWatchingGlobPatterns(ctx) 39553- 39554- s.watchedGlobPatternsMu.Lock() 39555- defer s.watchedGlobPatternsMu.Unlock() 39556- 39557- // Nothing to do if the set of workspace directories is unchanged. 39558- if equalURISet(s.watchedGlobPatterns, patterns) { 39559- return nil 39560- } 39561- 39562- // If the set of directories to watch has changed, register the updates and 39563- // unregister the previously watched directories. This ordering avoids a 39564- // period where no files are being watched. Still, if a user makes on-disk 39565- // changes before these updates are complete, we may miss them for the new 39566- // directories. 39567- prevID := s.watchRegistrationCount - 1 39568- if err := s.registerWatchedDirectoriesLocked(ctx, patterns); err != nil { 39569- return err 39570- } 39571- if prevID >= 0 { 39572- return s.client.UnregisterCapability(ctx, &protocol.UnregistrationParams{ 39573- Unregisterations: []protocol.Unregistration{{ 39574- ID: watchedFilesCapabilityID(prevID), 39575- Method: "workspace/didChangeWatchedFiles", 39576- }}, 39577- }) 39578- } 39579- return nil 39580-} 39581- 39582-func watchedFilesCapabilityID(id int) string { 39583- return fmt.Sprintf("workspace/didChangeWatchedFiles-%d", id) 39584-} 39585- 39586-func equalURISet(m1, m2 map[string]struct{}) bool { 39587- if len(m1) != len(m2) { 39588- return false 39589- } 39590- for k := range m1 { 39591- _, ok := m2[k] 39592- if !ok { 39593- return false 39594- } 39595- } 39596- return true 39597-} 39598- 39599-// registerWatchedDirectoriesLocked sends the workspace/didChangeWatchedFiles 39600-// registrations to the client and updates s.watchedDirectories. 39601-func (s *Server) registerWatchedDirectoriesLocked(ctx context.Context, patterns map[string]struct{}) error { 39602- if !s.session.Options().DynamicWatchedFilesSupported { 39603- return nil 39604- } 39605- for k := range s.watchedGlobPatterns { 39606- delete(s.watchedGlobPatterns, k) 39607- } 39608- var watchers []protocol.FileSystemWatcher 39609- val := protocol.WatchChange | protocol.WatchDelete | protocol.WatchCreate 39610- for pattern := range patterns { 39611- watchers = append(watchers, protocol.FileSystemWatcher{ 39612- GlobPattern: pattern, 39613- Kind: &val, 39614- }) 39615- } 39616- 39617- if err := s.client.RegisterCapability(ctx, &protocol.RegistrationParams{ 39618- Registrations: []protocol.Registration{{ 39619- ID: watchedFilesCapabilityID(s.watchRegistrationCount), 39620- Method: "workspace/didChangeWatchedFiles", 39621- RegisterOptions: protocol.DidChangeWatchedFilesRegistrationOptions{ 39622- Watchers: watchers, 39623- }, 39624- }}, 39625- }); err != nil { 39626- return err 39627- } 39628- s.watchRegistrationCount++ 39629- 39630- for k, v := range patterns { 39631- s.watchedGlobPatterns[k] = v 39632- } 39633- return nil 39634-} 39635- 39636-func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI, o *source.Options) error { 39637- if !s.session.Options().ConfigurationSupported { 39638- return nil 39639- } 39640- configs, err := s.client.Configuration(ctx, &protocol.ParamConfiguration{ 39641- Items: []protocol.ConfigurationItem{{ 39642- ScopeURI: string(folder), 39643- Section: "gopls", 39644- }}, 39645- }, 39646- ) 39647- if err != nil { 39648- return fmt.Errorf("failed to get workspace configuration from client (%s): %v", folder, err) 39649- } 39650- for _, config := range configs { 39651- if err := s.handleOptionResults(ctx, source.SetOptions(o, config)); err != nil { 39652- return err 39653- } 39654- } 39655- return nil 39656-} 39657- 39658-func (s *Server) eventuallyShowMessage(ctx context.Context, msg *protocol.ShowMessageParams) error { 39659- s.stateMu.Lock() 39660- defer s.stateMu.Unlock() 39661- if s.state == serverInitialized { 39662- return s.client.ShowMessage(ctx, msg) 39663- } 39664- s.notifications = append(s.notifications, msg) 39665- return nil 39666-} 39667- 39668-func (s *Server) handleOptionResults(ctx context.Context, results source.OptionResults) error { 39669- var warnings, errors []string 39670- for _, result := range results { 39671- switch result.Error.(type) { 39672- case nil: 39673- // nothing to do 39674- case *source.SoftError: 39675- warnings = append(warnings, result.Error.Error()) 39676- default: 39677- errors = append(errors, result.Error.Error()) 39678- } 39679- } 39680- 39681- // Sort messages, but put errors first. 39682- // 39683- // Having stable content for the message allows clients to de-duplicate. This 39684- // matters because we may send duplicate warnings for clients that support 39685- // dynamic configuration: one for the initial settings, and then more for the 39686- // individual view settings. 39687- var msgs []string 39688- msgType := protocol.Warning 39689- if len(errors) > 0 { 39690- msgType = protocol.Error 39691- sort.Strings(errors) 39692- msgs = append(msgs, errors...) 39693- } 39694- if len(warnings) > 0 { 39695- sort.Strings(warnings) 39696- msgs = append(msgs, warnings...) 39697- } 39698- 39699- if len(msgs) > 0 { 39700- // Settings 39701- combined := "Invalid settings: " + strings.Join(msgs, "; ") 39702- params := &protocol.ShowMessageParams{ 39703- Type: msgType, 39704- Message: combined, 39705- } 39706- return s.eventuallyShowMessage(ctx, params) 39707- } 39708- 39709- return nil 39710-} 39711- 39712-// beginFileRequest checks preconditions for a file-oriented request and routes 39713-// it to a snapshot. 39714-// We don't want to return errors for benign conditions like wrong file type, 39715-// so callers should do if !ok { return err } rather than if err != nil. 39716-// The returned cleanup function is non-nil even in case of false/error result. 39717-func (s *Server) beginFileRequest(ctx context.Context, pURI protocol.DocumentURI, expectKind source.FileKind) (source.Snapshot, source.FileHandle, bool, func(), error) { 39718- uri := pURI.SpanURI() 39719- if !uri.IsFile() { 39720- // Not a file URI. Stop processing the request, but don't return an error. 39721- return nil, nil, false, func() {}, nil 39722- } 39723- view, err := s.session.ViewOf(uri) 39724- if err != nil { 39725- return nil, nil, false, func() {}, err 39726- } 39727- snapshot, release, err := view.Snapshot() 39728- if err != nil { 39729- return nil, nil, false, func() {}, err 39730- } 39731- fh, err := snapshot.GetFile(ctx, uri) 39732- if err != nil { 39733- release() 39734- return nil, nil, false, func() {}, err 39735- } 39736- if expectKind != source.UnknownKind && view.FileKind(fh) != expectKind { 39737- // Wrong kind of file. Nothing to do. 39738- release() 39739- return nil, nil, false, func() {}, nil 39740- } 39741- return snapshot, fh, true, release, nil 39742-} 39743- 39744-// shutdown implements the 'shutdown' LSP handler. It releases resources 39745-// associated with the server and waits for all ongoing work to complete. 39746-func (s *Server) shutdown(ctx context.Context) error { 39747- s.stateMu.Lock() 39748- defer s.stateMu.Unlock() 39749- if s.state < serverInitialized { 39750- event.Log(ctx, "server shutdown without initialization") 39751- } 39752- if s.state != serverShutDown { 39753- // drop all the active views 39754- s.session.Shutdown(ctx) 39755- s.state = serverShutDown 39756- if s.tempDir != "" { 39757- if err := os.RemoveAll(s.tempDir); err != nil { 39758- event.Error(ctx, "removing temp dir", err) 39759- } 39760- } 39761- } 39762- return nil 39763-} 39764- 39765-func (s *Server) exit(ctx context.Context) error { 39766- s.stateMu.Lock() 39767- defer s.stateMu.Unlock() 39768- 39769- s.client.Close() 39770- 39771- if s.state != serverShutDown { 39772- // TODO: We should be able to do better than this. 39773- os.Exit(1) 39774- } 39775- // we don't terminate the process on a normal exit, we just allow it to 39776- // close naturally if needed after the connection is closed. 39777- return nil 39778-} 39779diff -urN a/gopls/internal/lsp/general_test.go b/gopls/internal/lsp/general_test.go 39780--- a/gopls/internal/lsp/general_test.go 2000-01-01 00:00:00.000000000 -0000 39781+++ b/gopls/internal/lsp/general_test.go 1970-01-01 00:00:00.000000000 +0000 39782@@ -1,44 +0,0 @@ 39783-// Copyright 2022 The Go Authors. All rights reserved. 39784-// Use of this source code is governed by a BSD-style 39785-// license that can be found in the LICENSE file. 39786- 39787-package lsp 39788- 39789-import ( 39790- "strings" 39791- "testing" 39792- 39793- "golang.org/x/tools/gopls/internal/lsp/protocol" 39794-) 39795- 39796-func TestVersionMessage(t *testing.T) { 39797- tests := []struct { 39798- goVersion int 39799- wantContains []string // string fragments that we expect to see 39800- wantType protocol.MessageType 39801- }{ 39802- {-1, nil, 0}, 39803- {12, []string{"1.12", "not supported", "upgrade to Go 1.16", "install gopls v0.7.5"}, protocol.Error}, 39804- {13, []string{"1.13", "will be unsupported by gopls v0.11.0", "upgrade to Go 1.16", "install gopls v0.9.5"}, protocol.Warning}, 39805- {15, []string{"1.15", "will be unsupported by gopls v0.11.0", "upgrade to Go 1.16", "install gopls v0.9.5"}, protocol.Warning}, 39806- {16, nil, 0}, 39807- } 39808- 39809- for _, test := range tests { 39810- gotMsg, gotType := versionMessage(test.goVersion) 39811- 39812- if len(test.wantContains) == 0 && gotMsg != "" { 39813- t.Errorf("versionMessage(%d) = %q, want \"\"", test.goVersion, gotMsg) 39814- } 39815- 39816- for _, want := range test.wantContains { 39817- if !strings.Contains(gotMsg, want) { 39818- t.Errorf("versionMessage(%d) = %q, want containing %q", test.goVersion, gotMsg, want) 39819- } 39820- } 39821- 39822- if gotType != test.wantType { 39823- t.Errorf("versionMessage(%d) = returned message type %d, want %d", test.goVersion, gotType, test.wantType) 39824- } 39825- } 39826-} 39827diff -urN a/gopls/internal/lsp/glob/glob.go b/gopls/internal/lsp/glob/glob.go 39828--- a/gopls/internal/lsp/glob/glob.go 2000-01-01 00:00:00.000000000 -0000 39829+++ b/gopls/internal/lsp/glob/glob.go 1970-01-01 00:00:00.000000000 +0000 39830@@ -1,349 +0,0 @@ 39831-// Copyright 2023 The Go Authors. All rights reserved. 39832-// Use of this source code is governed by a BSD-style 39833-// license that can be found in the LICENSE file. 39834- 39835-// Package glob implements an LSP-compliant glob pattern matcher for testing. 39836-package glob 39837- 39838-import ( 39839- "errors" 39840- "fmt" 39841- "strings" 39842- "unicode/utf8" 39843-) 39844- 39845-// A Glob is an LSP-compliant glob pattern, as defined by the spec: 39846-// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentFilter 39847-// 39848-// NOTE: this implementation is currently only intended for testing. In order 39849-// to make it production ready, we'd need to: 39850-// - verify it against the VS Code implementation 39851-// - add more tests 39852-// - microbenchmark, likely avoiding the element interface 39853-// - resolve the question of what is meant by "character". If it's a UTF-16 39854-// code (as we suspect) it'll be a bit more work. 39855-// 39856-// Quoting from the spec: 39857-// Glob patterns can have the following syntax: 39858-// - `*` to match one or more characters in a path segment 39859-// - `?` to match on one character in a path segment 39860-// - `**` to match any number of path segments, including none 39861-// - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` 39862-// matches all TypeScript and JavaScript files) 39863-// - `[]` to declare a range of characters to match in a path segment 39864-// (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) 39865-// - `[!...]` to negate a range of characters to match in a path segment 39866-// (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but 39867-// not `example.0`) 39868-// 39869-// Expanding on this: 39870-// - '/' matches one or more literal slashes. 39871-// - any other character matches itself literally. 39872-type Glob struct { 39873- elems []element // pattern elements 39874-} 39875- 39876-// Parse builds a Glob for the given pattern, returning an error if the pattern 39877-// is invalid. 39878-func Parse(pattern string) (*Glob, error) { 39879- g, _, err := parse(pattern, false) 39880- return g, err 39881-} 39882- 39883-func parse(pattern string, nested bool) (*Glob, string, error) { 39884- g := new(Glob) 39885- for len(pattern) > 0 { 39886- switch pattern[0] { 39887- case '/': 39888- pattern = pattern[1:] 39889- g.elems = append(g.elems, slash{}) 39890- 39891- case '*': 39892- if len(pattern) > 1 && pattern[1] == '*' { 39893- if (len(g.elems) > 0 && g.elems[len(g.elems)-1] != slash{}) || (len(pattern) > 2 && pattern[2] != '/') { 39894- return nil, "", errors.New("** may only be adjacent to '/'") 39895- } 39896- pattern = pattern[2:] 39897- g.elems = append(g.elems, starStar{}) 39898- break 39899- } 39900- pattern = pattern[1:] 39901- g.elems = append(g.elems, star{}) 39902- 39903- case '?': 39904- pattern = pattern[1:] 39905- g.elems = append(g.elems, anyChar{}) 39906- 39907- case '{': 39908- var gs group 39909- for pattern[0] != '}' { 39910- pattern = pattern[1:] 39911- g, pat, err := parse(pattern, true) 39912- if err != nil { 39913- return nil, "", err 39914- } 39915- if len(pat) == 0 { 39916- return nil, "", errors.New("unmatched '{'") 39917- } 39918- pattern = pat 39919- gs = append(gs, g) 39920- } 39921- pattern = pattern[1:] 39922- g.elems = append(g.elems, gs) 39923- 39924- case '}', ',': 39925- if nested { 39926- return g, pattern, nil 39927- } 39928- pattern = g.parseLiteral(pattern, false) 39929- 39930- case '[': 39931- pattern = pattern[1:] 39932- if len(pattern) == 0 { 39933- return nil, "", errBadRange 39934- } 39935- negate := false 39936- if pattern[0] == '!' { 39937- pattern = pattern[1:] 39938- negate = true 39939- } 39940- low, sz, err := readRangeRune(pattern) 39941- if err != nil { 39942- return nil, "", err 39943- } 39944- pattern = pattern[sz:] 39945- if len(pattern) == 0 || pattern[0] != '-' { 39946- return nil, "", errBadRange 39947- } 39948- pattern = pattern[1:] 39949- high, sz, err := readRangeRune(pattern) 39950- if err != nil { 39951- return nil, "", err 39952- } 39953- pattern = pattern[sz:] 39954- if len(pattern) == 0 || pattern[0] != ']' { 39955- return nil, "", errBadRange 39956- } 39957- pattern = pattern[1:] 39958- g.elems = append(g.elems, charRange{negate, low, high}) 39959- 39960- default: 39961- pattern = g.parseLiteral(pattern, nested) 39962- } 39963- } 39964- return g, "", nil 39965-} 39966- 39967-// helper for decoding a rune in range elements, e.g. [a-z] 39968-func readRangeRune(input string) (rune, int, error) { 39969- r, sz := utf8.DecodeRuneInString(input) 39970- var err error 39971- if r == utf8.RuneError { 39972- // See the documentation for DecodeRuneInString. 39973- switch sz { 39974- case 0: 39975- err = errBadRange 39976- case 1: 39977- err = errInvalidUTF8 39978- } 39979- } 39980- return r, sz, err 39981-} 39982- 39983-var ( 39984- errBadRange = errors.New("'[' patterns must be of the form [x-y]") 39985- errInvalidUTF8 = errors.New("invalid UTF-8 encoding") 39986-) 39987- 39988-func (g *Glob) parseLiteral(pattern string, nested bool) string { 39989- var specialChars string 39990- if nested { 39991- specialChars = "*?{[/}," 39992- } else { 39993- specialChars = "*?{[/" 39994- } 39995- end := strings.IndexAny(pattern, specialChars) 39996- if end == -1 { 39997- end = len(pattern) 39998- } 39999- g.elems = append(g.elems, literal(pattern[:end])) 40000- return pattern[end:] 40001-} 40002- 40003-func (g *Glob) String() string { 40004- var b strings.Builder 40005- for _, e := range g.elems { 40006- fmt.Fprint(&b, e) 40007- } 40008- return b.String() 40009-} 40010- 40011-// element holds a glob pattern element, as defined below. 40012-type element fmt.Stringer 40013- 40014-// element types. 40015-type ( 40016- slash struct{} // One or more '/' separators 40017- literal string // string literal, not containing /, *, ?, {}, or [] 40018- star struct{} // * 40019- anyChar struct{} // ? 40020- starStar struct{} // ** 40021- group []*Glob // {foo, bar, ...} grouping 40022- charRange struct { // [a-z] character range 40023- negate bool 40024- low, high rune 40025- } 40026-) 40027- 40028-func (s slash) String() string { return "/" } 40029-func (l literal) String() string { return string(l) } 40030-func (s star) String() string { return "*" } 40031-func (a anyChar) String() string { return "?" } 40032-func (s starStar) String() string { return "**" } 40033-func (g group) String() string { 40034- var parts []string 40035- for _, g := range g { 40036- parts = append(parts, g.String()) 40037- } 40038- return "{" + strings.Join(parts, ",") + "}" 40039-} 40040-func (r charRange) String() string { 40041- return "[" + string(r.low) + "-" + string(r.high) + "]" 40042-} 40043- 40044-// Match reports whether the input string matches the glob pattern. 40045-func (g *Glob) Match(input string) bool { 40046- return match(g.elems, input) 40047-} 40048- 40049-func match(elems []element, input string) (ok bool) { 40050- var elem interface{} 40051- for len(elems) > 0 { 40052- elem, elems = elems[0], elems[1:] 40053- switch elem := elem.(type) { 40054- case slash: 40055- if len(input) == 0 || input[0] != '/' { 40056- return false 40057- } 40058- for input[0] == '/' { 40059- input = input[1:] 40060- } 40061- 40062- case starStar: 40063- // Special cases: 40064- // - **/a matches "a" 40065- // - **/ matches everything 40066- // 40067- // Note that if ** is followed by anything, it must be '/' (this is 40068- // enforced by Parse). 40069- if len(elems) > 0 { 40070- elems = elems[1:] 40071- } 40072- 40073- // A trailing ** matches anything. 40074- if len(elems) == 0 { 40075- return true 40076- } 40077- 40078- // Backtracking: advance pattern segments until the remaining pattern 40079- // elements match. 40080- for len(input) != 0 { 40081- if match(elems, input) { 40082- return true 40083- } 40084- _, input = split(input) 40085- } 40086- return false 40087- 40088- case literal: 40089- if !strings.HasPrefix(input, string(elem)) { 40090- return false 40091- } 40092- input = input[len(elem):] 40093- 40094- case star: 40095- var segInput string 40096- segInput, input = split(input) 40097- 40098- elemEnd := len(elems) 40099- for i, e := range elems { 40100- if e == (slash{}) { 40101- elemEnd = i 40102- break 40103- } 40104- } 40105- segElems := elems[:elemEnd] 40106- elems = elems[elemEnd:] 40107- 40108- // A trailing * matches the entire segment. 40109- if len(segElems) == 0 { 40110- break 40111- } 40112- 40113- // Backtracking: advance characters until remaining subpattern elements 40114- // match. 40115- matched := false 40116- for i := range segInput { 40117- if match(segElems, segInput[i:]) { 40118- matched = true 40119- break 40120- } 40121- } 40122- if !matched { 40123- return false 40124- } 40125- 40126- case anyChar: 40127- if len(input) == 0 || input[0] == '/' { 40128- return false 40129- } 40130- input = input[1:] 40131- 40132- case group: 40133- // Append remaining pattern elements to each group member looking for a 40134- // match. 40135- var branch []element 40136- for _, m := range elem { 40137- branch = branch[:0] 40138- branch = append(branch, m.elems...) 40139- branch = append(branch, elems...) 40140- if match(branch, input) { 40141- return true 40142- } 40143- } 40144- return false 40145- 40146- case charRange: 40147- if len(input) == 0 || input[0] == '/' { 40148- return false 40149- } 40150- c, sz := utf8.DecodeRuneInString(input) 40151- if c < elem.low || c > elem.high { 40152- return false 40153- } 40154- input = input[sz:] 40155- 40156- default: 40157- panic(fmt.Sprintf("segment type %T not implemented", elem)) 40158- } 40159- } 40160- 40161- return len(input) == 0 40162-} 40163- 40164-// split returns the portion before and after the first slash 40165-// (or sequence of consecutive slashes). If there is no slash 40166-// it returns (input, nil). 40167-func split(input string) (first, rest string) { 40168- i := strings.IndexByte(input, '/') 40169- if i < 0 { 40170- return input, "" 40171- } 40172- first = input[:i] 40173- for j := i; j < len(input); j++ { 40174- if input[j] != '/' { 40175- return first, input[j:] 40176- } 40177- } 40178- return first, "" 40179-} 40180diff -urN a/gopls/internal/lsp/glob/glob_test.go b/gopls/internal/lsp/glob/glob_test.go 40181--- a/gopls/internal/lsp/glob/glob_test.go 2000-01-01 00:00:00.000000000 -0000 40182+++ b/gopls/internal/lsp/glob/glob_test.go 1970-01-01 00:00:00.000000000 +0000 40183@@ -1,118 +0,0 @@ 40184-// Copyright 2023 The Go Authors. All rights reserved. 40185-// Use of this source code is governed by a BSD-style 40186-// license that can be found in the LICENSE file. 40187- 40188-package glob_test 40189- 40190-import ( 40191- "testing" 40192- 40193- "golang.org/x/tools/gopls/internal/lsp/glob" 40194-) 40195- 40196-func TestParseErrors(t *testing.T) { 40197- tests := []string{ 40198- "***", 40199- "ab{c", 40200- "[]", 40201- "[a-]", 40202- "ab{c{d}", 40203- } 40204- 40205- for _, test := range tests { 40206- _, err := glob.Parse(test) 40207- if err == nil { 40208- t.Errorf("Parse(%q) succeeded unexpectedly", test) 40209- } 40210- } 40211-} 40212- 40213-func TestMatch(t *testing.T) { 40214- tests := []struct { 40215- pattern, input string 40216- want bool 40217- }{ 40218- // Basic cases. 40219- {"", "", true}, 40220- {"", "a", false}, 40221- {"", "/", false}, 40222- {"abc", "abc", true}, 40223- 40224- // ** behavior 40225- {"**", "abc", true}, 40226- {"**/abc", "abc", true}, 40227- {"**", "abc/def", true}, 40228- {"{a/**/c,a/**/d}", "a/b/c", true}, 40229- {"{a/**/c,a/**/d}", "a/b/c/d", true}, 40230- {"{a/**/c,a/**/e}", "a/b/c/d", false}, 40231- {"{a/**/c,a/**/e,a/**/d}", "a/b/c/d", true}, 40232- {"{/a/**/c,a/**/e,a/**/d}", "a/b/c/d", true}, 40233- {"{/a/**/c,a/**/e,a/**/d}", "/a/b/c/d", false}, 40234- {"{/a/**/c,a/**/e,a/**/d}", "/a/b/c", true}, 40235- {"{/a/**/e,a/**/e,a/**/d}", "/a/b/c", false}, 40236- 40237- // * and ? behavior 40238- {"/*", "/a", true}, 40239- {"*", "foo", true}, 40240- {"*o", "foo", true}, 40241- {"*o", "foox", false}, 40242- {"f*o", "foo", true}, 40243- {"f*o", "fo", true}, 40244- {"fo?", "foo", true}, 40245- {"fo?", "fox", true}, 40246- {"fo?", "fooo", false}, 40247- {"fo?", "fo", false}, 40248- {"?", "a", true}, 40249- {"?", "ab", false}, 40250- {"?", "", false}, 40251- {"*?", "", false}, 40252- {"?b", "ab", true}, 40253- {"?c", "ab", false}, 40254- 40255- // {} behavior 40256- {"ab{c,d}e", "abce", true}, 40257- {"ab{c,d}e", "abde", true}, 40258- {"ab{c,d}e", "abxe", false}, 40259- {"ab{c,d}e", "abe", false}, 40260- {"{a,b}c", "ac", true}, 40261- {"{a,b}c", "bc", true}, 40262- {"{a,b}c", "ab", false}, 40263- {"a{b,c}", "ab", true}, 40264- {"a{b,c}", "ac", true}, 40265- {"a{b,c}", "bc", false}, 40266- {"ab{c{1,2},d}e", "abc1e", true}, 40267- {"ab{c{1,2},d}e", "abde", true}, 40268- {"ab{c{1,2},d}e", "abc1f", false}, 40269- {"ab{c{1,2},d}e", "abce", false}, 40270- {"ab{c[}-~]}d", "abc}d", true}, 40271- {"ab{c[}-~]}d", "abc~d", true}, 40272- {"ab{c[}-~],y}d", "abcxd", false}, 40273- {"ab{c[}-~],y}d", "abyd", true}, 40274- {"ab{c[}-~],y}d", "abd", false}, 40275- {"{a/b/c,d/e/f}", "a/b/c", true}, 40276- {"/ab{/c,d}e", "/ab/ce", true}, 40277- {"/ab{/c,d}e", "/ab/cf", false}, 40278- 40279- // [-] behavior 40280- {"[a-c]", "a", true}, 40281- {"[a-c]", "b", true}, 40282- {"[a-c]", "c", true}, 40283- {"[a-c]", "d", false}, 40284- {"[a-c]", " ", false}, 40285- 40286- // Realistic examples. 40287- {"**/*.{ts,js}", "path/to/foo.ts", true}, 40288- {"**/*.{ts,js}", "path/to/foo.js", true}, 40289- {"**/*.{ts,js}", "path/to/foo.go", false}, 40290- } 40291- 40292- for _, test := range tests { 40293- g, err := glob.Parse(test.pattern) 40294- if err != nil { 40295- t.Fatalf("New(%q) failed unexpectedly: %v", test.pattern, err) 40296- } 40297- if got := g.Match(test.input); got != test.want { 40298- t.Errorf("New(%q).Match(%q) = %t, want %t", test.pattern, test.input, got, test.want) 40299- } 40300- } 40301-} 40302diff -urN a/gopls/internal/lsp/helper/helper.go b/gopls/internal/lsp/helper/helper.go 40303--- a/gopls/internal/lsp/helper/helper.go 2000-01-01 00:00:00.000000000 -0000 40304+++ b/gopls/internal/lsp/helper/helper.go 1970-01-01 00:00:00.000000000 +0000 40305@@ -1,264 +0,0 @@ 40306-// Copyright 2020 The Go Authors. All rights reserved. 40307-// Use of this source code is governed by a BSD-style 40308-// license that can be found in the LICENSE file. 40309- 40310-// The helper command generates the declaration of the concrete 40311-// 'server' type that implements the abstract Server interface defined 40312-// in protocol/tsserver.go (which is itself generated from the LSP 40313-// protocol). 40314-// 40315-// To run, invoke "go generate" in the parent (lsp) directory. 40316-// 40317-// TODO(adonovan): merge this into the main LSP generator. 40318-package main 40319- 40320-import ( 40321- "bytes" 40322- "flag" 40323- "fmt" 40324- "go/ast" 40325- "go/format" 40326- "go/parser" 40327- "go/token" 40328- "log" 40329- "os" 40330- "sort" 40331- "strings" 40332- "text/template" 40333-) 40334- 40335-var ( 40336- typ = flag.String("t", "Server", "generate code for this type") 40337- def = flag.String("d", "", "the file the type is defined in") // this relies on punning 40338- use = flag.String("u", "", "look for uses in this package") 40339- out = flag.String("o", "", "where to write the generated file") 40340-) 40341- 40342-func main() { 40343- log.SetFlags(log.Lshortfile) 40344- flag.Parse() 40345- if *typ == "" || *def == "" || *use == "" || *out == "" { 40346- flag.PrintDefaults() 40347- os.Exit(1) 40348- } 40349- // read the type definition and see what methods we're looking for 40350- doTypes() 40351- 40352- // parse the package and see which methods are defined 40353- doUses() 40354- 40355- output() 40356-} 40357- 40358-// replace "\\\n" with nothing before using 40359-var tmpl = `// Copyright 2021 The Go Authors. All rights reserved. 40360-// Use of this source code is governed by a BSD-style 40361-// license that can be found in the LICENSE file. 40362- 40363-package lsp 40364- 40365-// code generated by helper. DO NOT EDIT. 40366- 40367-import ( 40368- "context" 40369- 40370- "golang.org/x/tools/gopls/internal/lsp/protocol" 40371-) 40372- 40373-{{range $key, $v := .Stuff}} 40374-func (s *{{$.Type}}) {{$v.Name}}({{.Param}}) {{.Result}} { 40375- {{if ne .Found ""}} return s.{{.Internal}}({{.Invoke}})\ 40376- {{else}}return {{if lt 1 (len .Results)}}nil, {{end}}notImplemented("{{.Name}}"){{end}} 40377-} 40378-{{end}} 40379-` 40380- 40381-func output() { 40382- // put in empty param names as needed 40383- for _, t := range types { 40384- if t.paramnames == nil { 40385- t.paramnames = make([]string, len(t.paramtypes)) 40386- } 40387- for i, p := range t.paramtypes { 40388- cm := "" 40389- if i > 0 { 40390- cm = ", " 40391- } 40392- t.Param += fmt.Sprintf("%s%s %s", cm, t.paramnames[i], p) 40393- this := t.paramnames[i] 40394- if this == "_" { 40395- this = "nil" 40396- } 40397- t.Invoke += fmt.Sprintf("%s%s", cm, this) 40398- } 40399- if len(t.Results) > 1 { 40400- t.Result = "(" 40401- } 40402- for i, r := range t.Results { 40403- cm := "" 40404- if i > 0 { 40405- cm = ", " 40406- } 40407- t.Result += fmt.Sprintf("%s%s", cm, r) 40408- } 40409- if len(t.Results) > 1 { 40410- t.Result += ")" 40411- } 40412- } 40413- 40414- fd, err := os.Create(*out) 40415- if err != nil { 40416- log.Fatal(err) 40417- } 40418- t, err := template.New("foo").Parse(tmpl) 40419- if err != nil { 40420- log.Fatal(err) 40421- } 40422- type par struct { 40423- Type string 40424- Stuff []*Function 40425- } 40426- p := par{*typ, types} 40427- if false { // debugging the template 40428- t.Execute(os.Stderr, &p) 40429- } 40430- buf := bytes.NewBuffer(nil) 40431- err = t.Execute(buf, &p) 40432- if err != nil { 40433- log.Fatal(err) 40434- } 40435- ans, err := format.Source(bytes.Replace(buf.Bytes(), []byte("\\\n"), []byte{}, -1)) 40436- if err != nil { 40437- log.Fatal(err) 40438- } 40439- fd.Write(ans) 40440-} 40441- 40442-func doUses() { 40443- fset := token.NewFileSet() 40444- pkgs, err := parser.ParseDir(fset, *use, nil, 0) 40445- if err != nil { 40446- log.Fatalf("%q:%v", *use, err) 40447- } 40448- pkg := pkgs["lsp"] // CHECK 40449- files := pkg.Files 40450- for fname, f := range files { 40451- for _, d := range f.Decls { 40452- fd, ok := d.(*ast.FuncDecl) 40453- if !ok { 40454- continue 40455- } 40456- nm := fd.Name.String() 40457- if ast.IsExported(nm) { 40458- // we're looking for things like didChange 40459- continue 40460- } 40461- if fx, ok := byname[nm]; ok { 40462- if fx.Found != "" { 40463- log.Fatalf("found %s in %s and %s", fx.Internal, fx.Found, fname) 40464- } 40465- fx.Found = fname 40466- // and the Paramnames 40467- ft := fd.Type 40468- for _, f := range ft.Params.List { 40469- nm := "" 40470- if len(f.Names) > 0 { 40471- nm = f.Names[0].String() 40472- if nm == "_" { 40473- nm = "_gen" 40474- } 40475- } 40476- fx.paramnames = append(fx.paramnames, nm) 40477- } 40478- } 40479- } 40480- } 40481- if false { 40482- for i, f := range types { 40483- log.Printf("%d %s %s", i, f.Internal, f.Found) 40484- } 40485- } 40486-} 40487- 40488-type Function struct { 40489- Name string 40490- Internal string // first letter lower case 40491- paramtypes []string 40492- paramnames []string 40493- Results []string 40494- Param string 40495- Result string // do it in code, easier than in a template 40496- Invoke string 40497- Found string // file it was found in 40498-} 40499- 40500-var types []*Function 40501-var byname = map[string]*Function{} // internal names 40502- 40503-func doTypes() { 40504- fset := token.NewFileSet() 40505- f, err := parser.ParseFile(fset, *def, nil, 0) 40506- if err != nil { 40507- log.Fatal(err) 40508- } 40509- fd, err := os.Create("/tmp/ast") 40510- if err != nil { 40511- log.Fatal(err) 40512- } 40513- ast.Fprint(fd, fset, f, ast.NotNilFilter) 40514- ast.Inspect(f, inter) 40515- sort.Slice(types, func(i, j int) bool { return types[i].Name < types[j].Name }) 40516- if false { 40517- for i, f := range types { 40518- log.Printf("%d %s(%v) %v", i, f.Name, f.paramtypes, f.Results) 40519- } 40520- } 40521-} 40522- 40523-func inter(n ast.Node) bool { 40524- x, ok := n.(*ast.TypeSpec) 40525- if !ok || x.Name.Name != *typ { 40526- return true 40527- } 40528- m := x.Type.(*ast.InterfaceType).Methods.List 40529- for _, fld := range m { 40530- fn := fld.Type.(*ast.FuncType) 40531- p := fn.Params.List 40532- r := fn.Results.List 40533- fx := &Function{ 40534- Name: fld.Names[0].String(), 40535- } 40536- fx.Internal = strings.ToLower(fx.Name[:1]) + fx.Name[1:] 40537- for _, f := range p { 40538- fx.paramtypes = append(fx.paramtypes, whatis(f.Type)) 40539- } 40540- for _, f := range r { 40541- fx.Results = append(fx.Results, whatis(f.Type)) 40542- } 40543- types = append(types, fx) 40544- byname[fx.Internal] = fx 40545- } 40546- return false 40547-} 40548- 40549-func whatis(x ast.Expr) string { 40550- switch n := x.(type) { 40551- case *ast.SelectorExpr: 40552- return whatis(n.X) + "." + n.Sel.String() 40553- case *ast.StarExpr: 40554- return "*" + whatis(n.X) 40555- case *ast.Ident: 40556- if ast.IsExported(n.Name) { 40557- // these are from package protocol 40558- return "protocol." + n.Name 40559- } 40560- return n.Name 40561- case *ast.ArrayType: 40562- return "[]" + whatis(n.Elt) 40563- case *ast.InterfaceType: 40564- return "interface{}" 40565- default: 40566- log.Fatalf("Fatal %T", x) 40567- return fmt.Sprintf("%T", x) 40568- } 40569-} 40570diff -urN a/gopls/internal/lsp/helper/README.md b/gopls/internal/lsp/helper/README.md 40571--- a/gopls/internal/lsp/helper/README.md 2000-01-01 00:00:00.000000000 -0000 40572+++ b/gopls/internal/lsp/helper/README.md 1970-01-01 00:00:00.000000000 +0000 40573@@ -1,35 +0,0 @@ 40574-# Generate server_gen.go 40575- 40576-`helper` generates the file `../server_gen.go` (in package 40577-`internal/lsp`) which contains stub declarations of server methods. 40578- 40579-To invoke it, run `go generate` in the `gopls/internal/lsp` directory. 40580- 40581-It is derived from `gopls/internal/lsp/protocol/tsserver.go`, which 40582-itself is generated from the protocol downloaded from VSCode, so be 40583-sure to run `go generate` in the protocol first. Or run `go generate 40584-./...` twice in the gopls directory. 40585- 40586-It decides what stubs are needed and their signatures 40587-by looking at the `Server` interface (`-t` flag). These all look somewhat like 40588-`Resolve(context.Context, *CompletionItem) (*CompletionItem, error)`. 40589- 40590-It then parses the `lsp` directory (`-u` flag) to see if there is a corresponding 40591-implementation function (which in this case would be named `resolve`). If so 40592-it discovers the parameter names needed, and generates (in `server_gen.go`) code 40593-like 40594- 40595-``` go 40596-func (s *Server) resolve(ctx context.Context, params *protocol.CompletionItem) (*protocol.CompletionItem, error) { 40597- return s.resolve(ctx, params) 40598-} 40599-``` 40600- 40601-If `resolve` is not defined (and it is not), then the body of the generated function is 40602- 40603-```go 40604- return nil, notImplemented("resolve") 40605-``` 40606- 40607-So to add a capability currently not implemented, just define it somewhere in `lsp`. 40608-In this case, just define `func (s *Server) resolve(...)` and re-generate `server_gen.go`. 40609diff -urN a/gopls/internal/lsp/highlight.go b/gopls/internal/lsp/highlight.go 40610--- a/gopls/internal/lsp/highlight.go 2000-01-01 00:00:00.000000000 -0000 40611+++ b/gopls/internal/lsp/highlight.go 1970-01-01 00:00:00.000000000 +0000 40612@@ -1,45 +0,0 @@ 40613-// Copyright 2019 The Go Authors. All rights reserved. 40614-// Use of this source code is governed by a BSD-style 40615-// license that can be found in the LICENSE file. 40616- 40617-package lsp 40618- 40619-import ( 40620- "context" 40621- 40622- "golang.org/x/tools/internal/event" 40623- "golang.org/x/tools/internal/event/tag" 40624- "golang.org/x/tools/gopls/internal/lsp/protocol" 40625- "golang.org/x/tools/gopls/internal/lsp/source" 40626- "golang.org/x/tools/gopls/internal/lsp/template" 40627-) 40628- 40629-func (s *Server) documentHighlight(ctx context.Context, params *protocol.DocumentHighlightParams) ([]protocol.DocumentHighlight, error) { 40630- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 40631- defer release() 40632- if !ok { 40633- return nil, err 40634- } 40635- 40636- if snapshot.View().FileKind(fh) == source.Tmpl { 40637- return template.Highlight(ctx, snapshot, fh, params.Position) 40638- } 40639- 40640- rngs, err := source.Highlight(ctx, snapshot, fh, params.Position) 40641- if err != nil { 40642- event.Error(ctx, "no highlight", err, tag.URI.Of(params.TextDocument.URI)) 40643- } 40644- return toProtocolHighlight(rngs), nil 40645-} 40646- 40647-func toProtocolHighlight(rngs []protocol.Range) []protocol.DocumentHighlight { 40648- result := make([]protocol.DocumentHighlight, 0, len(rngs)) 40649- kind := protocol.Text 40650- for _, rng := range rngs { 40651- result = append(result, protocol.DocumentHighlight{ 40652- Kind: kind, 40653- Range: rng, 40654- }) 40655- } 40656- return result 40657-} 40658diff -urN a/gopls/internal/lsp/hover.go b/gopls/internal/lsp/hover.go 40659--- a/gopls/internal/lsp/hover.go 2000-01-01 00:00:00.000000000 -0000 40660+++ b/gopls/internal/lsp/hover.go 1970-01-01 00:00:00.000000000 +0000 40661@@ -1,34 +0,0 @@ 40662-// Copyright 2019 The Go Authors. All rights reserved. 40663-// Use of this source code is governed by a BSD-style 40664-// license that can be found in the LICENSE file. 40665- 40666-package lsp 40667- 40668-import ( 40669- "context" 40670- 40671- "golang.org/x/tools/gopls/internal/lsp/mod" 40672- "golang.org/x/tools/gopls/internal/lsp/protocol" 40673- "golang.org/x/tools/gopls/internal/lsp/source" 40674- "golang.org/x/tools/gopls/internal/lsp/template" 40675- "golang.org/x/tools/gopls/internal/lsp/work" 40676-) 40677- 40678-func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (*protocol.Hover, error) { 40679- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 40680- defer release() 40681- if !ok { 40682- return nil, err 40683- } 40684- switch snapshot.View().FileKind(fh) { 40685- case source.Mod: 40686- return mod.Hover(ctx, snapshot, fh, params.Position) 40687- case source.Go: 40688- return source.Hover(ctx, snapshot, fh, params.Position) 40689- case source.Tmpl: 40690- return template.Hover(ctx, snapshot, fh, params.Position) 40691- case source.Work: 40692- return work.Hover(ctx, snapshot, fh, params.Position) 40693- } 40694- return nil, nil 40695-} 40696diff -urN a/gopls/internal/lsp/implementation.go b/gopls/internal/lsp/implementation.go 40697--- a/gopls/internal/lsp/implementation.go 2000-01-01 00:00:00.000000000 -0000 40698+++ b/gopls/internal/lsp/implementation.go 1970-01-01 00:00:00.000000000 +0000 40699@@ -1,21 +0,0 @@ 40700-// Copyright 2019 The Go Authors. All rights reserved. 40701-// Use of this source code is governed by a BSD-style 40702-// license that can be found in the LICENSE file. 40703- 40704-package lsp 40705- 40706-import ( 40707- "context" 40708- 40709- "golang.org/x/tools/gopls/internal/lsp/protocol" 40710- "golang.org/x/tools/gopls/internal/lsp/source" 40711-) 40712- 40713-func (s *Server) implementation(ctx context.Context, params *protocol.ImplementationParams) ([]protocol.Location, error) { 40714- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 40715- defer release() 40716- if !ok { 40717- return nil, err 40718- } 40719- return source.Implementation(ctx, snapshot, fh, params.Position) 40720-} 40721diff -urN a/gopls/internal/lsp/inlay_hint.go b/gopls/internal/lsp/inlay_hint.go 40722--- a/gopls/internal/lsp/inlay_hint.go 2000-01-01 00:00:00.000000000 -0000 40723+++ b/gopls/internal/lsp/inlay_hint.go 1970-01-01 00:00:00.000000000 +0000 40724@@ -1,21 +0,0 @@ 40725-// Copyright 2022 The Go Authors. All rights reserved. 40726-// Use of this source code is governed by a BSD-style 40727-// license that can be found in the LICENSE file. 40728- 40729-package lsp 40730- 40731-import ( 40732- "context" 40733- 40734- "golang.org/x/tools/gopls/internal/lsp/protocol" 40735- "golang.org/x/tools/gopls/internal/lsp/source" 40736-) 40737- 40738-func (s *Server) inlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) { 40739- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 40740- defer release() 40741- if !ok { 40742- return nil, err 40743- } 40744- return source.InlayHint(ctx, snapshot, fh, params.Range) 40745-} 40746diff -urN a/gopls/internal/lsp/link.go b/gopls/internal/lsp/link.go 40747--- a/gopls/internal/lsp/link.go 2000-01-01 00:00:00.000000000 -0000 40748+++ b/gopls/internal/lsp/link.go 1970-01-01 00:00:00.000000000 +0000 40749@@ -1,278 +0,0 @@ 40750-// Copyright 2018 The Go Authors. All rights reserved. 40751-// Use of this source code is governed by a BSD-style 40752-// license that can be found in the LICENSE file. 40753- 40754-package lsp 40755- 40756-import ( 40757- "bytes" 40758- "context" 40759- "fmt" 40760- "go/ast" 40761- "go/token" 40762- "net/url" 40763- "regexp" 40764- "strings" 40765- "sync" 40766- 40767- "golang.org/x/mod/modfile" 40768- "golang.org/x/tools/gopls/internal/lsp/protocol" 40769- "golang.org/x/tools/gopls/internal/lsp/safetoken" 40770- "golang.org/x/tools/gopls/internal/lsp/source" 40771- "golang.org/x/tools/internal/event" 40772- "golang.org/x/tools/internal/event/tag" 40773-) 40774- 40775-func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) (links []protocol.DocumentLink, err error) { 40776- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 40777- defer release() 40778- if !ok { 40779- return nil, err 40780- } 40781- switch snapshot.View().FileKind(fh) { 40782- case source.Mod: 40783- links, err = modLinks(ctx, snapshot, fh) 40784- case source.Go: 40785- links, err = goLinks(ctx, snapshot, fh) 40786- } 40787- // Don't return errors for document links. 40788- if err != nil { 40789- event.Error(ctx, "failed to compute document links", err, tag.URI.Of(fh.URI())) 40790- return nil, nil 40791- } 40792- return links, nil 40793-} 40794- 40795-func modLinks(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentLink, error) { 40796- pm, err := snapshot.ParseMod(ctx, fh) 40797- if err != nil { 40798- return nil, err 40799- } 40800- 40801- var links []protocol.DocumentLink 40802- for _, req := range pm.File.Require { 40803- if req.Syntax == nil { 40804- continue 40805- } 40806- // See golang/go#36998: don't link to modules matching GOPRIVATE. 40807- if snapshot.View().IsGoPrivatePath(req.Mod.Path) { 40808- continue 40809- } 40810- dep := []byte(req.Mod.Path) 40811- start, end := req.Syntax.Start.Byte, req.Syntax.End.Byte 40812- i := bytes.Index(pm.Mapper.Content[start:end], dep) 40813- if i == -1 { 40814- continue 40815- } 40816- // Shift the start position to the location of the 40817- // dependency within the require statement. 40818- target := source.BuildLink(snapshot.View().Options().LinkTarget, "mod/"+req.Mod.String(), "") 40819- l, err := toProtocolLink(pm.Mapper, target, start+i, start+i+len(dep)) 40820- if err != nil { 40821- return nil, err 40822- } 40823- links = append(links, l) 40824- } 40825- // TODO(ridersofrohan): handle links for replace and exclude directives. 40826- if syntax := pm.File.Syntax; syntax == nil { 40827- return links, nil 40828- } 40829- 40830- // Get all the links that are contained in the comments of the file. 40831- urlRegexp := snapshot.View().Options().URLRegexp 40832- for _, expr := range pm.File.Syntax.Stmt { 40833- comments := expr.Comment() 40834- if comments == nil { 40835- continue 40836- } 40837- for _, section := range [][]modfile.Comment{comments.Before, comments.Suffix, comments.After} { 40838- for _, comment := range section { 40839- l, err := findLinksInString(urlRegexp, comment.Token, comment.Start.Byte, pm.Mapper) 40840- if err != nil { 40841- return nil, err 40842- } 40843- links = append(links, l...) 40844- } 40845- } 40846- } 40847- return links, nil 40848-} 40849- 40850-// goLinks returns the set of hyperlink annotations for the specified Go file. 40851-func goLinks(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentLink, error) { 40852- view := snapshot.View() 40853- 40854- pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull) 40855- if err != nil { 40856- return nil, err 40857- } 40858- 40859- var links []protocol.DocumentLink 40860- 40861- // Create links for import specs. 40862- if view.Options().ImportShortcut.ShowLinks() { 40863- 40864- // If links are to pkg.go.dev, append module version suffixes. 40865- // This requires the import map from the package metadata. Ignore errors. 40866- var depsByImpPath map[source.ImportPath]source.PackageID 40867- if strings.ToLower(view.Options().LinkTarget) == "pkg.go.dev" { 40868- if metas, _ := snapshot.MetadataForFile(ctx, fh.URI()); len(metas) > 0 { 40869- depsByImpPath = metas[0].DepsByImpPath // 0 => narrowest package 40870- } 40871- } 40872- 40873- for _, imp := range pgf.File.Imports { 40874- importPath := source.UnquoteImportPath(imp) 40875- if importPath == "" { 40876- continue // bad import 40877- } 40878- // See golang/go#36998: don't link to modules matching GOPRIVATE. 40879- if view.IsGoPrivatePath(string(importPath)) { 40880- continue 40881- } 40882- 40883- urlPath := string(importPath) 40884- 40885- // For pkg.go.dev, append module version suffix to package import path. 40886- if m := snapshot.Metadata(depsByImpPath[importPath]); m != nil && m.Module != nil && m.Module.Path != "" && m.Module.Version != "" { 40887- urlPath = strings.Replace(urlPath, m.Module.Path, m.Module.Path+"@"+m.Module.Version, 1) 40888- } 40889- 40890- start, end, err := safetoken.Offsets(pgf.Tok, imp.Path.Pos(), imp.Path.End()) 40891- if err != nil { 40892- return nil, err 40893- } 40894- targetURL := source.BuildLink(view.Options().LinkTarget, urlPath, "") 40895- // Account for the quotation marks in the positions. 40896- l, err := toProtocolLink(pgf.Mapper, targetURL, start+len(`"`), end-len(`"`)) 40897- if err != nil { 40898- return nil, err 40899- } 40900- links = append(links, l) 40901- } 40902- } 40903- 40904- urlRegexp := snapshot.View().Options().URLRegexp 40905- 40906- // Gather links found in string literals. 40907- var str []*ast.BasicLit 40908- ast.Inspect(pgf.File, func(node ast.Node) bool { 40909- switch n := node.(type) { 40910- case *ast.ImportSpec: 40911- return false // don't process import strings again 40912- case *ast.BasicLit: 40913- if n.Kind == token.STRING { 40914- str = append(str, n) 40915- } 40916- } 40917- return true 40918- }) 40919- for _, s := range str { 40920- strOffset, err := safetoken.Offset(pgf.Tok, s.Pos()) 40921- if err != nil { 40922- return nil, err 40923- } 40924- l, err := findLinksInString(urlRegexp, s.Value, strOffset, pgf.Mapper) 40925- if err != nil { 40926- return nil, err 40927- } 40928- links = append(links, l...) 40929- } 40930- 40931- // Gather links found in comments. 40932- for _, commentGroup := range pgf.File.Comments { 40933- for _, comment := range commentGroup.List { 40934- commentOffset, err := safetoken.Offset(pgf.Tok, comment.Pos()) 40935- if err != nil { 40936- return nil, err 40937- } 40938- l, err := findLinksInString(urlRegexp, comment.Text, commentOffset, pgf.Mapper) 40939- if err != nil { 40940- return nil, err 40941- } 40942- links = append(links, l...) 40943- } 40944- } 40945- 40946- return links, nil 40947-} 40948- 40949-// acceptedSchemes controls the schemes that URLs must have to be shown to the 40950-// user. Other schemes can't be opened by LSP clients, so linkifying them is 40951-// distracting. See golang/go#43990. 40952-var acceptedSchemes = map[string]bool{ 40953- "http": true, 40954- "https": true, 40955-} 40956- 40957-// urlRegexp is the user-supplied regular expression to match URL. 40958-// srcOffset is the start offset of 'src' within m's file. 40959-func findLinksInString(urlRegexp *regexp.Regexp, src string, srcOffset int, m *protocol.Mapper) ([]protocol.DocumentLink, error) { 40960- var links []protocol.DocumentLink 40961- for _, index := range urlRegexp.FindAllIndex([]byte(src), -1) { 40962- start, end := index[0], index[1] 40963- link := src[start:end] 40964- linkURL, err := url.Parse(link) 40965- // Fallback: Linkify IP addresses as suggested in golang/go#18824. 40966- if err != nil { 40967- linkURL, err = url.Parse("//" + link) 40968- // Not all potential links will be valid, so don't return this error. 40969- if err != nil { 40970- continue 40971- } 40972- } 40973- // If the URL has no scheme, use https. 40974- if linkURL.Scheme == "" { 40975- linkURL.Scheme = "https" 40976- } 40977- if !acceptedSchemes[linkURL.Scheme] { 40978- continue 40979- } 40980- 40981- l, err := toProtocolLink(m, linkURL.String(), srcOffset+start, srcOffset+end) 40982- if err != nil { 40983- return nil, err 40984- } 40985- links = append(links, l) 40986- } 40987- // Handle golang/go#1234-style links. 40988- r := getIssueRegexp() 40989- for _, index := range r.FindAllIndex([]byte(src), -1) { 40990- start, end := index[0], index[1] 40991- matches := r.FindStringSubmatch(src) 40992- if len(matches) < 4 { 40993- continue 40994- } 40995- org, repo, number := matches[1], matches[2], matches[3] 40996- targetURL := fmt.Sprintf("https://github.com/%s/%s/issues/%s", org, repo, number) 40997- l, err := toProtocolLink(m, targetURL, srcOffset+start, srcOffset+end) 40998- if err != nil { 40999- return nil, err 41000- } 41001- links = append(links, l) 41002- } 41003- return links, nil 41004-} 41005- 41006-func getIssueRegexp() *regexp.Regexp { 41007- once.Do(func() { 41008- issueRegexp = regexp.MustCompile(`(\w+)/([\w-]+)#([0-9]+)`) 41009- }) 41010- return issueRegexp 41011-} 41012- 41013-var ( 41014- once sync.Once 41015- issueRegexp *regexp.Regexp 41016-) 41017- 41018-func toProtocolLink(m *protocol.Mapper, targetURL string, start, end int) (protocol.DocumentLink, error) { 41019- rng, err := m.OffsetRange(start, end) 41020- if err != nil { 41021- return protocol.DocumentLink{}, err 41022- } 41023- return protocol.DocumentLink{ 41024- Range: rng, 41025- Target: targetURL, 41026- }, nil 41027-} 41028diff -urN a/gopls/internal/lsp/lsprpc/autostart_default.go b/gopls/internal/lsp/lsprpc/autostart_default.go 41029--- a/gopls/internal/lsp/lsprpc/autostart_default.go 2000-01-01 00:00:00.000000000 -0000 41030+++ b/gopls/internal/lsp/lsprpc/autostart_default.go 1970-01-01 00:00:00.000000000 +0000 41031@@ -1,39 +0,0 @@ 41032-// Copyright 2020 The Go Authors. All rights reserved. 41033-// Use of this source code is governed by a BSD-style 41034-// license that can be found in the LICENSE file. 41035- 41036-package lsprpc 41037- 41038-import ( 41039- "fmt" 41040- 41041- exec "golang.org/x/sys/execabs" 41042-) 41043- 41044-var ( 41045- daemonize = func(*exec.Cmd) {} 41046- autoNetworkAddress = autoNetworkAddressDefault 41047- verifyRemoteOwnership = verifyRemoteOwnershipDefault 41048-) 41049- 41050-func runRemote(cmd *exec.Cmd) error { 41051- daemonize(cmd) 41052- if err := cmd.Start(); err != nil { 41053- return fmt.Errorf("starting remote gopls: %w", err) 41054- } 41055- return nil 41056-} 41057- 41058-// autoNetworkAddressDefault returns the default network and address for the 41059-// automatically-started gopls remote. See autostart_posix.go for more 41060-// information. 41061-func autoNetworkAddressDefault(goplsPath, id string) (network string, address string) { 41062- if id != "" { 41063- panic("identified remotes are not supported on windows") 41064- } 41065- return "tcp", "localhost:37374" 41066-} 41067- 41068-func verifyRemoteOwnershipDefault(network, address string) (bool, error) { 41069- return true, nil 41070-} 41071diff -urN a/gopls/internal/lsp/lsprpc/autostart_posix.go b/gopls/internal/lsp/lsprpc/autostart_posix.go 41072--- a/gopls/internal/lsp/lsprpc/autostart_posix.go 2000-01-01 00:00:00.000000000 -0000 41073+++ b/gopls/internal/lsp/lsprpc/autostart_posix.go 1970-01-01 00:00:00.000000000 +0000 41074@@ -1,97 +0,0 @@ 41075-// Copyright 2020 The Go Authors. All rights reserved. 41076-// Use of this source code is governed by a BSD-style 41077-// license that can be found in the LICENSE file. 41078- 41079-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 41080-// +build darwin dragonfly freebsd linux netbsd openbsd solaris 41081- 41082-package lsprpc 41083- 41084-import ( 41085- "crypto/sha256" 41086- "errors" 41087- "fmt" 41088- "log" 41089- "os" 41090- "os/user" 41091- "path/filepath" 41092- "strconv" 41093- "syscall" 41094- 41095- exec "golang.org/x/sys/execabs" 41096-) 41097- 41098-func init() { 41099- daemonize = daemonizePosix 41100- autoNetworkAddress = autoNetworkAddressPosix 41101- verifyRemoteOwnership = verifyRemoteOwnershipPosix 41102-} 41103- 41104-func daemonizePosix(cmd *exec.Cmd) { 41105- cmd.SysProcAttr = &syscall.SysProcAttr{ 41106- Setsid: true, 41107- } 41108-} 41109- 41110-// autoNetworkAddressPosix resolves an id on the 'auto' pseduo-network to a 41111-// real network and address. On unix, this uses unix domain sockets. 41112-func autoNetworkAddressPosix(goplsPath, id string) (network string, address string) { 41113- // Especially when doing local development or testing, it's important that 41114- // the remote gopls instance we connect to is running the same binary as our 41115- // forwarder. So we encode a short hash of the binary path into the daemon 41116- // socket name. If possible, we also include the buildid in this hash, to 41117- // account for long-running processes where the binary has been subsequently 41118- // rebuilt. 41119- h := sha256.New() 41120- cmd := exec.Command("go", "tool", "buildid", goplsPath) 41121- cmd.Stdout = h 41122- var pathHash []byte 41123- if err := cmd.Run(); err == nil { 41124- pathHash = h.Sum(nil) 41125- } else { 41126- log.Printf("error getting current buildid: %v", err) 41127- sum := sha256.Sum256([]byte(goplsPath)) 41128- pathHash = sum[:] 41129- } 41130- shortHash := fmt.Sprintf("%x", pathHash)[:6] 41131- user := os.Getenv("USER") 41132- if user == "" { 41133- user = "shared" 41134- } 41135- basename := filepath.Base(goplsPath) 41136- idComponent := "" 41137- if id != "" { 41138- idComponent = "-" + id 41139- } 41140- runtimeDir := os.TempDir() 41141- if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" { 41142- runtimeDir = xdg 41143- } 41144- return "unix", filepath.Join(runtimeDir, fmt.Sprintf("%s-%s-daemon.%s%s", basename, shortHash, user, idComponent)) 41145-} 41146- 41147-func verifyRemoteOwnershipPosix(network, address string) (bool, error) { 41148- if network != "unix" { 41149- return true, nil 41150- } 41151- fi, err := os.Stat(address) 41152- if err != nil { 41153- if os.IsNotExist(err) { 41154- return true, nil 41155- } 41156- return false, fmt.Errorf("checking socket owner: %w", err) 41157- } 41158- stat, ok := fi.Sys().(*syscall.Stat_t) 41159- if !ok { 41160- return false, errors.New("fi.Sys() is not a Stat_t") 41161- } 41162- user, err := user.Current() 41163- if err != nil { 41164- return false, fmt.Errorf("checking current user: %w", err) 41165- } 41166- uid, err := strconv.ParseUint(user.Uid, 10, 32) 41167- if err != nil { 41168- return false, fmt.Errorf("parsing current UID: %w", err) 41169- } 41170- return stat.Uid == uint32(uid), nil 41171-} 41172diff -urN a/gopls/internal/lsp/lsprpc/binder.go b/gopls/internal/lsp/lsprpc/binder.go 41173--- a/gopls/internal/lsp/lsprpc/binder.go 2000-01-01 00:00:00.000000000 -0000 41174+++ b/gopls/internal/lsp/lsprpc/binder.go 1970-01-01 00:00:00.000000000 +0000 41175@@ -1,148 +0,0 @@ 41176-// Copyright 2021 The Go Authors. All rights reserved. 41177-// Use of this source code is governed by a BSD-style 41178-// license that can be found in the LICENSE file. 41179- 41180-package lsprpc 41181- 41182-import ( 41183- "context" 41184- "encoding/json" 41185- "fmt" 41186- 41187- "golang.org/x/tools/gopls/internal/lsp/protocol" 41188- "golang.org/x/tools/internal/event" 41189- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 41190- "golang.org/x/tools/internal/xcontext" 41191-) 41192- 41193-// The BinderFunc type adapts a bind function to implement the jsonrpc2.Binder 41194-// interface. 41195-type BinderFunc func(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions 41196- 41197-func (f BinderFunc) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions { 41198- return f(ctx, conn) 41199-} 41200- 41201-// Middleware defines a transformation of jsonrpc2 Binders, that may be 41202-// composed to build jsonrpc2 servers. 41203-type Middleware func(jsonrpc2_v2.Binder) jsonrpc2_v2.Binder 41204- 41205-// A ServerFunc is used to construct an LSP server for a given client. 41206-type ServerFunc func(context.Context, protocol.ClientCloser) protocol.Server 41207- 41208-// ServerBinder binds incoming connections to a new server. 41209-type ServerBinder struct { 41210- newServer ServerFunc 41211-} 41212- 41213-func NewServerBinder(newServer ServerFunc) *ServerBinder { 41214- return &ServerBinder{newServer: newServer} 41215-} 41216- 41217-func (b *ServerBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions { 41218- client := protocol.ClientDispatcherV2(conn) 41219- server := b.newServer(ctx, client) 41220- serverHandler := protocol.ServerHandlerV2(server) 41221- // Wrap the server handler to inject the client into each request context, so 41222- // that log events are reflected back to the client. 41223- wrapped := jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 41224- ctx = protocol.WithClient(ctx, client) 41225- return serverHandler.Handle(ctx, req) 41226- }) 41227- preempter := &canceler{ 41228- conn: conn, 41229- } 41230- return jsonrpc2_v2.ConnectionOptions{ 41231- Handler: wrapped, 41232- Preempter: preempter, 41233- } 41234-} 41235- 41236-type canceler struct { 41237- conn *jsonrpc2_v2.Connection 41238-} 41239- 41240-func (c *canceler) Preempt(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 41241- if req.Method != "$/cancelRequest" { 41242- return nil, jsonrpc2_v2.ErrNotHandled 41243- } 41244- var params protocol.CancelParams 41245- if err := json.Unmarshal(req.Params, ¶ms); err != nil { 41246- return nil, fmt.Errorf("%w: %v", jsonrpc2_v2.ErrParse, err) 41247- } 41248- var id jsonrpc2_v2.ID 41249- switch raw := params.ID.(type) { 41250- case float64: 41251- id = jsonrpc2_v2.Int64ID(int64(raw)) 41252- case string: 41253- id = jsonrpc2_v2.StringID(raw) 41254- default: 41255- return nil, fmt.Errorf("%w: invalid ID type %T", jsonrpc2_v2.ErrParse, params.ID) 41256- } 41257- c.conn.Cancel(id) 41258- return nil, nil 41259-} 41260- 41261-type ForwardBinder struct { 41262- dialer jsonrpc2_v2.Dialer 41263- onBind func(*jsonrpc2_v2.Connection) 41264-} 41265- 41266-func NewForwardBinder(dialer jsonrpc2_v2.Dialer) *ForwardBinder { 41267- return &ForwardBinder{ 41268- dialer: dialer, 41269- } 41270-} 41271- 41272-func (b *ForwardBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) (opts jsonrpc2_v2.ConnectionOptions) { 41273- client := protocol.ClientDispatcherV2(conn) 41274- clientBinder := NewClientBinder(func(context.Context, protocol.Server) protocol.Client { return client }) 41275- 41276- serverConn, err := jsonrpc2_v2.Dial(context.Background(), b.dialer, clientBinder) 41277- if err != nil { 41278- return jsonrpc2_v2.ConnectionOptions{ 41279- Handler: jsonrpc2_v2.HandlerFunc(func(context.Context, *jsonrpc2_v2.Request) (interface{}, error) { 41280- return nil, fmt.Errorf("%w: %v", jsonrpc2_v2.ErrInternal, err) 41281- }), 41282- } 41283- } 41284- 41285- if b.onBind != nil { 41286- b.onBind(serverConn) 41287- } 41288- server := protocol.ServerDispatcherV2(serverConn) 41289- preempter := &canceler{ 41290- conn: conn, 41291- } 41292- detached := xcontext.Detach(ctx) 41293- go func() { 41294- conn.Wait() 41295- if err := serverConn.Close(); err != nil { 41296- event.Log(detached, fmt.Sprintf("closing remote connection: %v", err)) 41297- } 41298- }() 41299- return jsonrpc2_v2.ConnectionOptions{ 41300- Handler: protocol.ServerHandlerV2(server), 41301- Preempter: preempter, 41302- } 41303-} 41304- 41305-// A ClientFunc is used to construct an LSP client for a given server. 41306-type ClientFunc func(context.Context, protocol.Server) protocol.Client 41307- 41308-// ClientBinder binds an LSP client to an incoming connection. 41309-type ClientBinder struct { 41310- newClient ClientFunc 41311-} 41312- 41313-func NewClientBinder(newClient ClientFunc) *ClientBinder { 41314- return &ClientBinder{newClient} 41315-} 41316- 41317-func (b *ClientBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions { 41318- server := protocol.ServerDispatcherV2(conn) 41319- client := b.newClient(ctx, server) 41320- return jsonrpc2_v2.ConnectionOptions{ 41321- Handler: protocol.ClientHandlerV2(client), 41322- } 41323-} 41324diff -urN a/gopls/internal/lsp/lsprpc/binder_test.go b/gopls/internal/lsp/lsprpc/binder_test.go 41325--- a/gopls/internal/lsp/lsprpc/binder_test.go 2000-01-01 00:00:00.000000000 -0000 41326+++ b/gopls/internal/lsp/lsprpc/binder_test.go 1970-01-01 00:00:00.000000000 +0000 41327@@ -1,147 +0,0 @@ 41328-// Copyright 2021 The Go Authors. All rights reserved. 41329-// Use of this source code is governed by a BSD-style 41330-// license that can be found in the LICENSE file. 41331- 41332-package lsprpc_test 41333- 41334-import ( 41335- "context" 41336- "regexp" 41337- "strings" 41338- "testing" 41339- "time" 41340- 41341- "golang.org/x/tools/gopls/internal/lsp/protocol" 41342- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 41343- 41344- . "golang.org/x/tools/gopls/internal/lsp/lsprpc" 41345-) 41346- 41347-type TestEnv struct { 41348- Conns []*jsonrpc2_v2.Connection 41349- Servers []*jsonrpc2_v2.Server 41350-} 41351- 41352-func (e *TestEnv) Shutdown(t *testing.T) { 41353- for _, s := range e.Servers { 41354- s.Shutdown() 41355- } 41356- for _, c := range e.Conns { 41357- if err := c.Close(); err != nil { 41358- t.Error(err) 41359- } 41360- } 41361- for _, s := range e.Servers { 41362- if err := s.Wait(); err != nil { 41363- t.Error(err) 41364- } 41365- } 41366-} 41367- 41368-func (e *TestEnv) serve(ctx context.Context, t *testing.T, server jsonrpc2_v2.Binder) (jsonrpc2_v2.Listener, *jsonrpc2_v2.Server) { 41369- l, err := jsonrpc2_v2.NetPipeListener(ctx) 41370- if err != nil { 41371- t.Fatal(err) 41372- } 41373- s := jsonrpc2_v2.NewServer(ctx, l, server) 41374- e.Servers = append(e.Servers, s) 41375- return l, s 41376-} 41377- 41378-func (e *TestEnv) dial(ctx context.Context, t *testing.T, dialer jsonrpc2_v2.Dialer, client jsonrpc2_v2.Binder, forwarded bool) *jsonrpc2_v2.Connection { 41379- if forwarded { 41380- l, _ := e.serve(ctx, t, NewForwardBinder(dialer)) 41381- dialer = l.Dialer() 41382- } 41383- conn, err := jsonrpc2_v2.Dial(ctx, dialer, client) 41384- if err != nil { 41385- t.Fatal(err) 41386- } 41387- e.Conns = append(e.Conns, conn) 41388- return conn 41389-} 41390- 41391-func staticClientBinder(client protocol.Client) jsonrpc2_v2.Binder { 41392- f := func(context.Context, protocol.Server) protocol.Client { return client } 41393- return NewClientBinder(f) 41394-} 41395- 41396-func staticServerBinder(server protocol.Server) jsonrpc2_v2.Binder { 41397- f := func(ctx context.Context, client protocol.ClientCloser) protocol.Server { 41398- return server 41399- } 41400- return NewServerBinder(f) 41401-} 41402- 41403-func TestClientLoggingV2(t *testing.T) { 41404- ctx := context.Background() 41405- 41406- for name, forwarded := range map[string]bool{ 41407- "forwarded": true, 41408- "standalone": false, 41409- } { 41410- t.Run(name, func(t *testing.T) { 41411- client := FakeClient{Logs: make(chan string, 10)} 41412- env := new(TestEnv) 41413- defer env.Shutdown(t) 41414- l, _ := env.serve(ctx, t, staticServerBinder(PingServer{})) 41415- conn := env.dial(ctx, t, l.Dialer(), staticClientBinder(client), forwarded) 41416- 41417- if err := protocol.ServerDispatcherV2(conn).DidOpen(ctx, &protocol.DidOpenTextDocumentParams{}); err != nil { 41418- t.Errorf("DidOpen: %v", err) 41419- } 41420- select { 41421- case got := <-client.Logs: 41422- want := "ping" 41423- matched, err := regexp.MatchString(want, got) 41424- if err != nil { 41425- t.Fatal(err) 41426- } 41427- if !matched { 41428- t.Errorf("got log %q, want a log containing %q", got, want) 41429- } 41430- case <-time.After(1 * time.Second): 41431- t.Error("timeout waiting for client log") 41432- } 41433- }) 41434- } 41435-} 41436- 41437-func TestRequestCancellationV2(t *testing.T) { 41438- ctx := context.Background() 41439- 41440- for name, forwarded := range map[string]bool{ 41441- "forwarded": true, 41442- "standalone": false, 41443- } { 41444- t.Run(name, func(t *testing.T) { 41445- server := WaitableServer{ 41446- Started: make(chan struct{}), 41447- Completed: make(chan error), 41448- } 41449- env := new(TestEnv) 41450- defer env.Shutdown(t) 41451- l, _ := env.serve(ctx, t, staticServerBinder(server)) 41452- client := FakeClient{Logs: make(chan string, 10)} 41453- conn := env.dial(ctx, t, l.Dialer(), staticClientBinder(client), forwarded) 41454- 41455- sd := protocol.ServerDispatcherV2(conn) 41456- ctx, cancel := context.WithCancel(ctx) 41457- 41458- result := make(chan error) 41459- go func() { 41460- _, err := sd.Hover(ctx, &protocol.HoverParams{}) 41461- result <- err 41462- }() 41463- // Wait for the Hover request to start. 41464- <-server.Started 41465- cancel() 41466- if err := <-result; err == nil { 41467- t.Error("nil error for cancelled Hover(), want non-nil") 41468- } 41469- if err := <-server.Completed; err == nil || !strings.Contains(err.Error(), "cancelled hover") { 41470- t.Errorf("Hover(): unexpected server-side error %v", err) 41471- } 41472- }) 41473- } 41474-} 41475diff -urN a/gopls/internal/lsp/lsprpc/commandinterceptor.go b/gopls/internal/lsp/lsprpc/commandinterceptor.go 41476--- a/gopls/internal/lsp/lsprpc/commandinterceptor.go 2000-01-01 00:00:00.000000000 -0000 41477+++ b/gopls/internal/lsp/lsprpc/commandinterceptor.go 1970-01-01 00:00:00.000000000 +0000 41478@@ -1,44 +0,0 @@ 41479-// Copyright 2021 The Go Authors. All rights reserved. 41480-// Use of this source code is governed by a BSD-style 41481-// license that can be found in the LICENSE file. 41482- 41483-package lsprpc 41484- 41485-import ( 41486- "context" 41487- "encoding/json" 41488- 41489- "golang.org/x/tools/gopls/internal/lsp/protocol" 41490- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 41491-) 41492- 41493-// HandlerMiddleware is a middleware that only modifies the jsonrpc2 handler. 41494-type HandlerMiddleware func(jsonrpc2_v2.Handler) jsonrpc2_v2.Handler 41495- 41496-// BindHandler transforms a HandlerMiddleware into a Middleware. 41497-func BindHandler(hmw HandlerMiddleware) Middleware { 41498- return Middleware(func(binder jsonrpc2_v2.Binder) jsonrpc2_v2.Binder { 41499- return BinderFunc(func(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions { 41500- opts := binder.Bind(ctx, conn) 41501- opts.Handler = hmw(opts.Handler) 41502- return opts 41503- }) 41504- }) 41505-} 41506- 41507-func CommandInterceptor(command string, run func(*protocol.ExecuteCommandParams) (interface{}, error)) Middleware { 41508- return BindHandler(func(delegate jsonrpc2_v2.Handler) jsonrpc2_v2.Handler { 41509- return jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 41510- if req.Method == "workspace/executeCommand" { 41511- var params protocol.ExecuteCommandParams 41512- if err := json.Unmarshal(req.Params, ¶ms); err == nil { 41513- if params.Command == command { 41514- return run(¶ms) 41515- } 41516- } 41517- } 41518- 41519- return delegate.Handle(ctx, req) 41520- }) 41521- }) 41522-} 41523diff -urN a/gopls/internal/lsp/lsprpc/commandinterceptor_test.go b/gopls/internal/lsp/lsprpc/commandinterceptor_test.go 41524--- a/gopls/internal/lsp/lsprpc/commandinterceptor_test.go 2000-01-01 00:00:00.000000000 -0000 41525+++ b/gopls/internal/lsp/lsprpc/commandinterceptor_test.go 1970-01-01 00:00:00.000000000 +0000 41526@@ -1,42 +0,0 @@ 41527-// Copyright 2021 The Go Authors. All rights reserved. 41528-// Use of this source code is governed by a BSD-style 41529-// license that can be found in the LICENSE file. 41530- 41531-package lsprpc_test 41532- 41533-import ( 41534- "context" 41535- "testing" 41536- 41537- "golang.org/x/tools/gopls/internal/lsp/protocol" 41538- 41539- . "golang.org/x/tools/gopls/internal/lsp/lsprpc" 41540-) 41541- 41542-func TestCommandInterceptor(t *testing.T) { 41543- const command = "foo" 41544- caught := false 41545- intercept := func(_ *protocol.ExecuteCommandParams) (interface{}, error) { 41546- caught = true 41547- return map[string]interface{}{}, nil 41548- } 41549- 41550- ctx := context.Background() 41551- env := new(TestEnv) 41552- defer env.Shutdown(t) 41553- mw := CommandInterceptor(command, intercept) 41554- l, _ := env.serve(ctx, t, mw(noopBinder)) 41555- conn := env.dial(ctx, t, l.Dialer(), noopBinder, false) 41556- 41557- params := &protocol.ExecuteCommandParams{ 41558- Command: command, 41559- } 41560- var res interface{} 41561- err := conn.Call(ctx, "workspace/executeCommand", params).Await(ctx, &res) 41562- if err != nil { 41563- t.Fatal(err) 41564- } 41565- if !caught { 41566- t.Errorf("workspace/executeCommand was not intercepted") 41567- } 41568-} 41569diff -urN a/gopls/internal/lsp/lsprpc/dialer.go b/gopls/internal/lsp/lsprpc/dialer.go 41570--- a/gopls/internal/lsp/lsprpc/dialer.go 2000-01-01 00:00:00.000000000 -0000 41571+++ b/gopls/internal/lsp/lsprpc/dialer.go 1970-01-01 00:00:00.000000000 +0000 41572@@ -1,114 +0,0 @@ 41573-// Copyright 2021 The Go Authors. All rights reserved. 41574-// Use of this source code is governed by a BSD-style 41575-// license that can be found in the LICENSE file. 41576- 41577-package lsprpc 41578- 41579-import ( 41580- "context" 41581- "fmt" 41582- "io" 41583- "net" 41584- "os" 41585- "time" 41586- 41587- exec "golang.org/x/sys/execabs" 41588- "golang.org/x/tools/internal/event" 41589-) 41590- 41591-// AutoNetwork is the pseudo network type used to signal that gopls should use 41592-// automatic discovery to resolve a remote address. 41593-const AutoNetwork = "auto" 41594- 41595-// An AutoDialer is a jsonrpc2 dialer that understands the 'auto' network. 41596-type AutoDialer struct { 41597- network, addr string // the 'real' network and address 41598- isAuto bool // whether the server is on the 'auto' network 41599- 41600- executable string 41601- argFunc func(network, addr string) []string 41602-} 41603- 41604-func NewAutoDialer(rawAddr string, argFunc func(network, addr string) []string) (*AutoDialer, error) { 41605- d := AutoDialer{ 41606- argFunc: argFunc, 41607- } 41608- d.network, d.addr = ParseAddr(rawAddr) 41609- if d.network == AutoNetwork { 41610- d.isAuto = true 41611- bin, err := os.Executable() 41612- if err != nil { 41613- return nil, fmt.Errorf("getting executable: %w", err) 41614- } 41615- d.executable = bin 41616- d.network, d.addr = autoNetworkAddress(bin, d.addr) 41617- } 41618- return &d, nil 41619-} 41620- 41621-// Dial implements the jsonrpc2.Dialer interface. 41622-func (d *AutoDialer) Dial(ctx context.Context) (io.ReadWriteCloser, error) { 41623- conn, err := d.dialNet(ctx) 41624- return conn, err 41625-} 41626- 41627-// TODO(rFindley): remove this once we no longer need to integrate with v1 of 41628-// the jsonrpc2 package. 41629-func (d *AutoDialer) dialNet(ctx context.Context) (net.Conn, error) { 41630- // Attempt to verify that we own the remote. This is imperfect, but if we can 41631- // determine that the remote is owned by a different user, we should fail. 41632- ok, err := verifyRemoteOwnership(d.network, d.addr) 41633- if err != nil { 41634- // If the ownership check itself failed, we fail open but log an error to 41635- // the user. 41636- event.Error(ctx, "unable to check daemon socket owner, failing open", err) 41637- } else if !ok { 41638- // We successfully checked that the socket is not owned by us, we fail 41639- // closed. 41640- return nil, fmt.Errorf("socket %q is owned by a different user", d.addr) 41641- } 41642- const dialTimeout = 1 * time.Second 41643- // Try dialing our remote once, in case it is already running. 41644- netConn, err := net.DialTimeout(d.network, d.addr, dialTimeout) 41645- if err == nil { 41646- return netConn, nil 41647- } 41648- if d.isAuto && d.argFunc != nil { 41649- if d.network == "unix" { 41650- // Sometimes the socketfile isn't properly cleaned up when the server 41651- // shuts down. Since we have already tried and failed to dial this 41652- // address, it should *usually* be safe to remove the socket before 41653- // binding to the address. 41654- // TODO(rfindley): there is probably a race here if multiple server 41655- // instances are simultaneously starting up. 41656- if _, err := os.Stat(d.addr); err == nil { 41657- if err := os.Remove(d.addr); err != nil { 41658- return nil, fmt.Errorf("removing remote socket file: %w", err) 41659- } 41660- } 41661- } 41662- args := d.argFunc(d.network, d.addr) 41663- cmd := exec.Command(d.executable, args...) 41664- if err := runRemote(cmd); err != nil { 41665- return nil, err 41666- } 41667- } 41668- 41669- const retries = 5 41670- // It can take some time for the newly started server to bind to our address, 41671- // so we retry for a bit. 41672- for retry := 0; retry < retries; retry++ { 41673- startDial := time.Now() 41674- netConn, err = net.DialTimeout(d.network, d.addr, dialTimeout) 41675- if err == nil { 41676- return netConn, nil 41677- } 41678- event.Log(ctx, fmt.Sprintf("failed attempt #%d to connect to remote: %v\n", retry+2, err)) 41679- // In case our failure was a fast-failure, ensure we wait at least 41680- // f.dialTimeout before trying again. 41681- if retry != retries-1 { 41682- time.Sleep(dialTimeout - time.Since(startDial)) 41683- } 41684- } 41685- return nil, fmt.Errorf("dialing remote: %w", err) 41686-} 41687diff -urN a/gopls/internal/lsp/lsprpc/goenv.go b/gopls/internal/lsp/lsprpc/goenv.go 41688--- a/gopls/internal/lsp/lsprpc/goenv.go 2000-01-01 00:00:00.000000000 -0000 41689+++ b/gopls/internal/lsp/lsprpc/goenv.go 1970-01-01 00:00:00.000000000 +0000 41690@@ -1,96 +0,0 @@ 41691-// Copyright 2021 The Go Authors. All rights reserved. 41692-// Use of this source code is governed by a BSD-style 41693-// license that can be found in the LICENSE file. 41694- 41695-package lsprpc 41696- 41697-import ( 41698- "context" 41699- "encoding/json" 41700- "fmt" 41701- "os" 41702- 41703- "golang.org/x/tools/internal/event" 41704- "golang.org/x/tools/internal/gocommand" 41705- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 41706- "golang.org/x/tools/gopls/internal/lsp/protocol" 41707-) 41708- 41709-func GoEnvMiddleware() (Middleware, error) { 41710- return BindHandler(func(delegate jsonrpc2_v2.Handler) jsonrpc2_v2.Handler { 41711- return jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 41712- if req.Method == "initialize" { 41713- if err := addGoEnvToInitializeRequestV2(ctx, req); err != nil { 41714- event.Error(ctx, "adding go env to initialize", err) 41715- } 41716- } 41717- return delegate.Handle(ctx, req) 41718- }) 41719- }), nil 41720-} 41721- 41722-func addGoEnvToInitializeRequestV2(ctx context.Context, req *jsonrpc2_v2.Request) error { 41723- var params protocol.ParamInitialize 41724- if err := json.Unmarshal(req.Params, ¶ms); err != nil { 41725- return err 41726- } 41727- var opts map[string]interface{} 41728- switch v := params.InitializationOptions.(type) { 41729- case nil: 41730- opts = make(map[string]interface{}) 41731- case map[string]interface{}: 41732- opts = v 41733- default: 41734- return fmt.Errorf("unexpected type for InitializationOptions: %T", v) 41735- } 41736- envOpt, ok := opts["env"] 41737- if !ok { 41738- envOpt = make(map[string]interface{}) 41739- } 41740- env, ok := envOpt.(map[string]interface{}) 41741- if !ok { 41742- return fmt.Errorf("env option is %T, expected a map", envOpt) 41743- } 41744- goenv, err := getGoEnv(ctx, env) 41745- if err != nil { 41746- return err 41747- } 41748- // We don't want to propagate GOWORK unless explicitly set since that could mess with 41749- // path inference during cmd/go invocations, see golang/go#51825. 41750- _, goworkSet := os.LookupEnv("GOWORK") 41751- for govar, value := range goenv { 41752- if govar == "GOWORK" && !goworkSet { 41753- continue 41754- } 41755- env[govar] = value 41756- } 41757- opts["env"] = env 41758- params.InitializationOptions = opts 41759- raw, err := json.Marshal(params) 41760- if err != nil { 41761- return fmt.Errorf("marshaling updated options: %v", err) 41762- } 41763- req.Params = json.RawMessage(raw) 41764- return nil 41765-} 41766- 41767-func getGoEnv(ctx context.Context, env map[string]interface{}) (map[string]string, error) { 41768- var runEnv []string 41769- for k, v := range env { 41770- runEnv = append(runEnv, fmt.Sprintf("%s=%s", k, v)) 41771- } 41772- runner := gocommand.Runner{} 41773- output, err := runner.Run(ctx, gocommand.Invocation{ 41774- Verb: "env", 41775- Args: []string{"-json"}, 41776- Env: runEnv, 41777- }) 41778- if err != nil { 41779- return nil, err 41780- } 41781- envmap := make(map[string]string) 41782- if err := json.Unmarshal(output.Bytes(), &envmap); err != nil { 41783- return nil, err 41784- } 41785- return envmap, nil 41786-} 41787diff -urN a/gopls/internal/lsp/lsprpc/goenv_test.go b/gopls/internal/lsp/lsprpc/goenv_test.go 41788--- a/gopls/internal/lsp/lsprpc/goenv_test.go 2000-01-01 00:00:00.000000000 -0000 41789+++ b/gopls/internal/lsp/lsprpc/goenv_test.go 1970-01-01 00:00:00.000000000 +0000 41790@@ -1,65 +0,0 @@ 41791-// Copyright 2021 The Go Authors. All rights reserved. 41792-// Use of this source code is governed by a BSD-style 41793-// license that can be found in the LICENSE file. 41794- 41795-package lsprpc_test 41796- 41797-import ( 41798- "context" 41799- "testing" 41800- 41801- "golang.org/x/tools/gopls/internal/lsp/protocol" 41802- 41803- . "golang.org/x/tools/gopls/internal/lsp/lsprpc" 41804-) 41805- 41806-type initServer struct { 41807- protocol.Server 41808- 41809- params *protocol.ParamInitialize 41810-} 41811- 41812-func (s *initServer) Initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) { 41813- s.params = params 41814- return &protocol.InitializeResult{}, nil 41815-} 41816- 41817-func TestGoEnvMiddleware(t *testing.T) { 41818- ctx := context.Background() 41819- 41820- server := &initServer{} 41821- env := new(TestEnv) 41822- defer env.Shutdown(t) 41823- l, _ := env.serve(ctx, t, staticServerBinder(server)) 41824- mw, err := GoEnvMiddleware() 41825- if err != nil { 41826- t.Fatal(err) 41827- } 41828- binder := mw(NewForwardBinder(l.Dialer())) 41829- l, _ = env.serve(ctx, t, binder) 41830- conn := env.dial(ctx, t, l.Dialer(), noopBinder, true) 41831- dispatch := protocol.ServerDispatcherV2(conn) 41832- initParams := &protocol.ParamInitialize{} 41833- initParams.InitializationOptions = map[string]interface{}{ 41834- "env": map[string]interface{}{ 41835- "GONOPROXY": "example.com", 41836- }, 41837- } 41838- if _, err := dispatch.Initialize(ctx, initParams); err != nil { 41839- t.Fatal(err) 41840- } 41841- 41842- if server.params == nil { 41843- t.Fatalf("initialize params are unset") 41844- } 41845- envOpts := server.params.InitializationOptions.(map[string]interface{})["env"].(map[string]interface{}) 41846- 41847- // Check for an arbitrary Go variable. It should be set. 41848- if _, ok := envOpts["GOPRIVATE"]; !ok { 41849- t.Errorf("Go environment variable GOPRIVATE unset in initialization options") 41850- } 41851- // Check that the variable present in our user config was not overwritten. 41852- if got, want := envOpts["GONOPROXY"], "example.com"; got != want { 41853- t.Errorf("GONOPROXY=%q, want %q", got, want) 41854- } 41855-} 41856diff -urN a/gopls/internal/lsp/lsprpc/lsprpc.go b/gopls/internal/lsp/lsprpc/lsprpc.go 41857--- a/gopls/internal/lsp/lsprpc/lsprpc.go 2000-01-01 00:00:00.000000000 -0000 41858+++ b/gopls/internal/lsp/lsprpc/lsprpc.go 1970-01-01 00:00:00.000000000 +0000 41859@@ -1,543 +0,0 @@ 41860-// Copyright 2020 The Go Authors. All rights reserved. 41861-// Use of this source code is governed by a BSD-style 41862-// license that can be found in the LICENSE file. 41863- 41864-// Package lsprpc implements a jsonrpc2.StreamServer that may be used to 41865-// serve the LSP on a jsonrpc2 channel. 41866-package lsprpc 41867- 41868-import ( 41869- "context" 41870- "encoding/json" 41871- "fmt" 41872- "log" 41873- "net" 41874- "os" 41875- "strconv" 41876- "strings" 41877- "sync" 41878- "sync/atomic" 41879- "time" 41880- 41881- "golang.org/x/tools/gopls/internal/lsp" 41882- "golang.org/x/tools/gopls/internal/lsp/cache" 41883- "golang.org/x/tools/gopls/internal/lsp/command" 41884- "golang.org/x/tools/gopls/internal/lsp/debug" 41885- "golang.org/x/tools/gopls/internal/lsp/protocol" 41886- "golang.org/x/tools/gopls/internal/lsp/source" 41887- "golang.org/x/tools/internal/event" 41888- "golang.org/x/tools/internal/event/tag" 41889- "golang.org/x/tools/internal/jsonrpc2" 41890-) 41891- 41892-// Unique identifiers for client/server. 41893-var serverIndex int64 41894- 41895-// The StreamServer type is a jsonrpc2.StreamServer that handles incoming 41896-// streams as a new LSP session, using a shared cache. 41897-type StreamServer struct { 41898- cache *cache.Cache 41899- // daemon controls whether or not to log new connections. 41900- daemon bool 41901- 41902- // optionsOverrides is passed to newly created sessions. 41903- optionsOverrides func(*source.Options) 41904- 41905- // serverForTest may be set to a test fake for testing. 41906- serverForTest protocol.Server 41907-} 41908- 41909-// NewStreamServer creates a StreamServer using the shared cache. If 41910-// withTelemetry is true, each session is instrumented with telemetry that 41911-// records RPC statistics. 41912-func NewStreamServer(cache *cache.Cache, daemon bool, optionsFunc func(*source.Options)) *StreamServer { 41913- return &StreamServer{cache: cache, daemon: daemon, optionsOverrides: optionsFunc} 41914-} 41915- 41916-func (s *StreamServer) Binder() *ServerBinder { 41917- newServer := func(ctx context.Context, client protocol.ClientCloser) protocol.Server { 41918- session := cache.NewSession(ctx, s.cache, s.optionsOverrides) 41919- server := s.serverForTest 41920- if server == nil { 41921- server = lsp.NewServer(session, client) 41922- if instance := debug.GetInstance(ctx); instance != nil { 41923- instance.AddService(server, session) 41924- } 41925- } 41926- return server 41927- } 41928- return NewServerBinder(newServer) 41929-} 41930- 41931-// ServeStream implements the jsonrpc2.StreamServer interface, by handling 41932-// incoming streams using a new lsp server. 41933-func (s *StreamServer) ServeStream(ctx context.Context, conn jsonrpc2.Conn) error { 41934- client := protocol.ClientDispatcher(conn) 41935- session := cache.NewSession(ctx, s.cache, s.optionsOverrides) 41936- server := s.serverForTest 41937- if server == nil { 41938- server = lsp.NewServer(session, client) 41939- if instance := debug.GetInstance(ctx); instance != nil { 41940- instance.AddService(server, session) 41941- } 41942- } 41943- // Clients may or may not send a shutdown message. Make sure the server is 41944- // shut down. 41945- // TODO(rFindley): this shutdown should perhaps be on a disconnected context. 41946- defer func() { 41947- if err := server.Shutdown(ctx); err != nil { 41948- event.Error(ctx, "error shutting down", err) 41949- } 41950- }() 41951- executable, err := os.Executable() 41952- if err != nil { 41953- log.Printf("error getting gopls path: %v", err) 41954- executable = "" 41955- } 41956- ctx = protocol.WithClient(ctx, client) 41957- conn.Go(ctx, 41958- protocol.Handlers( 41959- handshaker(session, executable, s.daemon, 41960- protocol.ServerHandler(server, 41961- jsonrpc2.MethodNotFound)))) 41962- if s.daemon { 41963- log.Printf("Session %s: connected", session.ID()) 41964- defer log.Printf("Session %s: exited", session.ID()) 41965- } 41966- <-conn.Done() 41967- return conn.Err() 41968-} 41969- 41970-// A Forwarder is a jsonrpc2.StreamServer that handles an LSP stream by 41971-// forwarding it to a remote. This is used when the gopls process started by 41972-// the editor is in the `-remote` mode, which means it finds and connects to a 41973-// separate gopls daemon. In these cases, we still want the forwarder gopls to 41974-// be instrumented with telemetry, and want to be able to in some cases hijack 41975-// the jsonrpc2 connection with the daemon. 41976-type Forwarder struct { 41977- dialer *AutoDialer 41978- 41979- mu sync.Mutex 41980- // Hold on to the server connection so that we can redo the handshake if any 41981- // information changes. 41982- serverConn jsonrpc2.Conn 41983- serverID string 41984-} 41985- 41986-// NewForwarder creates a new Forwarder, ready to forward connections to the 41987-// remote server specified by rawAddr. If provided and rawAddr indicates an 41988-// 'automatic' address (starting with 'auto;'), argFunc may be used to start a 41989-// remote server for the auto-discovered address. 41990-func NewForwarder(rawAddr string, argFunc func(network, address string) []string) (*Forwarder, error) { 41991- dialer, err := NewAutoDialer(rawAddr, argFunc) 41992- if err != nil { 41993- return nil, err 41994- } 41995- fwd := &Forwarder{ 41996- dialer: dialer, 41997- } 41998- return fwd, nil 41999-} 42000- 42001-// QueryServerState queries the server state of the current server. 42002-func QueryServerState(ctx context.Context, addr string) (*ServerState, error) { 42003- serverConn, err := dialRemote(ctx, addr) 42004- if err != nil { 42005- return nil, err 42006- } 42007- var state ServerState 42008- if err := protocol.Call(ctx, serverConn, sessionsMethod, nil, &state); err != nil { 42009- return nil, fmt.Errorf("querying server state: %w", err) 42010- } 42011- return &state, nil 42012-} 42013- 42014-// dialRemote is used for making calls into the gopls daemon. addr should be a 42015-// URL, possibly on the synthetic 'auto' network (e.g. tcp://..., unix://..., 42016-// or auto://...). 42017-func dialRemote(ctx context.Context, addr string) (jsonrpc2.Conn, error) { 42018- network, address := ParseAddr(addr) 42019- if network == AutoNetwork { 42020- gp, err := os.Executable() 42021- if err != nil { 42022- return nil, fmt.Errorf("getting gopls path: %w", err) 42023- } 42024- network, address = autoNetworkAddress(gp, address) 42025- } 42026- netConn, err := net.DialTimeout(network, address, 5*time.Second) 42027- if err != nil { 42028- return nil, fmt.Errorf("dialing remote: %w", err) 42029- } 42030- serverConn := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(netConn)) 42031- serverConn.Go(ctx, jsonrpc2.MethodNotFound) 42032- return serverConn, nil 42033-} 42034- 42035-func ExecuteCommand(ctx context.Context, addr string, id string, request, result interface{}) error { 42036- serverConn, err := dialRemote(ctx, addr) 42037- if err != nil { 42038- return err 42039- } 42040- args, err := command.MarshalArgs(request) 42041- if err != nil { 42042- return err 42043- } 42044- params := protocol.ExecuteCommandParams{ 42045- Command: id, 42046- Arguments: args, 42047- } 42048- return protocol.Call(ctx, serverConn, "workspace/executeCommand", params, result) 42049-} 42050- 42051-// ServeStream dials the forwarder remote and binds the remote to serve the LSP 42052-// on the incoming stream. 42053-func (f *Forwarder) ServeStream(ctx context.Context, clientConn jsonrpc2.Conn) error { 42054- client := protocol.ClientDispatcher(clientConn) 42055- 42056- netConn, err := f.dialer.dialNet(ctx) 42057- if err != nil { 42058- return fmt.Errorf("forwarder: connecting to remote: %w", err) 42059- } 42060- serverConn := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(netConn)) 42061- server := protocol.ServerDispatcher(serverConn) 42062- 42063- // Forward between connections. 42064- serverConn.Go(ctx, 42065- protocol.Handlers( 42066- protocol.ClientHandler(client, 42067- jsonrpc2.MethodNotFound))) 42068- 42069- // Don't run the clientConn yet, so that we can complete the handshake before 42070- // processing any client messages. 42071- 42072- // Do a handshake with the server instance to exchange debug information. 42073- index := atomic.AddInt64(&serverIndex, 1) 42074- f.mu.Lock() 42075- f.serverConn = serverConn 42076- f.serverID = strconv.FormatInt(index, 10) 42077- f.mu.Unlock() 42078- f.handshake(ctx) 42079- clientConn.Go(ctx, 42080- protocol.Handlers( 42081- f.handler( 42082- protocol.ServerHandler(server, 42083- jsonrpc2.MethodNotFound)))) 42084- 42085- select { 42086- case <-serverConn.Done(): 42087- clientConn.Close() 42088- case <-clientConn.Done(): 42089- serverConn.Close() 42090- } 42091- 42092- err = nil 42093- if serverConn.Err() != nil { 42094- err = fmt.Errorf("remote disconnected: %v", serverConn.Err()) 42095- } else if clientConn.Err() != nil { 42096- err = fmt.Errorf("client disconnected: %v", clientConn.Err()) 42097- } 42098- event.Log(ctx, fmt.Sprintf("forwarder: exited with error: %v", err)) 42099- return err 42100-} 42101- 42102-// TODO(rfindley): remove this handshaking in favor of middleware. 42103-func (f *Forwarder) handshake(ctx context.Context) { 42104- // This call to os.Executable is redundant, and will be eliminated by the 42105- // transition to the V2 API. 42106- goplsPath, err := os.Executable() 42107- if err != nil { 42108- event.Error(ctx, "getting executable for handshake", err) 42109- goplsPath = "" 42110- } 42111- var ( 42112- hreq = handshakeRequest{ 42113- ServerID: f.serverID, 42114- GoplsPath: goplsPath, 42115- } 42116- hresp handshakeResponse 42117- ) 42118- if di := debug.GetInstance(ctx); di != nil { 42119- hreq.Logfile = di.Logfile 42120- hreq.DebugAddr = di.ListenedDebugAddress() 42121- } 42122- if err := protocol.Call(ctx, f.serverConn, handshakeMethod, hreq, &hresp); err != nil { 42123- // TODO(rfindley): at some point in the future we should return an error 42124- // here. Handshakes have become functional in nature. 42125- event.Error(ctx, "forwarder: gopls handshake failed", err) 42126- } 42127- if hresp.GoplsPath != goplsPath { 42128- event.Error(ctx, "", fmt.Errorf("forwarder: gopls path mismatch: forwarder is %q, remote is %q", goplsPath, hresp.GoplsPath)) 42129- } 42130- event.Log(ctx, "New server", 42131- tag.NewServer.Of(f.serverID), 42132- tag.Logfile.Of(hresp.Logfile), 42133- tag.DebugAddress.Of(hresp.DebugAddr), 42134- tag.GoplsPath.Of(hresp.GoplsPath), 42135- tag.ClientID.Of(hresp.SessionID), 42136- ) 42137-} 42138- 42139-func ConnectToRemote(ctx context.Context, addr string) (net.Conn, error) { 42140- dialer, err := NewAutoDialer(addr, nil) 42141- if err != nil { 42142- return nil, err 42143- } 42144- return dialer.dialNet(ctx) 42145-} 42146- 42147-// handler intercepts messages to the daemon to enrich them with local 42148-// information. 42149-func (f *Forwarder) handler(handler jsonrpc2.Handler) jsonrpc2.Handler { 42150- return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error { 42151- // Intercept certain messages to add special handling. 42152- switch r.Method() { 42153- case "initialize": 42154- if newr, err := addGoEnvToInitializeRequest(ctx, r); err == nil { 42155- r = newr 42156- } else { 42157- log.Printf("unable to add local env to initialize request: %v", err) 42158- } 42159- case "workspace/executeCommand": 42160- var params protocol.ExecuteCommandParams 42161- if err := json.Unmarshal(r.Params(), ¶ms); err == nil { 42162- if params.Command == command.StartDebugging.ID() { 42163- var args command.DebuggingArgs 42164- if err := command.UnmarshalArgs(params.Arguments, &args); err == nil { 42165- reply = f.replyWithDebugAddress(ctx, reply, args) 42166- } else { 42167- event.Error(ctx, "unmarshaling debugging args", err) 42168- } 42169- } 42170- } else { 42171- event.Error(ctx, "intercepting executeCommand request", err) 42172- } 42173- } 42174- // The gopls workspace environment defaults to the process environment in 42175- // which gopls daemon was started. To avoid discrepancies in Go environment 42176- // between the editor and daemon, inject any unset variables in `go env` 42177- // into the options sent by initialize. 42178- // 42179- // See also golang.org/issue/37830. 42180- return handler(ctx, reply, r) 42181- } 42182-} 42183- 42184-// addGoEnvToInitializeRequest builds a new initialize request in which we set 42185-// any environment variables output by `go env` and not already present in the 42186-// request. 42187-// 42188-// It returns an error if r is not an initialize request, or is otherwise 42189-// malformed. 42190-func addGoEnvToInitializeRequest(ctx context.Context, r jsonrpc2.Request) (jsonrpc2.Request, error) { 42191- var params protocol.ParamInitialize 42192- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 42193- return nil, err 42194- } 42195- var opts map[string]interface{} 42196- switch v := params.InitializationOptions.(type) { 42197- case nil: 42198- opts = make(map[string]interface{}) 42199- case map[string]interface{}: 42200- opts = v 42201- default: 42202- return nil, fmt.Errorf("unexpected type for InitializationOptions: %T", v) 42203- } 42204- envOpt, ok := opts["env"] 42205- if !ok { 42206- envOpt = make(map[string]interface{}) 42207- } 42208- env, ok := envOpt.(map[string]interface{}) 42209- if !ok { 42210- return nil, fmt.Errorf(`env option is %T, expected a map`, envOpt) 42211- } 42212- goenv, err := getGoEnv(ctx, env) 42213- if err != nil { 42214- return nil, err 42215- } 42216- // We don't want to propagate GOWORK unless explicitly set since that could mess with 42217- // path inference during cmd/go invocations, see golang/go#51825. 42218- _, goworkSet := os.LookupEnv("GOWORK") 42219- for govar, value := range goenv { 42220- if govar == "GOWORK" && !goworkSet { 42221- continue 42222- } 42223- env[govar] = value 42224- } 42225- opts["env"] = env 42226- params.InitializationOptions = opts 42227- call, ok := r.(*jsonrpc2.Call) 42228- if !ok { 42229- return nil, fmt.Errorf("%T is not a *jsonrpc2.Call", r) 42230- } 42231- return jsonrpc2.NewCall(call.ID(), "initialize", params) 42232-} 42233- 42234-func (f *Forwarder) replyWithDebugAddress(outerCtx context.Context, r jsonrpc2.Replier, args command.DebuggingArgs) jsonrpc2.Replier { 42235- di := debug.GetInstance(outerCtx) 42236- if di == nil { 42237- event.Log(outerCtx, "no debug instance to start") 42238- return r 42239- } 42240- return func(ctx context.Context, result interface{}, outerErr error) error { 42241- if outerErr != nil { 42242- return r(ctx, result, outerErr) 42243- } 42244- // Enrich the result with our own debugging information. Since we're an 42245- // intermediary, the jsonrpc2 package has deserialized the result into 42246- // maps, by default. Re-do the unmarshalling. 42247- raw, err := json.Marshal(result) 42248- if err != nil { 42249- event.Error(outerCtx, "marshaling intermediate command result", err) 42250- return r(ctx, result, err) 42251- } 42252- var modified command.DebuggingResult 42253- if err := json.Unmarshal(raw, &modified); err != nil { 42254- event.Error(outerCtx, "unmarshaling intermediate command result", err) 42255- return r(ctx, result, err) 42256- } 42257- addr := args.Addr 42258- if addr == "" { 42259- addr = "localhost:0" 42260- } 42261- addr, err = di.Serve(outerCtx, addr) 42262- if err != nil { 42263- event.Error(outerCtx, "starting debug server", err) 42264- return r(ctx, result, outerErr) 42265- } 42266- urls := []string{"http://" + addr} 42267- modified.URLs = append(urls, modified.URLs...) 42268- go f.handshake(ctx) 42269- return r(ctx, modified, nil) 42270- } 42271-} 42272- 42273-// A handshakeRequest identifies a client to the LSP server. 42274-type handshakeRequest struct { 42275- // ServerID is the ID of the server on the client. This should usually be 0. 42276- ServerID string `json:"serverID"` 42277- // Logfile is the location of the clients log file. 42278- Logfile string `json:"logfile"` 42279- // DebugAddr is the client debug address. 42280- DebugAddr string `json:"debugAddr"` 42281- // GoplsPath is the path to the Gopls binary running the current client 42282- // process. 42283- GoplsPath string `json:"goplsPath"` 42284-} 42285- 42286-// A handshakeResponse is returned by the LSP server to tell the LSP client 42287-// information about its session. 42288-type handshakeResponse struct { 42289- // SessionID is the server session associated with the client. 42290- SessionID string `json:"sessionID"` 42291- // Logfile is the location of the server logs. 42292- Logfile string `json:"logfile"` 42293- // DebugAddr is the server debug address. 42294- DebugAddr string `json:"debugAddr"` 42295- // GoplsPath is the path to the Gopls binary running the current server 42296- // process. 42297- GoplsPath string `json:"goplsPath"` 42298-} 42299- 42300-// ClientSession identifies a current client LSP session on the server. Note 42301-// that it looks similar to handshakeResposne, but in fact 'Logfile' and 42302-// 'DebugAddr' now refer to the client. 42303-type ClientSession struct { 42304- SessionID string `json:"sessionID"` 42305- Logfile string `json:"logfile"` 42306- DebugAddr string `json:"debugAddr"` 42307-} 42308- 42309-// ServerState holds information about the gopls daemon process, including its 42310-// debug information and debug information of all of its current connected 42311-// clients. 42312-type ServerState struct { 42313- Logfile string `json:"logfile"` 42314- DebugAddr string `json:"debugAddr"` 42315- GoplsPath string `json:"goplsPath"` 42316- CurrentClientID string `json:"currentClientID"` 42317- Clients []ClientSession `json:"clients"` 42318-} 42319- 42320-const ( 42321- handshakeMethod = "gopls/handshake" 42322- sessionsMethod = "gopls/sessions" 42323-) 42324- 42325-func handshaker(session *cache.Session, goplsPath string, logHandshakes bool, handler jsonrpc2.Handler) jsonrpc2.Handler { 42326- return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error { 42327- switch r.Method() { 42328- case handshakeMethod: 42329- // We log.Printf in this handler, rather than event.Log when we want logs 42330- // to go to the daemon log rather than being reflected back to the 42331- // client. 42332- var req handshakeRequest 42333- if err := json.Unmarshal(r.Params(), &req); err != nil { 42334- if logHandshakes { 42335- log.Printf("Error processing handshake for session %s: %v", session.ID(), err) 42336- } 42337- sendError(ctx, reply, err) 42338- return nil 42339- } 42340- if logHandshakes { 42341- log.Printf("Session %s: got handshake. Logfile: %q, Debug addr: %q", session.ID(), req.Logfile, req.DebugAddr) 42342- } 42343- event.Log(ctx, "Handshake session update", 42344- cache.KeyUpdateSession.Of(session), 42345- tag.DebugAddress.Of(req.DebugAddr), 42346- tag.Logfile.Of(req.Logfile), 42347- tag.ServerID.Of(req.ServerID), 42348- tag.GoplsPath.Of(req.GoplsPath), 42349- ) 42350- resp := handshakeResponse{ 42351- SessionID: session.ID(), 42352- GoplsPath: goplsPath, 42353- } 42354- if di := debug.GetInstance(ctx); di != nil { 42355- resp.Logfile = di.Logfile 42356- resp.DebugAddr = di.ListenedDebugAddress() 42357- } 42358- return reply(ctx, resp, nil) 42359- 42360- case sessionsMethod: 42361- resp := ServerState{ 42362- GoplsPath: goplsPath, 42363- CurrentClientID: session.ID(), 42364- } 42365- if di := debug.GetInstance(ctx); di != nil { 42366- resp.Logfile = di.Logfile 42367- resp.DebugAddr = di.ListenedDebugAddress() 42368- for _, c := range di.State.Clients() { 42369- resp.Clients = append(resp.Clients, ClientSession{ 42370- SessionID: c.Session.ID(), 42371- Logfile: c.Logfile, 42372- DebugAddr: c.DebugAddress, 42373- }) 42374- } 42375- } 42376- return reply(ctx, resp, nil) 42377- } 42378- return handler(ctx, reply, r) 42379- } 42380-} 42381- 42382-func sendError(ctx context.Context, reply jsonrpc2.Replier, err error) { 42383- err = fmt.Errorf("%v: %w", err, jsonrpc2.ErrParse) 42384- if err := reply(ctx, nil, err); err != nil { 42385- event.Error(ctx, "", err) 42386- } 42387-} 42388- 42389-// ParseAddr parses the address of a gopls remote. 42390-// TODO(rFindley): further document this syntax, and allow URI-style remote 42391-// addresses such as "auto://...". 42392-func ParseAddr(listen string) (network string, address string) { 42393- // Allow passing just -remote=auto, as a shorthand for using automatic remote 42394- // resolution. 42395- if listen == AutoNetwork { 42396- return AutoNetwork, "" 42397- } 42398- if parts := strings.SplitN(listen, ";", 2); len(parts) == 2 { 42399- return parts[0], parts[1] 42400- } 42401- return "tcp", listen 42402-} 42403diff -urN a/gopls/internal/lsp/lsprpc/lsprpc_test.go b/gopls/internal/lsp/lsprpc/lsprpc_test.go 42404--- a/gopls/internal/lsp/lsprpc/lsprpc_test.go 2000-01-01 00:00:00.000000000 -0000 42405+++ b/gopls/internal/lsp/lsprpc/lsprpc_test.go 1970-01-01 00:00:00.000000000 +0000 42406@@ -1,345 +0,0 @@ 42407-// Copyright 2020 The Go Authors. All rights reserved. 42408-// Use of this source code is governed by a BSD-style 42409-// license that can be found in the LICENSE file. 42410- 42411-package lsprpc 42412- 42413-import ( 42414- "context" 42415- "errors" 42416- "regexp" 42417- "strings" 42418- "testing" 42419- "time" 42420- 42421- "golang.org/x/tools/gopls/internal/lsp/cache" 42422- "golang.org/x/tools/gopls/internal/lsp/debug" 42423- "golang.org/x/tools/gopls/internal/lsp/fake" 42424- "golang.org/x/tools/gopls/internal/lsp/protocol" 42425- "golang.org/x/tools/internal/event" 42426- "golang.org/x/tools/internal/jsonrpc2" 42427- "golang.org/x/tools/internal/jsonrpc2/servertest" 42428-) 42429- 42430-type FakeClient struct { 42431- protocol.Client 42432- 42433- Logs chan string 42434-} 42435- 42436-func (c FakeClient) LogMessage(ctx context.Context, params *protocol.LogMessageParams) error { 42437- c.Logs <- params.Message 42438- return nil 42439-} 42440- 42441-// fakeServer is intended to be embedded in the test fakes below, to trivially 42442-// implement Shutdown. 42443-type fakeServer struct { 42444- protocol.Server 42445-} 42446- 42447-func (fakeServer) Shutdown(ctx context.Context) error { 42448- return nil 42449-} 42450- 42451-type PingServer struct{ fakeServer } 42452- 42453-func (s PingServer) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { 42454- event.Log(ctx, "ping") 42455- return nil 42456-} 42457- 42458-func TestClientLogging(t *testing.T) { 42459- ctx, cancel := context.WithCancel(context.Background()) 42460- defer cancel() 42461- 42462- server := PingServer{} 42463- client := FakeClient{Logs: make(chan string, 10)} 42464- 42465- ctx = debug.WithInstance(ctx, "", "") 42466- ss := NewStreamServer(cache.New(nil), false, nil) 42467- ss.serverForTest = server 42468- ts := servertest.NewPipeServer(ss, nil) 42469- defer checkClose(t, ts.Close) 42470- cc := ts.Connect(ctx) 42471- cc.Go(ctx, protocol.ClientHandler(client, jsonrpc2.MethodNotFound)) 42472- 42473- if err := protocol.ServerDispatcher(cc).DidOpen(ctx, &protocol.DidOpenTextDocumentParams{}); err != nil { 42474- t.Errorf("DidOpen: %v", err) 42475- } 42476- 42477- select { 42478- case got := <-client.Logs: 42479- want := "ping" 42480- matched, err := regexp.MatchString(want, got) 42481- if err != nil { 42482- t.Fatal(err) 42483- } 42484- if !matched { 42485- t.Errorf("got log %q, want a log containing %q", got, want) 42486- } 42487- case <-time.After(1 * time.Second): 42488- t.Error("timeout waiting for client log") 42489- } 42490-} 42491- 42492-// WaitableServer instruments LSP request so that we can control their timing. 42493-// The requests chosen are arbitrary: we simply needed one that blocks, and 42494-// another that doesn't. 42495-type WaitableServer struct { 42496- fakeServer 42497- 42498- Started chan struct{} 42499- Completed chan error 42500-} 42501- 42502-func (s WaitableServer) Hover(ctx context.Context, _ *protocol.HoverParams) (_ *protocol.Hover, err error) { 42503- s.Started <- struct{}{} 42504- defer func() { 42505- s.Completed <- err 42506- }() 42507- select { 42508- case <-ctx.Done(): 42509- return nil, errors.New("cancelled hover") 42510- case <-time.After(10 * time.Second): 42511- } 42512- return &protocol.Hover{}, nil 42513-} 42514- 42515-func (s WaitableServer) ResolveCompletionItem(_ context.Context, item *protocol.CompletionItem) (*protocol.CompletionItem, error) { 42516- return item, nil 42517-} 42518- 42519-func checkClose(t *testing.T, closer func() error) { 42520- t.Helper() 42521- if err := closer(); err != nil { 42522- t.Errorf("closing: %v", err) 42523- } 42524-} 42525- 42526-func setupForwarding(ctx context.Context, t *testing.T, s protocol.Server) (direct, forwarded servertest.Connector, cleanup func()) { 42527- t.Helper() 42528- serveCtx := debug.WithInstance(ctx, "", "") 42529- ss := NewStreamServer(cache.New(nil), false, nil) 42530- ss.serverForTest = s 42531- tsDirect := servertest.NewTCPServer(serveCtx, ss, nil) 42532- 42533- forwarder, err := NewForwarder("tcp;"+tsDirect.Addr, nil) 42534- if err != nil { 42535- t.Fatal(err) 42536- } 42537- tsForwarded := servertest.NewPipeServer(forwarder, nil) 42538- return tsDirect, tsForwarded, func() { 42539- checkClose(t, tsDirect.Close) 42540- checkClose(t, tsForwarded.Close) 42541- } 42542-} 42543- 42544-func TestRequestCancellation(t *testing.T) { 42545- ctx := context.Background() 42546- server := WaitableServer{ 42547- Started: make(chan struct{}), 42548- Completed: make(chan error), 42549- } 42550- tsDirect, tsForwarded, cleanup := setupForwarding(ctx, t, server) 42551- defer cleanup() 42552- tests := []struct { 42553- serverType string 42554- ts servertest.Connector 42555- }{ 42556- {"direct", tsDirect}, 42557- {"forwarder", tsForwarded}, 42558- } 42559- 42560- for _, test := range tests { 42561- t.Run(test.serverType, func(t *testing.T) { 42562- cc := test.ts.Connect(ctx) 42563- sd := protocol.ServerDispatcher(cc) 42564- cc.Go(ctx, 42565- protocol.Handlers( 42566- jsonrpc2.MethodNotFound)) 42567- 42568- ctx := context.Background() 42569- ctx, cancel := context.WithCancel(ctx) 42570- 42571- result := make(chan error) 42572- go func() { 42573- _, err := sd.Hover(ctx, &protocol.HoverParams{}) 42574- result <- err 42575- }() 42576- // Wait for the Hover request to start. 42577- <-server.Started 42578- cancel() 42579- if err := <-result; err == nil { 42580- t.Error("nil error for cancelled Hover(), want non-nil") 42581- } 42582- if err := <-server.Completed; err == nil || !strings.Contains(err.Error(), "cancelled hover") { 42583- t.Errorf("Hover(): unexpected server-side error %v", err) 42584- } 42585- }) 42586- } 42587-} 42588- 42589-const exampleProgram = ` 42590--- go.mod -- 42591-module mod 42592- 42593-go 1.12 42594--- main.go -- 42595-package main 42596- 42597-import "fmt" 42598- 42599-func main() { 42600- fmt.Println("Hello World.") 42601-}` 42602- 42603-func TestDebugInfoLifecycle(t *testing.T) { 42604- sb, err := fake.NewSandbox(&fake.SandboxConfig{Files: fake.UnpackTxt(exampleProgram)}) 42605- if err != nil { 42606- t.Fatal(err) 42607- } 42608- defer func() { 42609- if err := sb.Close(); err != nil { 42610- // TODO(golang/go#38490): we can't currently make this an error because 42611- // it fails on Windows: the workspace directory is still locked by a 42612- // separate Go process. 42613- // Once we have a reliable way to wait for proper shutdown, make this an 42614- // error. 42615- t.Logf("closing workspace failed: %v", err) 42616- } 42617- }() 42618- 42619- baseCtx, cancel := context.WithCancel(context.Background()) 42620- defer cancel() 42621- clientCtx := debug.WithInstance(baseCtx, "", "") 42622- serverCtx := debug.WithInstance(baseCtx, "", "") 42623- 42624- cache := cache.New(nil) 42625- ss := NewStreamServer(cache, false, nil) 42626- tsBackend := servertest.NewTCPServer(serverCtx, ss, nil) 42627- 42628- forwarder, err := NewForwarder("tcp;"+tsBackend.Addr, nil) 42629- if err != nil { 42630- t.Fatal(err) 42631- } 42632- tsForwarder := servertest.NewPipeServer(forwarder, nil) 42633- 42634- const skipApplyEdits = false 42635- ed1, err := fake.NewEditor(sb, fake.EditorConfig{}).Connect(clientCtx, tsForwarder, fake.ClientHooks{}, skipApplyEdits) 42636- if err != nil { 42637- t.Fatal(err) 42638- } 42639- defer ed1.Close(clientCtx) 42640- ed2, err := fake.NewEditor(sb, fake.EditorConfig{}).Connect(baseCtx, tsBackend, fake.ClientHooks{}, skipApplyEdits) 42641- if err != nil { 42642- t.Fatal(err) 42643- } 42644- defer ed2.Close(baseCtx) 42645- 42646- serverDebug := debug.GetInstance(serverCtx) 42647- if got, want := len(serverDebug.State.Clients()), 2; got != want { 42648- t.Errorf("len(server:Clients) = %d, want %d", got, want) 42649- } 42650- if got, want := len(serverDebug.State.Sessions()), 2; got != want { 42651- t.Errorf("len(server:Sessions) = %d, want %d", got, want) 42652- } 42653- clientDebug := debug.GetInstance(clientCtx) 42654- if got, want := len(clientDebug.State.Servers()), 1; got != want { 42655- t.Errorf("len(client:Servers) = %d, want %d", got, want) 42656- } 42657- // Close one of the connections to verify that the client and session were 42658- // dropped. 42659- if err := ed1.Close(clientCtx); err != nil { 42660- t.Fatal(err) 42661- } 42662- /*TODO: at this point we have verified the editor is closed 42663- However there is no way currently to wait for all associated go routines to 42664- go away, and we need to wait for those to trigger the client drop 42665- for now we just give it a little bit of time, but we need to fix this 42666- in a principled way 42667- */ 42668- start := time.Now() 42669- delay := time.Millisecond 42670- const maxWait = time.Second 42671- for len(serverDebug.State.Clients()) > 1 { 42672- if time.Since(start) > maxWait { 42673- break 42674- } 42675- time.Sleep(delay) 42676- delay *= 2 42677- } 42678- if got, want := len(serverDebug.State.Clients()), 1; got != want { 42679- t.Errorf("len(server:Clients) = %d, want %d", got, want) 42680- } 42681- if got, want := len(serverDebug.State.Sessions()), 1; got != want { 42682- t.Errorf("len(server:Sessions()) = %d, want %d", got, want) 42683- } 42684-} 42685- 42686-type initServer struct { 42687- fakeServer 42688- 42689- params *protocol.ParamInitialize 42690-} 42691- 42692-func (s *initServer) Initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) { 42693- s.params = params 42694- return &protocol.InitializeResult{}, nil 42695-} 42696- 42697-func TestEnvForwarding(t *testing.T) { 42698- ctx := context.Background() 42699- 42700- server := &initServer{} 42701- _, tsForwarded, cleanup := setupForwarding(ctx, t, server) 42702- defer cleanup() 42703- 42704- conn := tsForwarded.Connect(ctx) 42705- conn.Go(ctx, jsonrpc2.MethodNotFound) 42706- dispatch := protocol.ServerDispatcher(conn) 42707- initParams := &protocol.ParamInitialize{} 42708- initParams.InitializationOptions = map[string]interface{}{ 42709- "env": map[string]interface{}{ 42710- "GONOPROXY": "example.com", 42711- }, 42712- } 42713- _, err := dispatch.Initialize(ctx, initParams) 42714- if err != nil { 42715- t.Fatal(err) 42716- } 42717- if server.params == nil { 42718- t.Fatalf("initialize params are unset") 42719- } 42720- env := server.params.InitializationOptions.(map[string]interface{})["env"].(map[string]interface{}) 42721- 42722- // Check for an arbitrary Go variable. It should be set. 42723- if _, ok := env["GOPRIVATE"]; !ok { 42724- t.Errorf("Go environment variable GOPRIVATE unset in initialization options") 42725- } 42726- // Check that the variable present in our user config was not overwritten. 42727- if v := env["GONOPROXY"]; v != "example.com" { 42728- t.Errorf("GONOPROXY environment variable was overwritten") 42729- } 42730-} 42731- 42732-func TestListenParsing(t *testing.T) { 42733- tests := []struct { 42734- input, wantNetwork, wantAddr string 42735- }{ 42736- {"127.0.0.1:0", "tcp", "127.0.0.1:0"}, 42737- {"unix;/tmp/sock", "unix", "/tmp/sock"}, 42738- {"auto", "auto", ""}, 42739- {"auto;foo", "auto", "foo"}, 42740- } 42741- 42742- for _, test := range tests { 42743- gotNetwork, gotAddr := ParseAddr(test.input) 42744- if gotNetwork != test.wantNetwork { 42745- t.Errorf("network = %q, want %q", gotNetwork, test.wantNetwork) 42746- } 42747- if gotAddr != test.wantAddr { 42748- t.Errorf("addr = %q, want %q", gotAddr, test.wantAddr) 42749- } 42750- } 42751-} 42752diff -urN a/gopls/internal/lsp/lsprpc/middleware.go b/gopls/internal/lsp/lsprpc/middleware.go 42753--- a/gopls/internal/lsp/lsprpc/middleware.go 2000-01-01 00:00:00.000000000 -0000 42754+++ b/gopls/internal/lsp/lsprpc/middleware.go 1970-01-01 00:00:00.000000000 +0000 42755@@ -1,142 +0,0 @@ 42756-// Copyright 2021 The Go Authors. All rights reserved. 42757-// Use of this source code is governed by a BSD-style 42758-// license that can be found in the LICENSE file. 42759- 42760-package lsprpc 42761- 42762-import ( 42763- "context" 42764- "encoding/json" 42765- "fmt" 42766- "sync" 42767- 42768- "golang.org/x/tools/internal/event" 42769- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 42770-) 42771- 42772-// Metadata holds arbitrary data transferred between jsonrpc2 peers. 42773-type Metadata map[string]interface{} 42774- 42775-// PeerInfo holds information about a peering between jsonrpc2 servers. 42776-type PeerInfo struct { 42777- // RemoteID is the identity of the current server on its peer. 42778- RemoteID int64 42779- 42780- // LocalID is the identity of the peer on the server. 42781- LocalID int64 42782- 42783- // IsClient reports whether the peer is a client. If false, the peer is a 42784- // server. 42785- IsClient bool 42786- 42787- // Metadata holds arbitrary information provided by the peer. 42788- Metadata Metadata 42789-} 42790- 42791-// Handshaker handles both server and client handshaking over jsonrpc2. To 42792-// instrument server-side handshaking, use Handshaker.Middleware. To instrument 42793-// client-side handshaking, call Handshaker.ClientHandshake for any new 42794-// client-side connections. 42795-type Handshaker struct { 42796- // Metadata will be shared with peers via handshaking. 42797- Metadata Metadata 42798- 42799- mu sync.Mutex 42800- prevID int64 42801- peers map[int64]PeerInfo 42802-} 42803- 42804-// Peers returns the peer info this handshaker knows about by way of either the 42805-// server-side handshake middleware, or client-side handshakes. 42806-func (h *Handshaker) Peers() []PeerInfo { 42807- h.mu.Lock() 42808- defer h.mu.Unlock() 42809- 42810- var c []PeerInfo 42811- for _, v := range h.peers { 42812- c = append(c, v) 42813- } 42814- return c 42815-} 42816- 42817-// Middleware is a jsonrpc2 middleware function to augment connection binding 42818-// to handle the handshake method, and record disconnections. 42819-func (h *Handshaker) Middleware(inner jsonrpc2_v2.Binder) jsonrpc2_v2.Binder { 42820- return BinderFunc(func(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions { 42821- opts := inner.Bind(ctx, conn) 42822- 42823- localID := h.nextID() 42824- info := &PeerInfo{ 42825- RemoteID: localID, 42826- Metadata: h.Metadata, 42827- } 42828- 42829- // Wrap the delegated handler to accept the handshake. 42830- delegate := opts.Handler 42831- opts.Handler = jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 42832- if req.Method == handshakeMethod { 42833- var peerInfo PeerInfo 42834- if err := json.Unmarshal(req.Params, &peerInfo); err != nil { 42835- return nil, fmt.Errorf("%w: unmarshaling client info: %v", jsonrpc2_v2.ErrInvalidParams, err) 42836- } 42837- peerInfo.LocalID = localID 42838- peerInfo.IsClient = true 42839- h.recordPeer(peerInfo) 42840- return info, nil 42841- } 42842- return delegate.Handle(ctx, req) 42843- }) 42844- 42845- // Record the dropped client. 42846- go h.cleanupAtDisconnect(conn, localID) 42847- 42848- return opts 42849- }) 42850-} 42851- 42852-// ClientHandshake performs a client-side handshake with the server at the 42853-// other end of conn, recording the server's peer info and watching for conn's 42854-// disconnection. 42855-func (h *Handshaker) ClientHandshake(ctx context.Context, conn *jsonrpc2_v2.Connection) { 42856- localID := h.nextID() 42857- info := &PeerInfo{ 42858- RemoteID: localID, 42859- Metadata: h.Metadata, 42860- } 42861- 42862- call := conn.Call(ctx, handshakeMethod, info) 42863- var serverInfo PeerInfo 42864- if err := call.Await(ctx, &serverInfo); err != nil { 42865- event.Error(ctx, "performing handshake", err) 42866- return 42867- } 42868- serverInfo.LocalID = localID 42869- h.recordPeer(serverInfo) 42870- 42871- go h.cleanupAtDisconnect(conn, localID) 42872-} 42873- 42874-func (h *Handshaker) nextID() int64 { 42875- h.mu.Lock() 42876- defer h.mu.Unlock() 42877- 42878- h.prevID++ 42879- return h.prevID 42880-} 42881- 42882-func (h *Handshaker) cleanupAtDisconnect(conn *jsonrpc2_v2.Connection, peerID int64) { 42883- conn.Wait() 42884- 42885- h.mu.Lock() 42886- defer h.mu.Unlock() 42887- delete(h.peers, peerID) 42888-} 42889- 42890-func (h *Handshaker) recordPeer(info PeerInfo) { 42891- h.mu.Lock() 42892- defer h.mu.Unlock() 42893- if h.peers == nil { 42894- h.peers = make(map[int64]PeerInfo) 42895- } 42896- h.peers[info.LocalID] = info 42897-} 42898diff -urN a/gopls/internal/lsp/lsprpc/middleware_test.go b/gopls/internal/lsp/lsprpc/middleware_test.go 42899--- a/gopls/internal/lsp/lsprpc/middleware_test.go 2000-01-01 00:00:00.000000000 -0000 42900+++ b/gopls/internal/lsp/lsprpc/middleware_test.go 1970-01-01 00:00:00.000000000 +0000 42901@@ -1,93 +0,0 @@ 42902-// Copyright 2021 The Go Authors. All rights reserved. 42903-// Use of this source code is governed by a BSD-style 42904-// license that can be found in the LICENSE file. 42905- 42906-package lsprpc_test 42907- 42908-import ( 42909- "context" 42910- "errors" 42911- "fmt" 42912- "testing" 42913- "time" 42914- 42915- . "golang.org/x/tools/gopls/internal/lsp/lsprpc" 42916- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 42917-) 42918- 42919-var noopBinder = BinderFunc(func(context.Context, *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions { 42920- return jsonrpc2_v2.ConnectionOptions{} 42921-}) 42922- 42923-func TestHandshakeMiddleware(t *testing.T) { 42924- sh := &Handshaker{ 42925- Metadata: Metadata{ 42926- "answer": 42, 42927- }, 42928- } 42929- ctx := context.Background() 42930- env := new(TestEnv) 42931- defer env.Shutdown(t) 42932- l, _ := env.serve(ctx, t, sh.Middleware(noopBinder)) 42933- conn := env.dial(ctx, t, l.Dialer(), noopBinder, false) 42934- ch := &Handshaker{ 42935- Metadata: Metadata{ 42936- "question": 6 * 9, 42937- }, 42938- } 42939- 42940- check := func(connected bool) error { 42941- clients := sh.Peers() 42942- servers := ch.Peers() 42943- want := 0 42944- if connected { 42945- want = 1 42946- } 42947- if got := len(clients); got != want { 42948- return fmt.Errorf("got %d clients on the server, want %d", got, want) 42949- } 42950- if got := len(servers); got != want { 42951- return fmt.Errorf("got %d servers on the client, want %d", got, want) 42952- } 42953- if !connected { 42954- return nil 42955- } 42956- client := clients[0] 42957- server := servers[0] 42958- if _, ok := client.Metadata["question"]; !ok { 42959- return errors.New("no client metadata") 42960- } 42961- if _, ok := server.Metadata["answer"]; !ok { 42962- return errors.New("no server metadata") 42963- } 42964- if client.LocalID != server.RemoteID { 42965- return fmt.Errorf("client.LocalID == %d, server.PeerID == %d", client.LocalID, server.RemoteID) 42966- } 42967- if client.RemoteID != server.LocalID { 42968- return fmt.Errorf("client.PeerID == %d, server.LocalID == %d", client.RemoteID, server.LocalID) 42969- } 42970- return nil 42971- } 42972- 42973- if err := check(false); err != nil { 42974- t.Fatalf("before handshake: %v", err) 42975- } 42976- ch.ClientHandshake(ctx, conn) 42977- if err := check(true); err != nil { 42978- t.Fatalf("after handshake: %v", err) 42979- } 42980- conn.Close() 42981- // Wait for up to ~2s for connections to get cleaned up. 42982- delay := 25 * time.Millisecond 42983- for retries := 3; retries >= 0; retries-- { 42984- time.Sleep(delay) 42985- err := check(false) 42986- if err == nil { 42987- return 42988- } 42989- if retries == 0 { 42990- t.Fatalf("after closing connection: %v", err) 42991- } 42992- delay *= 4 42993- } 42994-} 42995diff -urN a/gopls/internal/lsp/lsp_test.go b/gopls/internal/lsp/lsp_test.go 42996--- a/gopls/internal/lsp/lsp_test.go 2000-01-01 00:00:00.000000000 -0000 42997+++ b/gopls/internal/lsp/lsp_test.go 1970-01-01 00:00:00.000000000 +0000 42998@@ -1,1360 +0,0 @@ 42999-// Copyright 2018 The Go Authors. All rights reserved. 43000-// Use of this source code is governed by a BSD-style 43001-// license that can be found in the LICENSE file. 43002- 43003-package lsp 43004- 43005-import ( 43006- "bytes" 43007- "context" 43008- "fmt" 43009- "os" 43010- "os/exec" 43011- "path/filepath" 43012- "sort" 43013- "strings" 43014- "testing" 43015- 43016- "github.com/google/go-cmp/cmp" 43017- "github.com/google/go-cmp/cmp/cmpopts" 43018- "golang.org/x/tools/gopls/internal/lsp/cache" 43019- "golang.org/x/tools/gopls/internal/lsp/command" 43020- "golang.org/x/tools/gopls/internal/lsp/protocol" 43021- "golang.org/x/tools/gopls/internal/lsp/source" 43022- "golang.org/x/tools/gopls/internal/lsp/tests" 43023- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 43024- "golang.org/x/tools/gopls/internal/span" 43025- "golang.org/x/tools/internal/bug" 43026- "golang.org/x/tools/internal/diff" 43027- "golang.org/x/tools/internal/event" 43028- "golang.org/x/tools/internal/testenv" 43029-) 43030- 43031-func TestMain(m *testing.M) { 43032- bug.PanicOnBugs = true 43033- testenv.ExitIfSmallMachine() 43034- 43035- // Set the global exporter to nil so that we don't log to stderr. This avoids 43036- // a lot of misleading noise in test output. 43037- // 43038- // TODO(rfindley): investigate whether we can/should capture logs scoped to 43039- // individual tests by passing in a context with a local exporter. 43040- event.SetExporter(nil) 43041- 43042- os.Exit(m.Run()) 43043-} 43044- 43045-// TestLSP runs the marker tests in files beneath testdata/ using 43046-// implementations of each of the marker operations (e.g. @codelens) that 43047-// make LSP RPCs (e.g. textDocument/codeLens) to a gopls server. 43048-func TestLSP(t *testing.T) { 43049- tests.RunTests(t, "testdata", true, testLSP) 43050-} 43051- 43052-func testLSP(t *testing.T, datum *tests.Data) { 43053- ctx := tests.Context(t) 43054- 43055- session := cache.NewSession(ctx, cache.New(nil), nil) 43056- options := source.DefaultOptions().Clone() 43057- tests.DefaultOptions(options) 43058- session.SetOptions(options) 43059- options.SetEnvSlice(datum.Config.Env) 43060- view, snapshot, release, err := session.NewView(ctx, datum.Config.Dir, span.URIFromPath(datum.Config.Dir), options) 43061- if err != nil { 43062- t.Fatal(err) 43063- } 43064- 43065- defer session.RemoveView(view) 43066- 43067- // Enable type error analyses for tests. 43068- // TODO(golang/go#38212): Delete this once they are enabled by default. 43069- tests.EnableAllAnalyzers(options) 43070- session.SetViewOptions(ctx, view, options) 43071- 43072- // Enable all inlay hints for tests. 43073- tests.EnableAllInlayHints(options) 43074- 43075- // Only run the -modfile specific tests in module mode with Go 1.14 or above. 43076- datum.ModfileFlagAvailable = len(snapshot.ModFiles()) > 0 && testenv.Go1Point() >= 14 43077- release() 43078- 43079- // Open all files for performance reasons. This is done because gopls only 43080- // keeps active packages in memory for open files. 43081- // 43082- // In practice clients will only send document-oriented requests for open 43083- // files. 43084- var modifications []source.FileModification 43085- for _, module := range datum.Exported.Modules { 43086- for name := range module.Files { 43087- filename := datum.Exported.File(module.Name, name) 43088- if filepath.Ext(filename) != ".go" { 43089- continue 43090- } 43091- content, err := datum.Exported.FileContents(filename) 43092- if err != nil { 43093- t.Fatal(err) 43094- } 43095- modifications = append(modifications, source.FileModification{ 43096- URI: span.URIFromPath(filename), 43097- Action: source.Open, 43098- Version: -1, 43099- Text: content, 43100- LanguageID: "go", 43101- }) 43102- } 43103- } 43104- for filename, content := range datum.Config.Overlay { 43105- if filepath.Ext(filename) != ".go" { 43106- continue 43107- } 43108- modifications = append(modifications, source.FileModification{ 43109- URI: span.URIFromPath(filename), 43110- Action: source.Open, 43111- Version: -1, 43112- Text: content, 43113- LanguageID: "go", 43114- }) 43115- } 43116- if err := session.ModifyFiles(ctx, modifications); err != nil { 43117- t.Fatal(err) 43118- } 43119- r := &runner{ 43120- data: datum, 43121- ctx: ctx, 43122- normalizers: tests.CollectNormalizers(datum.Exported), 43123- editRecv: make(chan map[span.URI][]byte, 1), 43124- } 43125- 43126- r.server = NewServer(session, testClient{runner: r}) 43127- tests.Run(t, r, datum) 43128-} 43129- 43130-// runner implements tests.Tests by making LSP RPCs to a gopls server. 43131-type runner struct { 43132- server *Server 43133- data *tests.Data 43134- diagnostics map[span.URI][]*source.Diagnostic 43135- ctx context.Context 43136- normalizers []tests.Normalizer 43137- editRecv chan map[span.URI][]byte 43138-} 43139- 43140-// testClient stubs any client functions that may be called by LSP functions. 43141-type testClient struct { 43142- protocol.Client 43143- runner *runner 43144-} 43145- 43146-func (c testClient) Close() error { 43147- return nil 43148-} 43149- 43150-// Trivially implement PublishDiagnostics so that we can call 43151-// server.publishReports below to de-dup sent diagnostics. 43152-func (c testClient) PublishDiagnostics(context.Context, *protocol.PublishDiagnosticsParams) error { 43153- return nil 43154-} 43155- 43156-func (c testClient) ShowMessage(context.Context, *protocol.ShowMessageParams) error { 43157- return nil 43158-} 43159- 43160-func (c testClient) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) { 43161- res, err := applyTextDocumentEdits(c.runner, params.Edit.DocumentChanges) 43162- if err != nil { 43163- return nil, err 43164- } 43165- c.runner.editRecv <- res 43166- return &protocol.ApplyWorkspaceEditResult{Applied: true}, nil 43167-} 43168- 43169-func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) { 43170- mapper, err := r.data.Mapper(spn.URI()) 43171- if err != nil { 43172- t.Fatal(err) 43173- } 43174- loc, err := mapper.SpanLocation(spn) 43175- if err != nil { 43176- t.Fatalf("failed for %v: %v", spn, err) 43177- } 43178- 43179- params := &protocol.CallHierarchyPrepareParams{ 43180- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 43181- } 43182- 43183- items, err := r.server.PrepareCallHierarchy(r.ctx, params) 43184- if err != nil { 43185- t.Fatal(err) 43186- } 43187- if len(items) == 0 { 43188- t.Fatalf("expected call hierarchy item to be returned for identifier at %v\n", loc.Range) 43189- } 43190- 43191- callLocation := protocol.Location{ 43192- URI: items[0].URI, 43193- Range: items[0].Range, 43194- } 43195- if callLocation != loc { 43196- t.Fatalf("expected server.PrepareCallHierarchy to return identifier at %v but got %v\n", loc, callLocation) 43197- } 43198- 43199- incomingCalls, err := r.server.IncomingCalls(r.ctx, &protocol.CallHierarchyIncomingCallsParams{Item: items[0]}) 43200- if err != nil { 43201- t.Error(err) 43202- } 43203- var incomingCallItems []protocol.CallHierarchyItem 43204- for _, item := range incomingCalls { 43205- incomingCallItems = append(incomingCallItems, item.From) 43206- } 43207- msg := tests.DiffCallHierarchyItems(incomingCallItems, expectedCalls.IncomingCalls) 43208- if msg != "" { 43209- t.Error(fmt.Sprintf("incoming calls: %s", msg)) 43210- } 43211- 43212- outgoingCalls, err := r.server.OutgoingCalls(r.ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: items[0]}) 43213- if err != nil { 43214- t.Error(err) 43215- } 43216- var outgoingCallItems []protocol.CallHierarchyItem 43217- for _, item := range outgoingCalls { 43218- outgoingCallItems = append(outgoingCallItems, item.To) 43219- } 43220- msg = tests.DiffCallHierarchyItems(outgoingCallItems, expectedCalls.OutgoingCalls) 43221- if msg != "" { 43222- t.Error(fmt.Sprintf("outgoing calls: %s", msg)) 43223- } 43224-} 43225- 43226-func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) { 43227- if !strings.HasSuffix(uri.Filename(), "go.mod") { 43228- return 43229- } 43230- got, err := r.server.codeLens(r.ctx, &protocol.CodeLensParams{ 43231- TextDocument: protocol.TextDocumentIdentifier{ 43232- URI: protocol.DocumentURI(uri), 43233- }, 43234- }) 43235- if err != nil { 43236- t.Fatal(err) 43237- } 43238- if diff := tests.DiffCodeLens(uri, want, got); diff != "" { 43239- t.Errorf("%s: %s", uri, diff) 43240- } 43241-} 43242- 43243-func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnostic) { 43244- // Get the diagnostics for this view if we have not done it before. 43245- v := r.server.session.View(r.data.Config.Dir) 43246- r.collectDiagnostics(v) 43247- tests.CompareDiagnostics(t, uri, want, r.diagnostics[uri]) 43248-} 43249- 43250-func (r *runner) FoldingRanges(t *testing.T, spn span.Span) { 43251- uri := spn.URI() 43252- view, err := r.server.session.ViewOf(uri) 43253- if err != nil { 43254- t.Fatal(err) 43255- } 43256- original := view.Options() 43257- modified := original 43258- defer r.server.session.SetViewOptions(r.ctx, view, original) 43259- 43260- for _, test := range []struct { 43261- lineFoldingOnly bool 43262- prefix string 43263- }{ 43264- {false, "foldingRange"}, 43265- {true, "foldingRange-lineFolding"}, 43266- } { 43267- modified.LineFoldingOnly = test.lineFoldingOnly 43268- view, err = r.server.session.SetViewOptions(r.ctx, view, modified) 43269- if err != nil { 43270- t.Error(err) 43271- continue 43272- } 43273- ranges, err := r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{ 43274- TextDocument: protocol.TextDocumentIdentifier{ 43275- URI: protocol.URIFromSpanURI(uri), 43276- }, 43277- }) 43278- if err != nil { 43279- t.Error(err) 43280- continue 43281- } 43282- r.foldingRanges(t, test.prefix, uri, ranges) 43283- } 43284-} 43285- 43286-func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, ranges []protocol.FoldingRange) { 43287- m, err := r.data.Mapper(uri) 43288- if err != nil { 43289- t.Fatal(err) 43290- } 43291- // Fold all ranges. 43292- nonOverlapping := nonOverlappingRanges(ranges) 43293- for i, rngs := range nonOverlapping { 43294- got, err := foldRanges(m, string(m.Content), rngs) 43295- if err != nil { 43296- t.Error(err) 43297- continue 43298- } 43299- tag := fmt.Sprintf("%s-%d", prefix, i) 43300- want := string(r.data.Golden(t, tag, uri.Filename(), func() ([]byte, error) { 43301- return []byte(got), nil 43302- })) 43303- 43304- if want != got { 43305- t.Errorf("%s: foldingRanges failed for %s, expected:\n%v\ngot:\n%v", tag, uri.Filename(), want, got) 43306- } 43307- } 43308- 43309- // Filter by kind. 43310- kinds := []protocol.FoldingRangeKind{protocol.Imports, protocol.Comment} 43311- for _, kind := range kinds { 43312- var kindOnly []protocol.FoldingRange 43313- for _, fRng := range ranges { 43314- if fRng.Kind == string(kind) { 43315- kindOnly = append(kindOnly, fRng) 43316- } 43317- } 43318- 43319- nonOverlapping := nonOverlappingRanges(kindOnly) 43320- for i, rngs := range nonOverlapping { 43321- got, err := foldRanges(m, string(m.Content), rngs) 43322- if err != nil { 43323- t.Error(err) 43324- continue 43325- } 43326- tag := fmt.Sprintf("%s-%s-%d", prefix, kind, i) 43327- want := string(r.data.Golden(t, tag, uri.Filename(), func() ([]byte, error) { 43328- return []byte(got), nil 43329- })) 43330- 43331- if want != got { 43332- t.Errorf("%s: foldingRanges failed for %s, expected:\n%v\ngot:\n%v", tag, uri.Filename(), want, got) 43333- } 43334- } 43335- 43336- } 43337-} 43338- 43339-func nonOverlappingRanges(ranges []protocol.FoldingRange) (res [][]protocol.FoldingRange) { 43340- for _, fRng := range ranges { 43341- setNum := len(res) 43342- for i := 0; i < len(res); i++ { 43343- canInsert := true 43344- for _, rng := range res[i] { 43345- if conflict(rng, fRng) { 43346- canInsert = false 43347- break 43348- } 43349- } 43350- if canInsert { 43351- setNum = i 43352- break 43353- } 43354- } 43355- if setNum == len(res) { 43356- res = append(res, []protocol.FoldingRange{}) 43357- } 43358- res[setNum] = append(res[setNum], fRng) 43359- } 43360- return res 43361-} 43362- 43363-func conflict(a, b protocol.FoldingRange) bool { 43364- // a start position is <= b start positions 43365- return (a.StartLine < b.StartLine || (a.StartLine == b.StartLine && a.StartCharacter <= b.StartCharacter)) && 43366- (a.EndLine > b.StartLine || (a.EndLine == b.StartLine && a.EndCharacter > b.StartCharacter)) 43367-} 43368- 43369-func foldRanges(m *protocol.Mapper, contents string, ranges []protocol.FoldingRange) (string, error) { 43370- foldedText := "<>" 43371- res := contents 43372- // Apply the edits from the end of the file forward 43373- // to preserve the offsets 43374- // TODO(adonovan): factor to use diff.ApplyEdits, which validates the input. 43375- for i := len(ranges) - 1; i >= 0; i-- { 43376- r := ranges[i] 43377- start, err := m.PositionPoint(protocol.Position{Line: r.StartLine, Character: r.StartCharacter}) 43378- if err != nil { 43379- return "", err 43380- } 43381- end, err := m.PositionPoint(protocol.Position{Line: r.EndLine, Character: r.EndCharacter}) 43382- if err != nil { 43383- return "", err 43384- } 43385- res = res[:start.Offset()] + foldedText + res[end.Offset():] 43386- } 43387- return res, nil 43388-} 43389- 43390-func (r *runner) Format(t *testing.T, spn span.Span) { 43391- uri := spn.URI() 43392- filename := uri.Filename() 43393- gofmted := r.data.Golden(t, "gofmt", filename, func() ([]byte, error) { 43394- cmd := exec.Command("gofmt", filename) 43395- out, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files 43396- return out, nil 43397- }) 43398- 43399- edits, err := r.server.Formatting(r.ctx, &protocol.DocumentFormattingParams{ 43400- TextDocument: protocol.TextDocumentIdentifier{ 43401- URI: protocol.URIFromSpanURI(uri), 43402- }, 43403- }) 43404- if err != nil { 43405- if len(gofmted) > 0 { 43406- t.Error(err) 43407- } 43408- return 43409- } 43410- m, err := r.data.Mapper(uri) 43411- if err != nil { 43412- t.Fatal(err) 43413- } 43414- got, _, err := source.ApplyProtocolEdits(m, edits) 43415- if err != nil { 43416- t.Error(err) 43417- } 43418- if diff := compare.Bytes(gofmted, got); diff != "" { 43419- t.Errorf("format failed for %s (-want +got):\n%s", filename, diff) 43420- } 43421-} 43422- 43423-func (r *runner) SemanticTokens(t *testing.T, spn span.Span) { 43424- uri := spn.URI() 43425- filename := uri.Filename() 43426- // this is called solely for coverage in semantic.go 43427- _, err := r.server.semanticTokensFull(r.ctx, &protocol.SemanticTokensParams{ 43428- TextDocument: protocol.TextDocumentIdentifier{ 43429- URI: protocol.URIFromSpanURI(uri), 43430- }, 43431- }) 43432- if err != nil { 43433- t.Errorf("%v for %s", err, filename) 43434- } 43435- _, err = r.server.semanticTokensRange(r.ctx, &protocol.SemanticTokensRangeParams{ 43436- TextDocument: protocol.TextDocumentIdentifier{ 43437- URI: protocol.URIFromSpanURI(uri), 43438- }, 43439- // any legal range. Just to exercise the call. 43440- Range: protocol.Range{ 43441- Start: protocol.Position{ 43442- Line: 0, 43443- Character: 0, 43444- }, 43445- End: protocol.Position{ 43446- Line: 2, 43447- Character: 0, 43448- }, 43449- }, 43450- }) 43451- if err != nil { 43452- t.Errorf("%v for Range %s", err, filename) 43453- } 43454-} 43455- 43456-func (r *runner) Import(t *testing.T, spn span.Span) { 43457- // Invokes textDocument/codeAction and applies all the "goimports" edits. 43458- 43459- uri := spn.URI() 43460- filename := uri.Filename() 43461- actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{ 43462- TextDocument: protocol.TextDocumentIdentifier{ 43463- URI: protocol.URIFromSpanURI(uri), 43464- }, 43465- }) 43466- if err != nil { 43467- t.Fatal(err) 43468- } 43469- m, err := r.data.Mapper(uri) 43470- if err != nil { 43471- t.Fatal(err) 43472- } 43473- got := m.Content 43474- if len(actions) > 0 { 43475- res, err := applyTextDocumentEdits(r, actions[0].Edit.DocumentChanges) 43476- if err != nil { 43477- t.Fatal(err) 43478- } 43479- got = res[uri] 43480- } 43481- want := r.data.Golden(t, "goimports", filename, func() ([]byte, error) { 43482- return got, nil 43483- }) 43484- if diff := compare.Bytes(want, got); diff != "" { 43485- t.Errorf("import failed for %s:\n%s", filename, diff) 43486- } 43487-} 43488- 43489-func (r *runner) SuggestedFix(t *testing.T, spn span.Span, actionKinds []tests.SuggestedFix, expectedActions int) { 43490- uri := spn.URI() 43491- view, err := r.server.session.ViewOf(uri) 43492- if err != nil { 43493- t.Fatal(err) 43494- } 43495- 43496- m, err := r.data.Mapper(uri) 43497- if err != nil { 43498- t.Fatal(err) 43499- } 43500- rng, err := m.SpanRange(spn) 43501- if err != nil { 43502- t.Fatal(err) 43503- } 43504- // Get the diagnostics for this view if we have not done it before. 43505- r.collectDiagnostics(view) 43506- var diagnostics []protocol.Diagnostic 43507- for _, d := range r.diagnostics[uri] { 43508- // Compare the start positions rather than the entire range because 43509- // some diagnostics have a range with the same start and end position (8:1-8:1). 43510- // The current marker functionality prevents us from having a range of 0 length. 43511- if protocol.ComparePosition(d.Range.Start, rng.Start) == 0 { 43512- diagnostics = append(diagnostics, toProtocolDiagnostics([]*source.Diagnostic{d})...) 43513- break 43514- } 43515- } 43516- var codeActionKinds []protocol.CodeActionKind 43517- for _, k := range actionKinds { 43518- codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k.ActionKind)) 43519- } 43520- allActions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{ 43521- TextDocument: protocol.TextDocumentIdentifier{ 43522- URI: protocol.URIFromSpanURI(uri), 43523- }, 43524- Range: rng, 43525- Context: protocol.CodeActionContext{ 43526- Only: codeActionKinds, 43527- Diagnostics: diagnostics, 43528- }, 43529- }) 43530- if err != nil { 43531- t.Fatalf("CodeAction %s failed: %v", spn, err) 43532- } 43533- var actions []protocol.CodeAction 43534- for _, action := range allActions { 43535- for _, fix := range actionKinds { 43536- if strings.Contains(action.Title, fix.Title) { 43537- actions = append(actions, action) 43538- break 43539- } 43540- } 43541- 43542- } 43543- if len(actions) != expectedActions { 43544- var summaries []string 43545- for _, a := range actions { 43546- summaries = append(summaries, fmt.Sprintf("%q (%s)", a.Title, a.Kind)) 43547- } 43548- t.Fatalf("CodeAction(...): got %d code actions (%v), want %d", len(actions), summaries, expectedActions) 43549- } 43550- action := actions[0] 43551- var match bool 43552- for _, k := range codeActionKinds { 43553- if action.Kind == k { 43554- match = true 43555- break 43556- } 43557- } 43558- if !match { 43559- t.Fatalf("unexpected kind for code action %s, got %v, want one of %v", action.Title, action.Kind, codeActionKinds) 43560- } 43561- var res map[span.URI][]byte 43562- if cmd := action.Command; cmd != nil { 43563- _, err := r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{ 43564- Command: action.Command.Command, 43565- Arguments: action.Command.Arguments, 43566- }) 43567- if err != nil { 43568- t.Fatalf("error converting command %q to edits: %v", action.Command.Command, err) 43569- } 43570- res = <-r.editRecv 43571- } else { 43572- res, err = applyTextDocumentEdits(r, action.Edit.DocumentChanges) 43573- if err != nil { 43574- t.Fatal(err) 43575- } 43576- } 43577- for u, got := range res { 43578- want := r.data.Golden(t, "suggestedfix_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) { 43579- return got, nil 43580- }) 43581- if diff := compare.Bytes(want, got); diff != "" { 43582- t.Errorf("suggested fixes failed for %s:\n%s", u.Filename(), diff) 43583- } 43584- } 43585-} 43586- 43587-func (r *runner) FunctionExtraction(t *testing.T, start span.Span, end span.Span) { 43588- uri := start.URI() 43589- m, err := r.data.Mapper(uri) 43590- if err != nil { 43591- t.Fatal(err) 43592- } 43593- spn := span.New(start.URI(), start.Start(), end.End()) 43594- rng, err := m.SpanRange(spn) 43595- if err != nil { 43596- t.Fatal(err) 43597- } 43598- actionsRaw, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{ 43599- TextDocument: protocol.TextDocumentIdentifier{ 43600- URI: protocol.URIFromSpanURI(uri), 43601- }, 43602- Range: rng, 43603- Context: protocol.CodeActionContext{ 43604- Only: []protocol.CodeActionKind{"refactor.extract"}, 43605- }, 43606- }) 43607- if err != nil { 43608- t.Fatal(err) 43609- } 43610- var actions []protocol.CodeAction 43611- for _, action := range actionsRaw { 43612- if action.Command.Title == "Extract function" { 43613- actions = append(actions, action) 43614- } 43615- } 43616- // Hack: We assume that we only get one code action per range. 43617- // TODO(rstambler): Support multiple code actions per test. 43618- if len(actions) == 0 || len(actions) > 1 { 43619- t.Fatalf("unexpected number of code actions, want 1, got %v", len(actions)) 43620- } 43621- _, err = r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{ 43622- Command: actions[0].Command.Command, 43623- Arguments: actions[0].Command.Arguments, 43624- }) 43625- if err != nil { 43626- t.Fatal(err) 43627- } 43628- res := <-r.editRecv 43629- for u, got := range res { 43630- want := r.data.Golden(t, "functionextraction_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) { 43631- return got, nil 43632- }) 43633- if diff := compare.Bytes(want, got); diff != "" { 43634- t.Errorf("function extraction failed for %s:\n%s", u.Filename(), diff) 43635- } 43636- } 43637-} 43638- 43639-func (r *runner) MethodExtraction(t *testing.T, start span.Span, end span.Span) { 43640- uri := start.URI() 43641- m, err := r.data.Mapper(uri) 43642- if err != nil { 43643- t.Fatal(err) 43644- } 43645- spn := span.New(start.URI(), start.Start(), end.End()) 43646- rng, err := m.SpanRange(spn) 43647- if err != nil { 43648- t.Fatal(err) 43649- } 43650- actionsRaw, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{ 43651- TextDocument: protocol.TextDocumentIdentifier{ 43652- URI: protocol.URIFromSpanURI(uri), 43653- }, 43654- Range: rng, 43655- Context: protocol.CodeActionContext{ 43656- Only: []protocol.CodeActionKind{"refactor.extract"}, 43657- }, 43658- }) 43659- if err != nil { 43660- t.Fatal(err) 43661- } 43662- var actions []protocol.CodeAction 43663- for _, action := range actionsRaw { 43664- if action.Command.Title == "Extract method" { 43665- actions = append(actions, action) 43666- } 43667- } 43668- // Hack: We assume that we only get one matching code action per range. 43669- // TODO(rstambler): Support multiple code actions per test. 43670- if len(actions) == 0 || len(actions) > 1 { 43671- t.Fatalf("unexpected number of code actions, want 1, got %v", len(actions)) 43672- } 43673- _, err = r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{ 43674- Command: actions[0].Command.Command, 43675- Arguments: actions[0].Command.Arguments, 43676- }) 43677- if err != nil { 43678- t.Fatal(err) 43679- } 43680- res := <-r.editRecv 43681- for u, got := range res { 43682- want := r.data.Golden(t, "methodextraction_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) { 43683- return got, nil 43684- }) 43685- if diff := compare.Bytes(want, got); diff != "" { 43686- t.Errorf("method extraction failed for %s:\n%s", u.Filename(), diff) 43687- } 43688- } 43689-} 43690- 43691-// TODO(rfindley): This handler needs more work. The output is still a bit hard 43692-// to read (range diffs do not format nicely), and it is too entangled with hover. 43693-func (r *runner) Definition(t *testing.T, _ span.Span, d tests.Definition) { 43694- sm, err := r.data.Mapper(d.Src.URI()) 43695- if err != nil { 43696- t.Fatal(err) 43697- } 43698- loc, err := sm.SpanLocation(d.Src) 43699- if err != nil { 43700- t.Fatalf("failed for %v: %v", d.Src, err) 43701- } 43702- tdpp := protocol.LocationTextDocumentPositionParams(loc) 43703- var got []protocol.Location 43704- var hover *protocol.Hover 43705- if d.IsType { 43706- params := &protocol.TypeDefinitionParams{ 43707- TextDocumentPositionParams: tdpp, 43708- } 43709- got, err = r.server.TypeDefinition(r.ctx, params) 43710- } else { 43711- params := &protocol.DefinitionParams{ 43712- TextDocumentPositionParams: tdpp, 43713- } 43714- got, err = r.server.Definition(r.ctx, params) 43715- if err != nil { 43716- t.Fatalf("failed for %v: %+v", d.Src, err) 43717- } 43718- v := &protocol.HoverParams{ 43719- TextDocumentPositionParams: tdpp, 43720- } 43721- hover, err = r.server.Hover(r.ctx, v) 43722- } 43723- if err != nil { 43724- t.Fatalf("failed for %v: %v", d.Src, err) 43725- } 43726- dm, err := r.data.Mapper(d.Def.URI()) 43727- if err != nil { 43728- t.Fatal(err) 43729- } 43730- def, err := dm.SpanLocation(d.Def) 43731- if err != nil { 43732- t.Fatal(err) 43733- } 43734- if !d.OnlyHover { 43735- want := []protocol.Location{def} 43736- if diff := cmp.Diff(want, got); diff != "" { 43737- t.Fatalf("Definition(%s) mismatch (-want +got):\n%s", d.Src, diff) 43738- } 43739- } 43740- didSomething := false 43741- if hover != nil { 43742- didSomething = true 43743- tag := fmt.Sprintf("%s-hoverdef", d.Name) 43744- want := string(r.data.Golden(t, tag, d.Src.URI().Filename(), func() ([]byte, error) { 43745- return []byte(hover.Contents.Value), nil 43746- })) 43747- got := hover.Contents.Value 43748- if diff := tests.DiffMarkdown(want, got); diff != "" { 43749- t.Errorf("%s: markdown mismatch:\n%s", d.Src, diff) 43750- } 43751- } 43752- if !d.OnlyHover { 43753- didSomething = true 43754- locURI := got[0].URI.SpanURI() 43755- lm, err := r.data.Mapper(locURI) 43756- if err != nil { 43757- t.Fatal(err) 43758- } 43759- if def, err := lm.LocationSpan(got[0]); err != nil { 43760- t.Fatalf("failed for %v: %v", got[0], err) 43761- } else if def != d.Def { 43762- t.Errorf("for %v got %v want %v", d.Src, def, d.Def) 43763- } 43764- } 43765- if !didSomething { 43766- t.Errorf("no tests ran for %s", d.Src.URI()) 43767- } 43768-} 43769- 43770-func (r *runner) Implementation(t *testing.T, spn span.Span, wantSpans []span.Span) { 43771- sm, err := r.data.Mapper(spn.URI()) 43772- if err != nil { 43773- t.Fatal(err) 43774- } 43775- loc, err := sm.SpanLocation(spn) 43776- if err != nil { 43777- t.Fatal(err) 43778- } 43779- gotImpls, err := r.server.Implementation(r.ctx, &protocol.ImplementationParams{ 43780- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 43781- }) 43782- if err != nil { 43783- t.Fatalf("Server.Implementation(%s): %v", spn, err) 43784- } 43785- gotLocs, err := tests.LocationsToSpans(r.data, gotImpls) 43786- if err != nil { 43787- t.Fatal(err) 43788- } 43789- sanitize := func(s string) string { 43790- return strings.ReplaceAll(s, r.data.Config.Dir, "gopls/internal/lsp/testdata") 43791- } 43792- want := sanitize(tests.SortAndFormatSpans(wantSpans)) 43793- got := sanitize(tests.SortAndFormatSpans(gotLocs)) 43794- if got != want { 43795- t.Errorf("implementations(%s):\n%s", sanitize(fmt.Sprint(spn)), diff.Unified("want", "got", want, got)) 43796- } 43797-} 43798- 43799-func (r *runner) Highlight(t *testing.T, src span.Span, spans []span.Span) { 43800- m, err := r.data.Mapper(src.URI()) 43801- if err != nil { 43802- t.Fatal(err) 43803- } 43804- loc, err := m.SpanLocation(src) 43805- if err != nil { 43806- t.Fatal(err) 43807- } 43808- params := &protocol.DocumentHighlightParams{ 43809- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 43810- } 43811- highlights, err := r.server.DocumentHighlight(r.ctx, params) 43812- if err != nil { 43813- t.Fatalf("DocumentHighlight(%v) failed: %v", params, err) 43814- } 43815- var got []protocol.Range 43816- for _, h := range highlights { 43817- got = append(got, h.Range) 43818- } 43819- 43820- var want []protocol.Range 43821- for _, s := range spans { 43822- rng, err := m.SpanRange(s) 43823- if err != nil { 43824- t.Fatalf("Mapper.SpanRange(%v) failed: %v", s, err) 43825- } 43826- want = append(want, rng) 43827- } 43828- 43829- sortRanges := func(s []protocol.Range) { 43830- sort.Slice(s, func(i, j int) bool { 43831- return protocol.CompareRange(s[i], s[j]) < 0 43832- }) 43833- } 43834- 43835- sortRanges(got) 43836- sortRanges(want) 43837- 43838- if diff := cmp.Diff(want, got); diff != "" { 43839- t.Errorf("DocumentHighlight(%v) mismatch (-want +got):\n%s", src, diff) 43840- } 43841-} 43842- 43843-func (r *runner) References(t *testing.T, src span.Span, itemList []span.Span) { 43844- // This test is substantially the same as (*runner).References in source/source_test.go. 43845- // TODO(adonovan): Factor (and remove fluff). Where should the common code live? 43846- 43847- sm, err := r.data.Mapper(src.URI()) 43848- if err != nil { 43849- t.Fatal(err) 43850- } 43851- loc, err := sm.SpanLocation(src) 43852- if err != nil { 43853- t.Fatalf("failed for %v: %v", src, err) 43854- } 43855- for _, includeDeclaration := range []bool{true, false} { 43856- t.Run(fmt.Sprintf("refs-declaration-%v", includeDeclaration), func(t *testing.T) { 43857- want := make(map[protocol.Location]bool) 43858- for i, pos := range itemList { 43859- // We don't want the first result if we aren't including the declaration. 43860- // TODO(adonovan): don't assume a single declaration: 43861- // there may be >1 if corresponding methods are considered. 43862- if i == 0 && !includeDeclaration { 43863- continue 43864- } 43865- m, err := r.data.Mapper(pos.URI()) 43866- if err != nil { 43867- t.Fatal(err) 43868- } 43869- loc, err := m.SpanLocation(pos) 43870- if err != nil { 43871- t.Fatalf("failed for %v: %v", src, err) 43872- } 43873- want[loc] = true 43874- } 43875- params := &protocol.ReferenceParams{ 43876- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 43877- Context: protocol.ReferenceContext{ 43878- IncludeDeclaration: includeDeclaration, 43879- }, 43880- } 43881- got, err := r.server.References(r.ctx, params) 43882- if err != nil { 43883- t.Fatalf("failed for %v: %v", src, err) 43884- } 43885- 43886- sanitize := func(s string) string { 43887- // In practice, CONFIGDIR means "gopls/internal/lsp/testdata". 43888- return strings.ReplaceAll(s, r.data.Config.Dir, "CONFIGDIR") 43889- } 43890- formatLocation := func(loc protocol.Location) string { 43891- return fmt.Sprintf("%s:%d.%d-%d.%d", 43892- sanitize(string(loc.URI)), 43893- loc.Range.Start.Line+1, 43894- loc.Range.Start.Character+1, 43895- loc.Range.End.Line+1, 43896- loc.Range.End.Character+1) 43897- } 43898- toSlice := func(set map[protocol.Location]bool) []protocol.Location { 43899- // TODO(adonovan): use generic maps.Keys(), someday. 43900- list := make([]protocol.Location, 0, len(set)) 43901- for key := range set { 43902- list = append(list, key) 43903- } 43904- return list 43905- } 43906- toString := func(locs []protocol.Location) string { 43907- // TODO(adonovan): use generic JoinValues(locs, formatLocation). 43908- strs := make([]string, len(locs)) 43909- for i, loc := range locs { 43910- strs[i] = formatLocation(loc) 43911- } 43912- sort.Strings(strs) 43913- return strings.Join(strs, "\n") 43914- } 43915- gotStr := toString(got) 43916- wantStr := toString(toSlice(want)) 43917- if gotStr != wantStr { 43918- t.Errorf("incorrect references (got %d, want %d) at %s:\n%s", 43919- len(got), len(want), 43920- formatLocation(loc), 43921- diff.Unified("want", "got", wantStr, gotStr)) 43922- } 43923- }) 43924- } 43925-} 43926- 43927-func (r *runner) InlayHints(t *testing.T, spn span.Span) { 43928- uri := spn.URI() 43929- filename := uri.Filename() 43930- 43931- hints, err := r.server.InlayHint(r.ctx, &protocol.InlayHintParams{ 43932- TextDocument: protocol.TextDocumentIdentifier{ 43933- URI: protocol.URIFromSpanURI(uri), 43934- }, 43935- // TODO: add Range 43936- }) 43937- if err != nil { 43938- t.Fatal(err) 43939- } 43940- 43941- // Map inlay hints to text edits. 43942- edits := make([]protocol.TextEdit, len(hints)) 43943- for i, hint := range hints { 43944- var paddingLeft, paddingRight string 43945- if hint.PaddingLeft { 43946- paddingLeft = " " 43947- } 43948- if hint.PaddingRight { 43949- paddingRight = " " 43950- } 43951- edits[i] = protocol.TextEdit{ 43952- Range: protocol.Range{Start: hint.Position, End: hint.Position}, 43953- NewText: fmt.Sprintf("<%s%s%s>", paddingLeft, hint.Label[0].Value, paddingRight), 43954- } 43955- } 43956- 43957- m, err := r.data.Mapper(uri) 43958- if err != nil { 43959- t.Fatal(err) 43960- } 43961- got, _, err := source.ApplyProtocolEdits(m, edits) 43962- if err != nil { 43963- t.Error(err) 43964- } 43965- 43966- withinlayHints := r.data.Golden(t, "inlayHint", filename, func() ([]byte, error) { 43967- return got, nil 43968- }) 43969- 43970- if !bytes.Equal(withinlayHints, got) { 43971- t.Errorf("inlay hints failed for %s, expected:\n%s\ngot:\n%s", filename, withinlayHints, got) 43972- } 43973-} 43974- 43975-func (r *runner) Rename(t *testing.T, spn span.Span, newText string) { 43976- tag := fmt.Sprintf("%s-rename", newText) 43977- 43978- uri := spn.URI() 43979- filename := uri.Filename() 43980- sm, err := r.data.Mapper(uri) 43981- if err != nil { 43982- t.Fatal(err) 43983- } 43984- loc, err := sm.SpanLocation(spn) 43985- if err != nil { 43986- t.Fatalf("failed for %v: %v", spn, err) 43987- } 43988- 43989- wedit, err := r.server.Rename(r.ctx, &protocol.RenameParams{ 43990- TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, 43991- Position: loc.Range.Start, 43992- NewName: newText, 43993- }) 43994- if err != nil { 43995- renamed := string(r.data.Golden(t, tag, filename, func() ([]byte, error) { 43996- return []byte(err.Error()), nil 43997- })) 43998- if err.Error() != renamed { 43999- t.Errorf("%s: rename failed for %s, expected:\n%v\ngot:\n%v\n", spn, newText, renamed, err) 44000- } 44001- return 44002- } 44003- res, err := applyTextDocumentEdits(r, wedit.DocumentChanges) 44004- if err != nil { 44005- t.Fatal(err) 44006- } 44007- var orderedURIs []string 44008- for uri := range res { 44009- orderedURIs = append(orderedURIs, string(uri)) 44010- } 44011- sort.Strings(orderedURIs) 44012- 44013- // Print the name and content of each modified file, 44014- // concatenated, and compare against the golden. 44015- var buf bytes.Buffer 44016- for i := 0; i < len(res); i++ { 44017- if i != 0 { 44018- buf.WriteByte('\n') 44019- } 44020- uri := span.URIFromURI(orderedURIs[i]) 44021- if len(res) > 1 { 44022- buf.WriteString(filepath.Base(uri.Filename())) 44023- buf.WriteString(":\n") 44024- } 44025- buf.Write(res[uri]) 44026- } 44027- got := buf.Bytes() 44028- want := r.data.Golden(t, tag, filename, func() ([]byte, error) { 44029- return got, nil 44030- }) 44031- if diff := compare.Bytes(want, got); diff != "" { 44032- t.Errorf("rename failed for %s:\n%s", newText, diff) 44033- } 44034-} 44035- 44036-func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) { 44037- m, err := r.data.Mapper(src.URI()) 44038- if err != nil { 44039- t.Fatal(err) 44040- } 44041- loc, err := m.SpanLocation(src) 44042- if err != nil { 44043- t.Fatalf("failed for %v: %v", src, err) 44044- } 44045- params := &protocol.PrepareRenameParams{ 44046- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 44047- } 44048- got, err := r.server.PrepareRename(context.Background(), params) 44049- if err != nil { 44050- t.Errorf("prepare rename failed for %v: got error: %v", src, err) 44051- return 44052- } 44053- 44054- // TODO(rfindley): can we consolidate on a single representation for 44055- // PrepareRename results, and use cmp.Diff here? 44056- 44057- // PrepareRename may fail with no error if there was no object found at the 44058- // position. 44059- if got == nil { 44060- if want.Text != "" { // expected an ident. 44061- t.Errorf("prepare rename failed for %v: got nil", src) 44062- } 44063- return 44064- } 44065- if got.Range.Start == got.Range.End { 44066- // Special case for 0-length ranges. Marks can't specify a 0-length range, 44067- // so just compare the start. 44068- if got.Range.Start != want.Range.Start { 44069- t.Errorf("prepare rename failed: incorrect point, got %v want %v", got.Range.Start, want.Range.Start) 44070- } 44071- } else { 44072- if got.Range != want.Range { 44073- t.Errorf("prepare rename failed: incorrect range got %v want %v", got.Range, want.Range) 44074- } 44075- } 44076- if got.Placeholder != want.Text { 44077- t.Errorf("prepare rename failed: incorrect text got %v want %v", got.Placeholder, want.Text) 44078- } 44079-} 44080- 44081-func applyTextDocumentEdits(r *runner, edits []protocol.DocumentChanges) (map[span.URI][]byte, error) { 44082- res := make(map[span.URI][]byte) 44083- for _, docEdits := range edits { 44084- if docEdits.TextDocumentEdit != nil { 44085- uri := docEdits.TextDocumentEdit.TextDocument.URI.SpanURI() 44086- var m *protocol.Mapper 44087- // If we have already edited this file, we use the edited version (rather than the 44088- // file in its original state) so that we preserve our initial changes. 44089- if content, ok := res[uri]; ok { 44090- m = protocol.NewMapper(uri, content) 44091- } else { 44092- var err error 44093- if m, err = r.data.Mapper(uri); err != nil { 44094- return nil, err 44095- } 44096- } 44097- patched, _, err := source.ApplyProtocolEdits(m, docEdits.TextDocumentEdit.Edits) 44098- if err != nil { 44099- return nil, err 44100- } 44101- res[uri] = patched 44102- } 44103- } 44104- return res, nil 44105-} 44106- 44107-func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) { 44108- params := &protocol.DocumentSymbolParams{ 44109- TextDocument: protocol.TextDocumentIdentifier{ 44110- URI: protocol.URIFromSpanURI(uri), 44111- }, 44112- } 44113- got, err := r.server.DocumentSymbol(r.ctx, params) 44114- if err != nil { 44115- t.Fatal(err) 44116- } 44117- 44118- symbols := make([]protocol.DocumentSymbol, len(got)) 44119- for i, s := range got { 44120- s, ok := s.(protocol.DocumentSymbol) 44121- if !ok { 44122- t.Fatalf("%v: wanted []DocumentSymbols but got %v", uri, got) 44123- } 44124- symbols[i] = s 44125- } 44126- 44127- // Sort by position to make it easier to find errors. 44128- sortSymbols := func(s []protocol.DocumentSymbol) { 44129- sort.Slice(s, func(i, j int) bool { 44130- return protocol.CompareRange(s[i].SelectionRange, s[j].SelectionRange) < 0 44131- }) 44132- } 44133- sortSymbols(expectedSymbols) 44134- sortSymbols(symbols) 44135- 44136- // Ignore 'Range' here as it is difficult (impossible?) to express 44137- // multi-line ranges in the packagestest framework. 44138- ignoreRange := cmpopts.IgnoreFields(protocol.DocumentSymbol{}, "Range") 44139- if diff := cmp.Diff(expectedSymbols, symbols, ignoreRange); diff != "" { 44140- t.Errorf("mismatching symbols (-want +got)\n%s", diff) 44141- } 44142-} 44143- 44144-func (r *runner) WorkspaceSymbols(t *testing.T, uri span.URI, query string, typ tests.WorkspaceSymbolsTestType) { 44145- matcher := tests.WorkspaceSymbolsTestTypeToMatcher(typ) 44146- 44147- original := r.server.session.Options() 44148- modified := original 44149- modified.SymbolMatcher = matcher 44150- r.server.session.SetOptions(modified) 44151- defer r.server.session.SetOptions(original) 44152- 44153- params := &protocol.WorkspaceSymbolParams{ 44154- Query: query, 44155- } 44156- gotSymbols, err := r.server.Symbol(r.ctx, params) 44157- if err != nil { 44158- t.Fatal(err) 44159- } 44160- got, err := tests.WorkspaceSymbolsString(r.ctx, r.data, uri, gotSymbols) 44161- if err != nil { 44162- t.Fatal(err) 44163- } 44164- got = filepath.ToSlash(tests.Normalize(got, r.normalizers)) 44165- want := string(r.data.Golden(t, fmt.Sprintf("workspace_symbol-%s-%s", strings.ToLower(string(matcher)), query), uri.Filename(), func() ([]byte, error) { 44166- return []byte(got), nil 44167- })) 44168- if diff := compare.Text(want, got); diff != "" { 44169- t.Error(diff) 44170- } 44171-} 44172- 44173-func (r *runner) SignatureHelp(t *testing.T, spn span.Span, want *protocol.SignatureHelp) { 44174- m, err := r.data.Mapper(spn.URI()) 44175- if err != nil { 44176- t.Fatal(err) 44177- } 44178- loc, err := m.SpanLocation(spn) 44179- if err != nil { 44180- t.Fatalf("failed for %v: %v", loc, err) 44181- } 44182- params := &protocol.SignatureHelpParams{ 44183- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 44184- } 44185- got, err := r.server.SignatureHelp(r.ctx, params) 44186- if err != nil { 44187- // Only fail if we got an error we did not expect. 44188- if want != nil { 44189- t.Fatal(err) 44190- } 44191- return 44192- } 44193- if want == nil { 44194- if got != nil { 44195- t.Errorf("expected no signature, got %v", got) 44196- } 44197- return 44198- } 44199- if got == nil { 44200- t.Fatalf("expected %v, got nil", want) 44201- } 44202- if diff := tests.DiffSignatures(spn, want, got); diff != "" { 44203- t.Error(diff) 44204- } 44205-} 44206- 44207-func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) { 44208- m, err := r.data.Mapper(uri) 44209- if err != nil { 44210- t.Fatal(err) 44211- } 44212- got, err := r.server.DocumentLink(r.ctx, &protocol.DocumentLinkParams{ 44213- TextDocument: protocol.TextDocumentIdentifier{ 44214- URI: protocol.URIFromSpanURI(uri), 44215- }, 44216- }) 44217- if err != nil { 44218- t.Fatal(err) 44219- } 44220- if diff := tests.DiffLinks(m, wantLinks, got); diff != "" { 44221- t.Error(diff) 44222- } 44223-} 44224- 44225-func (r *runner) AddImport(t *testing.T, uri span.URI, expectedImport string) { 44226- cmd, err := command.NewListKnownPackagesCommand("List Known Packages", command.URIArg{ 44227- URI: protocol.URIFromSpanURI(uri), 44228- }) 44229- if err != nil { 44230- t.Fatal(err) 44231- } 44232- resp, err := r.server.executeCommand(r.ctx, &protocol.ExecuteCommandParams{ 44233- Command: cmd.Command, 44234- Arguments: cmd.Arguments, 44235- }) 44236- if err != nil { 44237- t.Fatal(err) 44238- } 44239- res := resp.(command.ListKnownPackagesResult) 44240- var hasPkg bool 44241- for _, p := range res.Packages { 44242- if p == expectedImport { 44243- hasPkg = true 44244- break 44245- } 44246- } 44247- if !hasPkg { 44248- t.Fatalf("%s: got %v packages\nwant contains %q", command.ListKnownPackages, res.Packages, expectedImport) 44249- } 44250- cmd, err = command.NewAddImportCommand("Add Imports", command.AddImportArgs{ 44251- URI: protocol.URIFromSpanURI(uri), 44252- ImportPath: expectedImport, 44253- }) 44254- if err != nil { 44255- t.Fatal(err) 44256- } 44257- _, err = r.server.executeCommand(r.ctx, &protocol.ExecuteCommandParams{ 44258- Command: cmd.Command, 44259- Arguments: cmd.Arguments, 44260- }) 44261- if err != nil { 44262- t.Fatal(err) 44263- } 44264- got := (<-r.editRecv)[uri] 44265- want := r.data.Golden(t, "addimport", uri.Filename(), func() ([]byte, error) { 44266- return []byte(got), nil 44267- }) 44268- if want == nil { 44269- t.Fatalf("golden file %q not found", uri.Filename()) 44270- } 44271- if diff := compare.Bytes(want, got); diff != "" { 44272- t.Errorf("%s mismatch\n%s", command.AddImport, diff) 44273- } 44274-} 44275- 44276-func (r *runner) SelectionRanges(t *testing.T, spn span.Span) { 44277- uri := spn.URI() 44278- sm, err := r.data.Mapper(uri) 44279- if err != nil { 44280- t.Fatal(err) 44281- } 44282- loc, err := sm.SpanLocation(spn) 44283- if err != nil { 44284- t.Error(err) 44285- } 44286- 44287- ranges, err := r.server.selectionRange(r.ctx, &protocol.SelectionRangeParams{ 44288- TextDocument: protocol.TextDocumentIdentifier{ 44289- URI: protocol.URIFromSpanURI(uri), 44290- }, 44291- Positions: []protocol.Position{loc.Range.Start}, 44292- }) 44293- if err != nil { 44294- t.Fatal(err) 44295- } 44296- 44297- sb := &strings.Builder{} 44298- for i, path := range ranges { 44299- fmt.Fprintf(sb, "Ranges %d: ", i) 44300- rng := path 44301- for { 44302- s, e, err := sm.RangeOffsets(rng.Range) 44303- if err != nil { 44304- t.Error(err) 44305- } 44306- 44307- var snippet string 44308- if e-s < 30 { 44309- snippet = string(sm.Content[s:e]) 44310- } else { 44311- snippet = string(sm.Content[s:s+15]) + "..." + string(sm.Content[e-15:e]) 44312- } 44313- 44314- fmt.Fprintf(sb, "\n\t%v %q", rng.Range, strings.ReplaceAll(snippet, "\n", "\\n")) 44315- 44316- if rng.Parent == nil { 44317- break 44318- } 44319- rng = *rng.Parent 44320- } 44321- sb.WriteRune('\n') 44322- } 44323- got := sb.String() 44324- 44325- testName := "selectionrange_" + tests.SpanName(spn) 44326- want := r.data.Golden(t, testName, uri.Filename(), func() ([]byte, error) { 44327- return []byte(got), nil 44328- }) 44329- if want == nil { 44330- t.Fatalf("golden file %q not found", uri.Filename()) 44331- } 44332- if diff := compare.Text(got, string(want)); diff != "" { 44333- t.Errorf("%s mismatch\n%s", testName, diff) 44334- } 44335-} 44336- 44337-func (r *runner) collectDiagnostics(view *cache.View) { 44338- if r.diagnostics != nil { 44339- return 44340- } 44341- r.diagnostics = make(map[span.URI][]*source.Diagnostic) 44342- 44343- snapshot, release, err := view.Snapshot() 44344- if err != nil { 44345- panic(err) 44346- } 44347- defer release() 44348- 44349- // Always run diagnostics with analysis. 44350- r.server.diagnose(r.ctx, snapshot, true) 44351- for uri, reports := range r.server.diagnostics { 44352- for _, report := range reports.reports { 44353- for _, d := range report.diags { 44354- r.diagnostics[uri] = append(r.diagnostics[uri], d) 44355- } 44356- } 44357- } 44358-} 44359diff -urN a/gopls/internal/lsp/mod/code_lens.go b/gopls/internal/lsp/mod/code_lens.go 44360--- a/gopls/internal/lsp/mod/code_lens.go 2000-01-01 00:00:00.000000000 -0000 44361+++ b/gopls/internal/lsp/mod/code_lens.go 1970-01-01 00:00:00.000000000 +0000 44362@@ -1,191 +0,0 @@ 44363-// Copyright 2020 The Go Authors. All rights reserved. 44364-// Use of this source code is governed by a BSD-style 44365-// license that can be found in the LICENSE file. 44366- 44367-package mod 44368- 44369-import ( 44370- "context" 44371- "fmt" 44372- "os" 44373- "path/filepath" 44374- 44375- "golang.org/x/mod/modfile" 44376- "golang.org/x/tools/gopls/internal/lsp/command" 44377- "golang.org/x/tools/gopls/internal/lsp/protocol" 44378- "golang.org/x/tools/gopls/internal/lsp/source" 44379-) 44380- 44381-// LensFuncs returns the supported lensFuncs for go.mod files. 44382-func LensFuncs() map[command.Command]source.LensFunc { 44383- return map[command.Command]source.LensFunc{ 44384- command.UpgradeDependency: upgradeLenses, 44385- command.Tidy: tidyLens, 44386- command.Vendor: vendorLens, 44387- command.RunGovulncheck: vulncheckLenses, 44388- } 44389-} 44390- 44391-func upgradeLenses(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 44392- pm, err := snapshot.ParseMod(ctx, fh) 44393- if err != nil || pm.File == nil { 44394- return nil, err 44395- } 44396- uri := protocol.URIFromSpanURI(fh.URI()) 44397- reset, err := command.NewResetGoModDiagnosticsCommand("Reset go.mod diagnostics", command.ResetGoModDiagnosticsArgs{URIArg: command.URIArg{URI: uri}}) 44398- if err != nil { 44399- return nil, err 44400- } 44401- // Put the `Reset go.mod diagnostics` codelens on the module statement. 44402- modrng, err := moduleStmtRange(fh, pm) 44403- if err != nil { 44404- return nil, err 44405- } 44406- lenses := []protocol.CodeLens{{Range: modrng, Command: &reset}} 44407- if len(pm.File.Require) == 0 { 44408- // Nothing to upgrade. 44409- return lenses, nil 44410- } 44411- var requires []string 44412- for _, req := range pm.File.Require { 44413- requires = append(requires, req.Mod.Path) 44414- } 44415- checkUpgrade, err := command.NewCheckUpgradesCommand("Check for upgrades", command.CheckUpgradesArgs{ 44416- URI: uri, 44417- Modules: requires, 44418- }) 44419- if err != nil { 44420- return nil, err 44421- } 44422- upgradeTransitive, err := command.NewUpgradeDependencyCommand("Upgrade transitive dependencies", command.DependencyArgs{ 44423- URI: uri, 44424- AddRequire: false, 44425- GoCmdArgs: []string{"-d", "-u", "-t", "./..."}, 44426- }) 44427- if err != nil { 44428- return nil, err 44429- } 44430- upgradeDirect, err := command.NewUpgradeDependencyCommand("Upgrade direct dependencies", command.DependencyArgs{ 44431- URI: uri, 44432- AddRequire: false, 44433- GoCmdArgs: append([]string{"-d"}, requires...), 44434- }) 44435- if err != nil { 44436- return nil, err 44437- } 44438- 44439- // Put the upgrade code lenses above the first require block or statement. 44440- rng, err := firstRequireRange(fh, pm) 44441- if err != nil { 44442- return nil, err 44443- } 44444- 44445- return append(lenses, []protocol.CodeLens{ 44446- {Range: rng, Command: &checkUpgrade}, 44447- {Range: rng, Command: &upgradeTransitive}, 44448- {Range: rng, Command: &upgradeDirect}, 44449- }...), nil 44450-} 44451- 44452-func tidyLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 44453- pm, err := snapshot.ParseMod(ctx, fh) 44454- if err != nil || pm.File == nil { 44455- return nil, err 44456- } 44457- uri := protocol.URIFromSpanURI(fh.URI()) 44458- cmd, err := command.NewTidyCommand("Run go mod tidy", command.URIArgs{URIs: []protocol.DocumentURI{uri}}) 44459- if err != nil { 44460- return nil, err 44461- } 44462- rng, err := moduleStmtRange(fh, pm) 44463- if err != nil { 44464- return nil, err 44465- } 44466- return []protocol.CodeLens{{ 44467- Range: rng, 44468- Command: &cmd, 44469- }}, nil 44470-} 44471- 44472-func vendorLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 44473- pm, err := snapshot.ParseMod(ctx, fh) 44474- if err != nil || pm.File == nil { 44475- return nil, err 44476- } 44477- if len(pm.File.Require) == 0 { 44478- // Nothing to vendor. 44479- return nil, nil 44480- } 44481- rng, err := moduleStmtRange(fh, pm) 44482- if err != nil { 44483- return nil, err 44484- } 44485- title := "Create vendor directory" 44486- uri := protocol.URIFromSpanURI(fh.URI()) 44487- cmd, err := command.NewVendorCommand(title, command.URIArg{URI: uri}) 44488- if err != nil { 44489- return nil, err 44490- } 44491- // Change the message depending on whether or not the module already has a 44492- // vendor directory. 44493- vendorDir := filepath.Join(filepath.Dir(fh.URI().Filename()), "vendor") 44494- if info, _ := os.Stat(vendorDir); info != nil && info.IsDir() { 44495- title = "Sync vendor directory" 44496- } 44497- return []protocol.CodeLens{{Range: rng, Command: &cmd}}, nil 44498-} 44499- 44500-func moduleStmtRange(fh source.FileHandle, pm *source.ParsedModule) (protocol.Range, error) { 44501- if pm.File == nil || pm.File.Module == nil || pm.File.Module.Syntax == nil { 44502- return protocol.Range{}, fmt.Errorf("no module statement in %s", fh.URI()) 44503- } 44504- syntax := pm.File.Module.Syntax 44505- return pm.Mapper.OffsetRange(syntax.Start.Byte, syntax.End.Byte) 44506-} 44507- 44508-// firstRequireRange returns the range for the first "require" in the given 44509-// go.mod file. This is either a require block or an individual require line. 44510-func firstRequireRange(fh source.FileHandle, pm *source.ParsedModule) (protocol.Range, error) { 44511- if len(pm.File.Require) == 0 { 44512- return protocol.Range{}, fmt.Errorf("no requires in the file %s", fh.URI()) 44513- } 44514- var start, end modfile.Position 44515- for _, stmt := range pm.File.Syntax.Stmt { 44516- if b, ok := stmt.(*modfile.LineBlock); ok && len(b.Token) == 1 && b.Token[0] == "require" { 44517- start, end = b.Span() 44518- break 44519- } 44520- } 44521- 44522- firstRequire := pm.File.Require[0].Syntax 44523- if start.Byte == 0 || firstRequire.Start.Byte < start.Byte { 44524- start, end = firstRequire.Start, firstRequire.End 44525- } 44526- return pm.Mapper.OffsetRange(start.Byte, end.Byte) 44527-} 44528- 44529-func vulncheckLenses(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 44530- pm, err := snapshot.ParseMod(ctx, fh) 44531- if err != nil || pm.File == nil { 44532- return nil, err 44533- } 44534- // Place the codelenses near the module statement. 44535- // A module may not have the require block, 44536- // but vulnerabilities can exist in standard libraries. 44537- uri := protocol.URIFromSpanURI(fh.URI()) 44538- rng, err := moduleStmtRange(fh, pm) 44539- if err != nil { 44540- return nil, err 44541- } 44542- 44543- vulncheck, err := command.NewRunGovulncheckCommand("Run govulncheck", command.VulncheckArgs{ 44544- URI: uri, 44545- Pattern: "./...", 44546- }) 44547- if err != nil { 44548- return nil, err 44549- } 44550- return []protocol.CodeLens{ 44551- {Range: rng, Command: &vulncheck}, 44552- }, nil 44553-} 44554diff -urN a/gopls/internal/lsp/mod/diagnostics.go b/gopls/internal/lsp/mod/diagnostics.go 44555--- a/gopls/internal/lsp/mod/diagnostics.go 2000-01-01 00:00:00.000000000 -0000 44556+++ b/gopls/internal/lsp/mod/diagnostics.go 1970-01-01 00:00:00.000000000 +0000 44557@@ -1,561 +0,0 @@ 44558-// Copyright 2019 The Go Authors. All rights reserved. 44559-// Use of this source code is governed by a BSD-style 44560-// license that can be found in the LICENSE file. 44561- 44562-// Package mod provides core features related to go.mod file 44563-// handling for use by Go editors and tools. 44564-package mod 44565- 44566-import ( 44567- "context" 44568- "fmt" 44569- "sort" 44570- "strings" 44571- 44572- "golang.org/x/mod/modfile" 44573- "golang.org/x/mod/semver" 44574- "golang.org/x/tools/gopls/internal/govulncheck" 44575- "golang.org/x/tools/gopls/internal/lsp/command" 44576- "golang.org/x/tools/gopls/internal/lsp/protocol" 44577- "golang.org/x/tools/gopls/internal/lsp/source" 44578- "golang.org/x/tools/gopls/internal/span" 44579- "golang.org/x/tools/internal/event" 44580- "golang.org/x/vuln/osv" 44581-) 44582- 44583-// Diagnostics returns diagnostics for the modules in the workspace. 44584-// 44585-// It waits for completion of type-checking of all active packages. 44586-func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) { 44587- ctx, done := event.Start(ctx, "mod.Diagnostics", source.SnapshotLabels(snapshot)...) 44588- defer done() 44589- 44590- return collectDiagnostics(ctx, snapshot, ModDiagnostics) 44591-} 44592- 44593-// UpgradeDiagnostics returns upgrade diagnostics for the modules in the 44594-// workspace with known upgrades. 44595-func UpgradeDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) { 44596- ctx, done := event.Start(ctx, "mod.UpgradeDiagnostics", source.SnapshotLabels(snapshot)...) 44597- defer done() 44598- 44599- return collectDiagnostics(ctx, snapshot, ModUpgradeDiagnostics) 44600-} 44601- 44602-// VulnerabilityDiagnostics returns vulnerability diagnostics for the active modules in the 44603-// workspace with known vulnerabilities. 44604-func VulnerabilityDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) { 44605- ctx, done := event.Start(ctx, "mod.VulnerabilityDiagnostics", source.SnapshotLabels(snapshot)...) 44606- defer done() 44607- 44608- return collectDiagnostics(ctx, snapshot, ModVulnerabilityDiagnostics) 44609-} 44610- 44611-func collectDiagnostics(ctx context.Context, snapshot source.Snapshot, diagFn func(context.Context, source.Snapshot, source.FileHandle) ([]*source.Diagnostic, error)) (map[span.URI][]*source.Diagnostic, error) { 44612- reports := make(map[span.URI][]*source.Diagnostic) 44613- for _, uri := range snapshot.ModFiles() { 44614- fh, err := snapshot.GetFile(ctx, uri) 44615- if err != nil { 44616- return nil, err 44617- } 44618- reports[fh.URI()] = []*source.Diagnostic{} 44619- diagnostics, err := diagFn(ctx, snapshot, fh) 44620- if err != nil { 44621- return nil, err 44622- } 44623- for _, d := range diagnostics { 44624- fh, err := snapshot.GetFile(ctx, d.URI) 44625- if err != nil { 44626- return nil, err 44627- } 44628- reports[fh.URI()] = append(reports[fh.URI()], d) 44629- } 44630- } 44631- return reports, nil 44632-} 44633- 44634-// ModDiagnostics waits for completion of type-checking of all active 44635-// packages, then returns diagnostics from diagnosing the packages in 44636-// the workspace and from tidying the go.mod file. 44637-func ModDiagnostics(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) (diagnostics []*source.Diagnostic, err error) { 44638- pm, err := snapshot.ParseMod(ctx, fh) 44639- if err != nil { 44640- if pm == nil || len(pm.ParseErrors) == 0 { 44641- return nil, err 44642- } 44643- return pm.ParseErrors, nil 44644- } 44645- 44646- // Packages in the workspace can contribute diagnostics to go.mod files. 44647- // TODO(rfindley): Try to avoid type checking all packages in the workspace here, 44648- // for every go.mod file. If gc_details is enabled, it looks like this could lead to extra 44649- // go command invocations (as gc details is not memoized). 44650- active, err := snapshot.ActiveMetadata(ctx) 44651- if err != nil && !source.IsNonFatalGoModError(err) { 44652- event.Error(ctx, fmt.Sprintf("workspace packages: diagnosing %s", pm.URI), err) 44653- } 44654- if err == nil { 44655- // Note: the call to PackageDiagnostics below may be the first operation 44656- // after the initial metadata load, and therefore result in type-checking 44657- // or loading many packages. 44658- ids := make([]source.PackageID, len(active)) 44659- for i, meta := range active { 44660- ids[i] = meta.ID 44661- } 44662- diags, err := snapshot.PackageDiagnostics(ctx, ids...) 44663- if err != nil { 44664- return nil, err 44665- } 44666- diagnostics = append(diagnostics, diags[fh.URI()]...) 44667- } 44668- 44669- tidied, err := snapshot.ModTidy(ctx, pm) 44670- if err != nil && !source.IsNonFatalGoModError(err) { 44671- event.Error(ctx, fmt.Sprintf("tidy: diagnosing %s", pm.URI), err) 44672- } 44673- if err == nil { 44674- for _, d := range tidied.Diagnostics { 44675- if d.URI != fh.URI() { 44676- continue 44677- } 44678- diagnostics = append(diagnostics, d) 44679- } 44680- } 44681- return diagnostics, nil 44682-} 44683- 44684-// ModUpgradeDiagnostics adds upgrade quick fixes for individual modules if the upgrades 44685-// are recorded in the view. 44686-func ModUpgradeDiagnostics(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) (upgradeDiagnostics []*source.Diagnostic, err error) { 44687- pm, err := snapshot.ParseMod(ctx, fh) 44688- if err != nil { 44689- // Don't return an error if there are parse error diagnostics to be shown, but also do not 44690- // continue since we won't be able to show the upgrade diagnostics. 44691- if pm != nil && len(pm.ParseErrors) != 0 { 44692- return nil, nil 44693- } 44694- return nil, err 44695- } 44696- 44697- upgrades := snapshot.View().ModuleUpgrades(fh.URI()) 44698- for _, req := range pm.File.Require { 44699- ver, ok := upgrades[req.Mod.Path] 44700- if !ok || req.Mod.Version == ver { 44701- continue 44702- } 44703- rng, err := pm.Mapper.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) 44704- if err != nil { 44705- return nil, err 44706- } 44707- // Upgrade to the exact version we offer the user, not the most recent. 44708- title := fmt.Sprintf("%s%v", upgradeCodeActionPrefix, ver) 44709- cmd, err := command.NewUpgradeDependencyCommand(title, command.DependencyArgs{ 44710- URI: protocol.URIFromSpanURI(fh.URI()), 44711- AddRequire: false, 44712- GoCmdArgs: []string{req.Mod.Path + "@" + ver}, 44713- }) 44714- if err != nil { 44715- return nil, err 44716- } 44717- upgradeDiagnostics = append(upgradeDiagnostics, &source.Diagnostic{ 44718- URI: fh.URI(), 44719- Range: rng, 44720- Severity: protocol.SeverityInformation, 44721- Source: source.UpgradeNotification, 44722- Message: fmt.Sprintf("%v can be upgraded", req.Mod.Path), 44723- SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, 44724- }) 44725- } 44726- 44727- return upgradeDiagnostics, nil 44728-} 44729- 44730-const upgradeCodeActionPrefix = "Upgrade to " 44731- 44732-// ModVulnerabilityDiagnostics adds diagnostics for vulnerabilities in individual modules 44733-// if the vulnerability is recorded in the view. 44734-func ModVulnerabilityDiagnostics(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) (vulnDiagnostics []*source.Diagnostic, err error) { 44735- pm, err := snapshot.ParseMod(ctx, fh) 44736- if err != nil { 44737- // Don't return an error if there are parse error diagnostics to be shown, but also do not 44738- // continue since we won't be able to show the vulnerability diagnostics. 44739- if pm != nil && len(pm.ParseErrors) != 0 { 44740- return nil, nil 44741- } 44742- return nil, err 44743- } 44744- 44745- diagSource := source.Govulncheck 44746- vs := snapshot.View().Vulnerabilities(fh.URI())[fh.URI()] 44747- if vs == nil && snapshot.View().Options().Vulncheck == source.ModeVulncheckImports { 44748- vs, err = snapshot.ModVuln(ctx, fh.URI()) 44749- if err != nil { 44750- return nil, err 44751- } 44752- diagSource = source.Vulncheck 44753- } 44754- if vs == nil || len(vs.Vulns) == 0 { 44755- return nil, nil 44756- } 44757- 44758- suggestRunOrResetGovulncheck, err := suggestGovulncheckAction(diagSource == source.Govulncheck, fh.URI()) 44759- if err != nil { 44760- // must not happen 44761- return nil, err // TODO: bug report 44762- } 44763- type modVuln struct { 44764- mod *govulncheck.Module 44765- vuln *govulncheck.Vuln 44766- } 44767- vulnsByModule := make(map[string][]modVuln) 44768- for _, vuln := range vs.Vulns { 44769- for _, mod := range vuln.Modules { 44770- vulnsByModule[mod.Path] = append(vulnsByModule[mod.Path], modVuln{mod, vuln}) 44771- } 44772- } 44773- 44774- for _, req := range pm.File.Require { 44775- vulns := vulnsByModule[req.Mod.Path] 44776- if len(vulns) == 0 { 44777- continue 44778- } 44779- // note: req.Syntax is the line corresponding to 'require', which means 44780- // req.Syntax.Start can point to the beginning of the "require" keyword 44781- // for a single line require (e.g. "require golang.org/x/mod v0.0.0"). 44782- start := req.Syntax.Start.Byte 44783- if len(req.Syntax.Token) == 3 { 44784- start += len("require ") 44785- } 44786- rng, err := pm.Mapper.OffsetRange(start, req.Syntax.End.Byte) 44787- if err != nil { 44788- return nil, err 44789- } 44790- // Map affecting vulns to 'warning' level diagnostics, 44791- // others to 'info' level diagnostics. 44792- // Fixes will include only the upgrades for warning level diagnostics. 44793- var warningFixes, infoFixes []source.SuggestedFix 44794- var warning, info []string 44795- var relatedInfo []protocol.DiagnosticRelatedInformation 44796- for _, mv := range vulns { 44797- mod, vuln := mv.mod, mv.vuln 44798- // It is possible that the source code was changed since the last 44799- // govulncheck run and information in the `vulns` info is stale. 44800- // For example, imagine that a user is in the middle of updating 44801- // problematic modules detected by the govulncheck run by applying 44802- // quick fixes. Stale diagnostics can be confusing and prevent the 44803- // user from quickly locating the next module to fix. 44804- // Ideally we should rerun the analysis with the updated module 44805- // dependencies or any other code changes, but we are not yet 44806- // in the position of automatically triggering the analysis 44807- // (govulncheck can take a while). We also don't know exactly what 44808- // part of source code was changed since `vulns` was computed. 44809- // As a heuristic, we assume that a user upgrades the affecting 44810- // module to the version with the fix or the latest one, and if the 44811- // version in the require statement is equal to or higher than the 44812- // fixed version, skip generating a diagnostic about the vulnerability. 44813- // Eventually, the user has to rerun govulncheck. 44814- if mod.FixedVersion != "" && semver.IsValid(req.Mod.Version) && semver.Compare(mod.FixedVersion, req.Mod.Version) <= 0 { 44815- continue 44816- } 44817- if !vuln.IsCalled() { 44818- info = append(info, vuln.OSV.ID) 44819- } else { 44820- warning = append(warning, vuln.OSV.ID) 44821- relatedInfo = append(relatedInfo, listRelatedInfo(ctx, snapshot, vuln)...) 44822- } 44823- // Upgrade to the exact version we offer the user, not the most recent. 44824- if fixedVersion := mod.FixedVersion; semver.IsValid(fixedVersion) && semver.Compare(req.Mod.Version, fixedVersion) < 0 { 44825- cmd, err := getUpgradeCodeAction(fh, req, fixedVersion) 44826- if err != nil { 44827- return nil, err // TODO: bug report 44828- } 44829- sf := source.SuggestedFixFromCommand(cmd, protocol.QuickFix) 44830- if !vuln.IsCalled() { 44831- infoFixes = append(infoFixes, sf) 44832- } else { 44833- warningFixes = append(warningFixes, sf) 44834- } 44835- } 44836- } 44837- 44838- if len(warning) == 0 && len(info) == 0 { 44839- continue 44840- } 44841- // Add an upgrade for module@latest. 44842- // TODO(suzmue): verify if latest is the same as fixedVersion. 44843- latest, err := getUpgradeCodeAction(fh, req, "latest") 44844- if err != nil { 44845- return nil, err // TODO: bug report 44846- } 44847- sf := source.SuggestedFixFromCommand(latest, protocol.QuickFix) 44848- if len(warningFixes) > 0 { 44849- warningFixes = append(warningFixes, sf) 44850- } 44851- if len(infoFixes) > 0 { 44852- infoFixes = append(infoFixes, sf) 44853- } 44854- 44855- sort.Strings(warning) 44856- sort.Strings(info) 44857- 44858- if len(warning) > 0 { 44859- warningFixes = append(warningFixes, suggestRunOrResetGovulncheck) 44860- vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{ 44861- URI: fh.URI(), 44862- Range: rng, 44863- Severity: protocol.SeverityWarning, 44864- Source: diagSource, 44865- Message: getVulnMessage(req.Mod.Path, warning, true, diagSource == source.Govulncheck), 44866- SuggestedFixes: warningFixes, 44867- Related: relatedInfo, 44868- }) 44869- } 44870- if len(info) > 0 { 44871- infoFixes = append(infoFixes, suggestRunOrResetGovulncheck) 44872- vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{ 44873- URI: fh.URI(), 44874- Range: rng, 44875- Severity: protocol.SeverityInformation, 44876- Source: diagSource, 44877- Message: getVulnMessage(req.Mod.Path, info, false, diagSource == source.Govulncheck), 44878- SuggestedFixes: infoFixes, 44879- Related: relatedInfo, 44880- }) 44881- } 44882- } 44883- 44884- // TODO(hyangah): place this diagnostic on the `go` directive or `toolchain` directive 44885- // after https://go.dev/issue/57001. 44886- const diagnoseStdLib = false 44887- if diagnoseStdLib { 44888- // Add standard library vulnerabilities. 44889- stdlibVulns := vulnsByModule["stdlib"] 44890- if len(stdlibVulns) == 0 { 44891- return vulnDiagnostics, nil 44892- } 44893- 44894- // Put the standard library diagnostic on the module declaration. 44895- rng, err := pm.Mapper.OffsetRange(pm.File.Module.Syntax.Start.Byte, pm.File.Module.Syntax.End.Byte) 44896- if err != nil { 44897- return vulnDiagnostics, nil // TODO: bug report 44898- } 44899- 44900- stdlib := stdlibVulns[0].mod.FoundVersion 44901- var warning, info []string 44902- var relatedInfo []protocol.DiagnosticRelatedInformation 44903- for _, mv := range stdlibVulns { 44904- vuln := mv.vuln 44905- stdlib = mv.mod.FoundVersion 44906- if !vuln.IsCalled() { 44907- info = append(info, vuln.OSV.ID) 44908- } else { 44909- warning = append(warning, vuln.OSV.ID) 44910- relatedInfo = append(relatedInfo, listRelatedInfo(ctx, snapshot, vuln)...) 44911- } 44912- } 44913- if len(warning) > 0 { 44914- fixes := []source.SuggestedFix{suggestRunOrResetGovulncheck} 44915- vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{ 44916- URI: fh.URI(), 44917- Range: rng, 44918- Severity: protocol.SeverityWarning, 44919- Source: diagSource, 44920- Message: getVulnMessage(stdlib, warning, true, diagSource == source.Govulncheck), 44921- SuggestedFixes: fixes, 44922- Related: relatedInfo, 44923- }) 44924- } 44925- if len(info) > 0 { 44926- fixes := []source.SuggestedFix{suggestRunOrResetGovulncheck} 44927- vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{ 44928- URI: fh.URI(), 44929- Range: rng, 44930- Severity: protocol.SeverityInformation, 44931- Source: diagSource, 44932- Message: getVulnMessage(stdlib, info, false, diagSource == source.Govulncheck), 44933- SuggestedFixes: fixes, 44934- Related: relatedInfo, 44935- }) 44936- } 44937- } 44938- 44939- return vulnDiagnostics, nil 44940-} 44941- 44942-// suggestGovulncheckAction returns a code action that suggests either run govulncheck 44943-// for more accurate investigation (if the present vulncheck diagnostics are based on 44944-// analysis less accurate than govulncheck) or reset the existing govulncheck result 44945-// (if the present vulncheck diagnostics are already based on govulncheck run). 44946-func suggestGovulncheckAction(fromGovulncheck bool, uri span.URI) (source.SuggestedFix, error) { 44947- if fromGovulncheck { 44948- resetVulncheck, err := command.NewResetGoModDiagnosticsCommand("Reset govulncheck result", command.ResetGoModDiagnosticsArgs{ 44949- URIArg: command.URIArg{URI: protocol.DocumentURI(uri)}, 44950- DiagnosticSource: string(source.Govulncheck), 44951- }) 44952- if err != nil { 44953- return source.SuggestedFix{}, err 44954- } 44955- return source.SuggestedFixFromCommand(resetVulncheck, protocol.QuickFix), nil 44956- } 44957- vulncheck, err := command.NewRunGovulncheckCommand("Run govulncheck to verify", command.VulncheckArgs{ 44958- URI: protocol.DocumentURI(uri), 44959- Pattern: "./...", 44960- }) 44961- if err != nil { 44962- return source.SuggestedFix{}, err 44963- } 44964- return source.SuggestedFixFromCommand(vulncheck, protocol.QuickFix), nil 44965-} 44966- 44967-func getVulnMessage(mod string, vulns []string, used, fromGovulncheck bool) string { 44968- var b strings.Builder 44969- if used { 44970- switch len(vulns) { 44971- case 1: 44972- fmt.Fprintf(&b, "%v has a vulnerability used in the code: %v.", mod, vulns[0]) 44973- default: 44974- fmt.Fprintf(&b, "%v has vulnerabilities used in the code: %v.", mod, strings.Join(vulns, ", ")) 44975- } 44976- } else { 44977- if fromGovulncheck { 44978- switch len(vulns) { 44979- case 1: 44980- fmt.Fprintf(&b, "%v has a vulnerability %v that is not used in the code.", mod, vulns[0]) 44981- default: 44982- fmt.Fprintf(&b, "%v has known vulnerabilities %v that are not used in the code.", mod, strings.Join(vulns, ", ")) 44983- } 44984- } else { 44985- switch len(vulns) { 44986- case 1: 44987- fmt.Fprintf(&b, "%v has a vulnerability %v.", mod, vulns[0]) 44988- default: 44989- fmt.Fprintf(&b, "%v has known vulnerabilities %v.", mod, strings.Join(vulns, ", ")) 44990- } 44991- } 44992- } 44993- return b.String() 44994-} 44995- 44996-func listRelatedInfo(ctx context.Context, snapshot source.Snapshot, vuln *govulncheck.Vuln) []protocol.DiagnosticRelatedInformation { 44997- var ri []protocol.DiagnosticRelatedInformation 44998- for _, m := range vuln.Modules { 44999- for _, p := range m.Packages { 45000- for _, c := range p.CallStacks { 45001- if len(c.Frames) == 0 { 45002- continue 45003- } 45004- entry := c.Frames[0] 45005- pos := entry.Position 45006- if pos.Filename == "" { 45007- continue // token.Position Filename is an optional field. 45008- } 45009- uri := span.URIFromPath(pos.Filename) 45010- startPos := protocol.Position{ 45011- Line: uint32(pos.Line) - 1, 45012- // We need to read the file contents to precisesly map 45013- // token.Position (pos) to the UTF16-based column offset 45014- // protocol.Position requires. That can be expensive. 45015- // We need this related info to just help users to open 45016- // the entry points of the callstack and once the file is 45017- // open, we will compute the precise location based on the 45018- // open file contents. So, use the beginning of the line 45019- // as the position here instead of precise UTF16-based 45020- // position computation. 45021- Character: 0, 45022- } 45023- ri = append(ri, protocol.DiagnosticRelatedInformation{ 45024- Location: protocol.Location{ 45025- URI: protocol.URIFromSpanURI(uri), 45026- Range: protocol.Range{ 45027- Start: startPos, 45028- End: startPos, 45029- }, 45030- }, 45031- Message: fmt.Sprintf("[%v] %v -> %v.%v", vuln.OSV.ID, entry.Name(), p.Path, c.Symbol), 45032- }) 45033- } 45034- } 45035- } 45036- return ri 45037-} 45038- 45039-func formatMessage(v *govulncheck.Vuln) string { 45040- details := []byte(v.OSV.Details) 45041- // Remove any new lines that are not preceded or followed by a new line. 45042- for i, r := range details { 45043- if r == '\n' && i > 0 && details[i-1] != '\n' && i+1 < len(details) && details[i+1] != '\n' { 45044- details[i] = ' ' 45045- } 45046- } 45047- return strings.TrimSpace(strings.Replace(string(details), "\n\n", "\n\n ", -1)) 45048-} 45049- 45050-// href returns the url for the vulnerability information. 45051-// Eventually we should retrieve the url embedded in the osv.Entry. 45052-// While vuln.go.dev is under development, this always returns 45053-// the page in pkg.go.dev. 45054-func href(vuln *osv.Entry) string { 45055- return fmt.Sprintf("https://pkg.go.dev/vuln/%s", vuln.ID) 45056-} 45057- 45058-func getUpgradeCodeAction(fh source.FileHandle, req *modfile.Require, version string) (protocol.Command, error) { 45059- cmd, err := command.NewUpgradeDependencyCommand(upgradeTitle(version), command.DependencyArgs{ 45060- URI: protocol.URIFromSpanURI(fh.URI()), 45061- AddRequire: false, 45062- GoCmdArgs: []string{req.Mod.Path + "@" + version}, 45063- }) 45064- if err != nil { 45065- return protocol.Command{}, err 45066- } 45067- return cmd, nil 45068-} 45069- 45070-func upgradeTitle(fixedVersion string) string { 45071- title := fmt.Sprintf("%s%v", upgradeCodeActionPrefix, fixedVersion) 45072- return title 45073-} 45074- 45075-// SelectUpgradeCodeActions takes a list of code actions for a required module 45076-// and returns a more selective list of upgrade code actions, 45077-// where the code actions have been deduped. Code actions unrelated to upgrade 45078-// are deduplicated by the name. 45079-func SelectUpgradeCodeActions(actions []protocol.CodeAction) []protocol.CodeAction { 45080- if len(actions) <= 1 { 45081- return actions // return early if no sorting necessary 45082- } 45083- var versionedUpgrade, latestUpgrade, resetAction protocol.CodeAction 45084- var chosenVersionedUpgrade string 45085- var selected []protocol.CodeAction 45086- 45087- seen := make(map[string]bool) 45088- 45089- for _, action := range actions { 45090- if strings.HasPrefix(action.Title, upgradeCodeActionPrefix) { 45091- if v := getUpgradeVersion(action); v == "latest" && latestUpgrade.Title == "" { 45092- latestUpgrade = action 45093- } else if versionedUpgrade.Title == "" || semver.Compare(v, chosenVersionedUpgrade) > 0 { 45094- chosenVersionedUpgrade = v 45095- versionedUpgrade = action 45096- } 45097- } else if strings.HasPrefix(action.Title, "Reset govulncheck") { 45098- resetAction = action 45099- } else if !seen[action.Command.Title] { 45100- seen[action.Command.Title] = true 45101- selected = append(selected, action) 45102- } 45103- } 45104- if versionedUpgrade.Title != "" { 45105- selected = append(selected, versionedUpgrade) 45106- } 45107- if latestUpgrade.Title != "" { 45108- selected = append(selected, latestUpgrade) 45109- } 45110- if resetAction.Title != "" { 45111- selected = append(selected, resetAction) 45112- } 45113- return selected 45114-} 45115- 45116-func getUpgradeVersion(p protocol.CodeAction) string { 45117- return strings.TrimPrefix(p.Title, upgradeCodeActionPrefix) 45118-} 45119diff -urN a/gopls/internal/lsp/mod/format.go b/gopls/internal/lsp/mod/format.go 45120--- a/gopls/internal/lsp/mod/format.go 2000-01-01 00:00:00.000000000 -0000 45121+++ b/gopls/internal/lsp/mod/format.go 1970-01-01 00:00:00.000000000 +0000 45122@@ -1,30 +0,0 @@ 45123-// Copyright 2020 The Go Authors. All rights reserved. 45124-// Use of this source code is governed by a BSD-style 45125-// license that can be found in the LICENSE file. 45126- 45127-package mod 45128- 45129-import ( 45130- "context" 45131- 45132- "golang.org/x/tools/gopls/internal/lsp/protocol" 45133- "golang.org/x/tools/gopls/internal/lsp/source" 45134- "golang.org/x/tools/internal/event" 45135-) 45136- 45137-func Format(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.TextEdit, error) { 45138- ctx, done := event.Start(ctx, "mod.Format") 45139- defer done() 45140- 45141- pm, err := snapshot.ParseMod(ctx, fh) 45142- if err != nil { 45143- return nil, err 45144- } 45145- formatted, err := pm.File.Format() 45146- if err != nil { 45147- return nil, err 45148- } 45149- // Calculate the edits to be made due to the change. 45150- diffs := snapshot.View().Options().ComputeEdits(string(pm.Mapper.Content), string(formatted)) 45151- return source.ToProtocolEdits(pm.Mapper, diffs) 45152-} 45153diff -urN a/gopls/internal/lsp/mod/hover.go b/gopls/internal/lsp/mod/hover.go 45154--- a/gopls/internal/lsp/mod/hover.go 2000-01-01 00:00:00.000000000 -0000 45155+++ b/gopls/internal/lsp/mod/hover.go 1970-01-01 00:00:00.000000000 +0000 45156@@ -1,358 +0,0 @@ 45157-// Copyright 2020 The Go Authors. All rights reserved. 45158-// Use of this source code is governed by a BSD-style 45159-// license that can be found in the LICENSE file. 45160- 45161-package mod 45162- 45163-import ( 45164- "bytes" 45165- "context" 45166- "fmt" 45167- "sort" 45168- "strings" 45169- 45170- "golang.org/x/mod/modfile" 45171- "golang.org/x/mod/semver" 45172- "golang.org/x/tools/gopls/internal/govulncheck" 45173- "golang.org/x/tools/gopls/internal/lsp/protocol" 45174- "golang.org/x/tools/gopls/internal/lsp/source" 45175- "golang.org/x/tools/internal/event" 45176-) 45177- 45178-func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.Hover, error) { 45179- var found bool 45180- for _, uri := range snapshot.ModFiles() { 45181- if fh.URI() == uri { 45182- found = true 45183- break 45184- } 45185- } 45186- 45187- // We only provide hover information for the view's go.mod files. 45188- if !found { 45189- return nil, nil 45190- } 45191- 45192- ctx, done := event.Start(ctx, "mod.Hover") 45193- defer done() 45194- 45195- // Get the position of the cursor. 45196- pm, err := snapshot.ParseMod(ctx, fh) 45197- if err != nil { 45198- return nil, fmt.Errorf("getting modfile handle: %w", err) 45199- } 45200- offset, err := pm.Mapper.PositionOffset(position) 45201- if err != nil { 45202- return nil, fmt.Errorf("computing cursor position: %w", err) 45203- } 45204- 45205- // If the cursor position is on a module statement 45206- if hover, ok := hoverOnModuleStatement(ctx, pm, offset, snapshot, fh); ok { 45207- return hover, nil 45208- } 45209- return hoverOnRequireStatement(ctx, pm, offset, snapshot, fh) 45210-} 45211- 45212-func hoverOnRequireStatement(ctx context.Context, pm *source.ParsedModule, offset int, snapshot source.Snapshot, fh source.FileHandle) (*protocol.Hover, error) { 45213- // Confirm that the cursor is at the position of a require statement. 45214- var req *modfile.Require 45215- var startOffset, endOffset int 45216- for _, r := range pm.File.Require { 45217- dep := []byte(r.Mod.Path) 45218- s, e := r.Syntax.Start.Byte, r.Syntax.End.Byte 45219- i := bytes.Index(pm.Mapper.Content[s:e], dep) 45220- if i == -1 { 45221- continue 45222- } 45223- // Shift the start position to the location of the 45224- // dependency within the require statement. 45225- startOffset, endOffset = s+i, e 45226- if startOffset <= offset && offset <= endOffset { 45227- req = r 45228- break 45229- } 45230- } 45231- // TODO(hyangah): find position for info about vulnerabilities in Go 45232- 45233- // The cursor position is not on a require statement. 45234- if req == nil { 45235- return nil, nil 45236- } 45237- 45238- // Get the vulnerability info. 45239- fromGovulncheck := true 45240- vs := snapshot.View().Vulnerabilities(fh.URI())[fh.URI()] 45241- if vs == nil && snapshot.View().Options().Vulncheck == source.ModeVulncheckImports { 45242- var err error 45243- vs, err = snapshot.ModVuln(ctx, fh.URI()) 45244- if err != nil { 45245- return nil, err 45246- } 45247- fromGovulncheck = false 45248- } 45249- affecting, nonaffecting := lookupVulns(vs, req.Mod.Path, req.Mod.Version) 45250- 45251- // Get the `go mod why` results for the given file. 45252- why, err := snapshot.ModWhy(ctx, fh) 45253- if err != nil { 45254- return nil, err 45255- } 45256- explanation, ok := why[req.Mod.Path] 45257- if !ok { 45258- return nil, nil 45259- } 45260- 45261- // Get the range to highlight for the hover. 45262- // TODO(hyangah): adjust the hover range to include the version number 45263- // to match the diagnostics' range. 45264- rng, err := pm.Mapper.OffsetRange(startOffset, endOffset) 45265- if err != nil { 45266- return nil, err 45267- } 45268- options := snapshot.View().Options() 45269- isPrivate := snapshot.View().IsGoPrivatePath(req.Mod.Path) 45270- header := formatHeader(req.Mod.Path, options) 45271- explanation = formatExplanation(explanation, req, options, isPrivate) 45272- vulns := formatVulnerabilities(req.Mod.Path, affecting, nonaffecting, options, fromGovulncheck) 45273- 45274- return &protocol.Hover{ 45275- Contents: protocol.MarkupContent{ 45276- Kind: options.PreferredContentFormat, 45277- Value: header + vulns + explanation, 45278- }, 45279- Range: rng, 45280- }, nil 45281-} 45282- 45283-func hoverOnModuleStatement(ctx context.Context, pm *source.ParsedModule, offset int, snapshot source.Snapshot, fh source.FileHandle) (*protocol.Hover, bool) { 45284- module := pm.File.Module 45285- if module == nil { 45286- return nil, false // no module stmt 45287- } 45288- if offset < module.Syntax.Start.Byte || offset > module.Syntax.End.Byte { 45289- return nil, false // cursor not in module stmt 45290- } 45291- 45292- rng, err := pm.Mapper.OffsetRange(module.Syntax.Start.Byte, module.Syntax.End.Byte) 45293- if err != nil { 45294- return nil, false 45295- } 45296- fromGovulncheck := true 45297- vs := snapshot.View().Vulnerabilities(fh.URI())[fh.URI()] 45298- 45299- if vs == nil && snapshot.View().Options().Vulncheck == source.ModeVulncheckImports { 45300- vs, err = snapshot.ModVuln(ctx, fh.URI()) 45301- if err != nil { 45302- return nil, false 45303- } 45304- fromGovulncheck = false 45305- } 45306- modpath := "stdlib" 45307- goVersion := snapshot.View().GoVersionString() 45308- affecting, nonaffecting := lookupVulns(vs, modpath, goVersion) 45309- options := snapshot.View().Options() 45310- vulns := formatVulnerabilities(modpath, affecting, nonaffecting, options, fromGovulncheck) 45311- 45312- return &protocol.Hover{ 45313- Contents: protocol.MarkupContent{ 45314- Kind: options.PreferredContentFormat, 45315- Value: vulns, 45316- }, 45317- Range: rng, 45318- }, true 45319-} 45320- 45321-func formatHeader(modpath string, options *source.Options) string { 45322- var b strings.Builder 45323- // Write the heading as an H3. 45324- b.WriteString("#### " + modpath) 45325- if options.PreferredContentFormat == protocol.Markdown { 45326- b.WriteString("\n\n") 45327- } else { 45328- b.WriteRune('\n') 45329- } 45330- return b.String() 45331-} 45332- 45333-func lookupVulns(vulns *govulncheck.Result, modpath, version string) (affecting, nonaffecting []*govulncheck.Vuln) { 45334- if vulns == nil { 45335- return nil, nil 45336- } 45337- for _, vuln := range vulns.Vulns { 45338- for _, mod := range vuln.Modules { 45339- if mod.Path != modpath { 45340- continue 45341- } 45342- // It is possible that the source code was changed since the last 45343- // govulncheck run and information in the `vulns` info is stale. 45344- // For example, imagine that a user is in the middle of updating 45345- // problematic modules detected by the govulncheck run by applying 45346- // quick fixes. Stale diagnostics can be confusing and prevent the 45347- // user from quickly locating the next module to fix. 45348- // Ideally we should rerun the analysis with the updated module 45349- // dependencies or any other code changes, but we are not yet 45350- // in the position of automatically triggering the analysis 45351- // (govulncheck can take a while). We also don't know exactly what 45352- // part of source code was changed since `vulns` was computed. 45353- // As a heuristic, we assume that a user upgrades the affecting 45354- // module to the version with the fix or the latest one, and if the 45355- // version in the require statement is equal to or higher than the 45356- // fixed version, skip the vulnerability information in the hover. 45357- // Eventually, the user has to rerun govulncheck. 45358- if mod.FixedVersion != "" && semver.IsValid(version) && semver.Compare(mod.FixedVersion, version) <= 0 { 45359- continue 45360- } 45361- if vuln.IsCalled() { 45362- affecting = append(affecting, vuln) 45363- } else { 45364- nonaffecting = append(nonaffecting, vuln) 45365- } 45366- } 45367- } 45368- sort.Slice(nonaffecting, func(i, j int) bool { return nonaffecting[i].OSV.ID < nonaffecting[j].OSV.ID }) 45369- sort.Slice(affecting, func(i, j int) bool { return affecting[i].OSV.ID < affecting[j].OSV.ID }) 45370- return affecting, nonaffecting 45371-} 45372- 45373-func formatVulnerabilities(modPath string, affecting, nonaffecting []*govulncheck.Vuln, options *source.Options, fromGovulncheck bool) string { 45374- if len(affecting) == 0 && len(nonaffecting) == 0 { 45375- return "" 45376- } 45377- 45378- // TODO(hyangah): can we use go templates to generate hover messages? 45379- // Then, we can use a different template for markdown case. 45380- useMarkdown := options.PreferredContentFormat == protocol.Markdown 45381- 45382- var b strings.Builder 45383- 45384- if len(affecting) > 0 { 45385- // TODO(hyangah): make the message more eyecatching (icon/codicon/color) 45386- if len(affecting) == 1 { 45387- b.WriteString(fmt.Sprintf("\n**WARNING:** Found %d reachable vulnerability.\n", len(affecting))) 45388- } else { 45389- b.WriteString(fmt.Sprintf("\n**WARNING:** Found %d reachable vulnerabilities.\n", len(affecting))) 45390- } 45391- } 45392- for _, v := range affecting { 45393- fix := fixedVersionInfo(v, modPath) 45394- pkgs := vulnerablePkgsInfo(v, modPath, useMarkdown) 45395- 45396- if useMarkdown { 45397- fmt.Fprintf(&b, "- [**%v**](%v) %v%v%v\n", v.OSV.ID, href(v.OSV), formatMessage(v), pkgs, fix) 45398- } else { 45399- fmt.Fprintf(&b, " - [%v] %v (%v) %v%v\n", v.OSV.ID, formatMessage(v), href(v.OSV), pkgs, fix) 45400- } 45401- } 45402- if len(nonaffecting) > 0 { 45403- if fromGovulncheck { 45404- fmt.Fprintf(&b, "\n**Note:** The project imports packages with known vulnerabilities, but does not call the vulnerable code.\n") 45405- } else { 45406- fmt.Fprintf(&b, "\n**Note:** The project imports packages with known vulnerabilities. Use `govulncheck` to check if the project uses vulnerable symbols.\n") 45407- } 45408- } 45409- for _, v := range nonaffecting { 45410- fix := fixedVersionInfo(v, modPath) 45411- pkgs := vulnerablePkgsInfo(v, modPath, useMarkdown) 45412- if useMarkdown { 45413- fmt.Fprintf(&b, "- [%v](%v) %v%v%v\n", v.OSV.ID, href(v.OSV), formatMessage(v), pkgs, fix) 45414- } else { 45415- fmt.Fprintf(&b, " - [%v] %v (%v) %v%v\n", v.OSV.ID, formatMessage(v), href(v.OSV), pkgs, fix) 45416- } 45417- } 45418- b.WriteString("\n") 45419- return b.String() 45420-} 45421- 45422-func vulnerablePkgsInfo(v *govulncheck.Vuln, modPath string, useMarkdown bool) string { 45423- var b bytes.Buffer 45424- for _, m := range v.Modules { 45425- if m.Path != modPath { 45426- continue 45427- } 45428- if c := len(m.Packages); c == 1 { 45429- b.WriteString("\n Vulnerable package is:") 45430- } else if c > 1 { 45431- b.WriteString("\n Vulnerable packages are:") 45432- } 45433- for _, pkg := range m.Packages { 45434- if useMarkdown { 45435- b.WriteString("\n * `") 45436- } else { 45437- b.WriteString("\n ") 45438- } 45439- b.WriteString(pkg.Path) 45440- if useMarkdown { 45441- b.WriteString("`") 45442- } 45443- } 45444- } 45445- if b.Len() == 0 { 45446- return "" 45447- } 45448- return b.String() 45449-} 45450-func fixedVersionInfo(v *govulncheck.Vuln, modPath string) string { 45451- fix := "\n\n **No fix is available.**" 45452- for _, m := range v.Modules { 45453- if m.Path != modPath { 45454- continue 45455- } 45456- if m.FixedVersion != "" { 45457- fix = "\n\n Fixed in " + m.FixedVersion + "." 45458- } 45459- break 45460- } 45461- return fix 45462-} 45463- 45464-func formatExplanation(text string, req *modfile.Require, options *source.Options, isPrivate bool) string { 45465- text = strings.TrimSuffix(text, "\n") 45466- splt := strings.Split(text, "\n") 45467- length := len(splt) 45468- 45469- var b strings.Builder 45470- 45471- // If the explanation is 2 lines, then it is of the form: 45472- // # golang.org/x/text/encoding 45473- // (main module does not need package golang.org/x/text/encoding) 45474- if length == 2 { 45475- b.WriteString(splt[1]) 45476- return b.String() 45477- } 45478- 45479- imp := splt[length-1] // import path 45480- reference := imp 45481- // See golang/go#36998: don't link to modules matching GOPRIVATE. 45482- if !isPrivate && options.PreferredContentFormat == protocol.Markdown { 45483- target := imp 45484- if strings.ToLower(options.LinkTarget) == "pkg.go.dev" { 45485- target = strings.Replace(target, req.Mod.Path, req.Mod.String(), 1) 45486- } 45487- reference = fmt.Sprintf("[%s](%s)", imp, source.BuildLink(options.LinkTarget, target, "")) 45488- } 45489- b.WriteString("This module is necessary because " + reference + " is imported in") 45490- 45491- // If the explanation is 3 lines, then it is of the form: 45492- // # golang.org/x/tools 45493- // modtest 45494- // golang.org/x/tools/go/packages 45495- if length == 3 { 45496- msg := fmt.Sprintf(" `%s`.", splt[1]) 45497- b.WriteString(msg) 45498- return b.String() 45499- } 45500- 45501- // If the explanation is more than 3 lines, then it is of the form: 45502- // # golang.org/x/text/language 45503- // rsc.io/quote 45504- // rsc.io/sampler 45505- // golang.org/x/text/language 45506- b.WriteString(":\n```text") 45507- dash := "" 45508- for _, imp := range splt[1 : length-1] { 45509- dash += "-" 45510- b.WriteString("\n" + dash + " " + imp) 45511- } 45512- b.WriteString("\n```") 45513- return b.String() 45514-} 45515diff -urN a/gopls/internal/lsp/mod/mod_test.go b/gopls/internal/lsp/mod/mod_test.go 45516--- a/gopls/internal/lsp/mod/mod_test.go 2000-01-01 00:00:00.000000000 -0000 45517+++ b/gopls/internal/lsp/mod/mod_test.go 1970-01-01 00:00:00.000000000 +0000 45518@@ -1,57 +0,0 @@ 45519-// Copyright 2019 The Go Authors. All rights reserved. 45520-// Use of this source code is governed by a BSD-style 45521-// license that can be found in the LICENSE file. 45522- 45523-package mod 45524- 45525-import ( 45526- "io/ioutil" 45527- "os" 45528- "path/filepath" 45529- "testing" 45530- 45531- "golang.org/x/tools/gopls/internal/lsp/cache" 45532- "golang.org/x/tools/gopls/internal/lsp/source" 45533- "golang.org/x/tools/gopls/internal/lsp/tests" 45534- "golang.org/x/tools/gopls/internal/span" 45535- "golang.org/x/tools/internal/testenv" 45536-) 45537- 45538-func TestMain(m *testing.M) { 45539- testenv.ExitIfSmallMachine() 45540- os.Exit(m.Run()) 45541-} 45542- 45543-func TestModfileRemainsUnchanged(t *testing.T) { 45544- ctx := tests.Context(t) 45545- session := cache.NewSession(ctx, cache.New(nil), nil) 45546- options := source.DefaultOptions().Clone() 45547- tests.DefaultOptions(options) 45548- options.TempModfile = true 45549- options.Env = map[string]string{"GOPACKAGESDRIVER": "off", "GOROOT": ""} 45550- 45551- // Make sure to copy the test directory to a temporary directory so we do not 45552- // modify the test code or add go.sum files when we run the tests. 45553- folder, err := tests.CopyFolderToTempDir(filepath.Join("testdata", "unchanged")) 45554- if err != nil { 45555- t.Fatal(err) 45556- } 45557- defer os.RemoveAll(folder) 45558- 45559- before, err := ioutil.ReadFile(filepath.Join(folder, "go.mod")) 45560- if err != nil { 45561- t.Fatal(err) 45562- } 45563- _, _, release, err := session.NewView(ctx, "diagnostics_test", span.URIFromPath(folder), options) 45564- if err != nil { 45565- t.Fatal(err) 45566- } 45567- release() 45568- after, err := ioutil.ReadFile(filepath.Join(folder, "go.mod")) 45569- if err != nil { 45570- t.Fatal(err) 45571- } 45572- if string(before) != string(after) { 45573- t.Errorf("the real go.mod file was changed even when tempModfile=true") 45574- } 45575-} 45576diff -urN a/gopls/internal/lsp/mod/testdata/unchanged/go.mod b/gopls/internal/lsp/mod/testdata/unchanged/go.mod 45577--- a/gopls/internal/lsp/mod/testdata/unchanged/go.mod 2000-01-01 00:00:00.000000000 -0000 45578+++ b/gopls/internal/lsp/mod/testdata/unchanged/go.mod 1970-01-01 00:00:00.000000000 +0000 45579@@ -1 +0,0 @@ 45580-module unchanged 45581diff -urN a/gopls/internal/lsp/mod/testdata/unchanged/main.go b/gopls/internal/lsp/mod/testdata/unchanged/main.go 45582--- a/gopls/internal/lsp/mod/testdata/unchanged/main.go 2000-01-01 00:00:00.000000000 -0000 45583+++ b/gopls/internal/lsp/mod/testdata/unchanged/main.go 1970-01-01 00:00:00.000000000 +0000 45584@@ -1,6 +0,0 @@ 45585-// Package unchanged does something 45586-package unchanged 45587- 45588-func Yo() { 45589- println("yo") 45590-} 45591diff -urN a/gopls/internal/lsp/progress/progress.go b/gopls/internal/lsp/progress/progress.go 45592--- a/gopls/internal/lsp/progress/progress.go 2000-01-01 00:00:00.000000000 -0000 45593+++ b/gopls/internal/lsp/progress/progress.go 1970-01-01 00:00:00.000000000 +0000 45594@@ -1,271 +0,0 @@ 45595-// Copyright 2020 The Go Authors. All rights reserved. 45596-// Use of this source code is governed by a BSD-style 45597-// license that can be found in the LICENSE file. 45598- 45599-package progress 45600- 45601-import ( 45602- "context" 45603- "fmt" 45604- "math/rand" 45605- "strconv" 45606- "strings" 45607- "sync" 45608- 45609- "golang.org/x/tools/gopls/internal/lsp/protocol" 45610- "golang.org/x/tools/internal/event" 45611- "golang.org/x/tools/internal/event/tag" 45612- "golang.org/x/tools/internal/xcontext" 45613-) 45614- 45615-type Tracker struct { 45616- client protocol.Client 45617- supportsWorkDoneProgress bool 45618- 45619- mu sync.Mutex 45620- inProgress map[protocol.ProgressToken]*WorkDone 45621-} 45622- 45623-func NewTracker(client protocol.Client) *Tracker { 45624- return &Tracker{ 45625- client: client, 45626- inProgress: make(map[protocol.ProgressToken]*WorkDone), 45627- } 45628-} 45629- 45630-func (tracker *Tracker) SetSupportsWorkDoneProgress(b bool) { 45631- tracker.supportsWorkDoneProgress = b 45632-} 45633- 45634-// Start notifies the client of work being done on the server. It uses either 45635-// ShowMessage RPCs or $/progress messages, depending on the capabilities of 45636-// the client. The returned WorkDone handle may be used to report incremental 45637-// progress, and to report work completion. In particular, it is an error to 45638-// call start and not call end(...) on the returned WorkDone handle. 45639-// 45640-// If token is empty, a token will be randomly generated. 45641-// 45642-// The progress item is considered cancellable if the given cancel func is 45643-// non-nil. In this case, cancel is called when the work done 45644-// 45645-// Example: 45646-// 45647-// func Generate(ctx) (err error) { 45648-// ctx, cancel := context.WithCancel(ctx) 45649-// defer cancel() 45650-// work := s.progress.start(ctx, "generate", "running go generate", cancel) 45651-// defer func() { 45652-// if err != nil { 45653-// work.end(ctx, fmt.Sprintf("generate failed: %v", err)) 45654-// } else { 45655-// work.end(ctx, "done") 45656-// } 45657-// }() 45658-// // Do the work... 45659-// } 45660-func (t *Tracker) Start(ctx context.Context, title, message string, token protocol.ProgressToken, cancel func()) *WorkDone { 45661- ctx = xcontext.Detach(ctx) // progress messages should not be cancelled 45662- wd := &WorkDone{ 45663- client: t.client, 45664- token: token, 45665- cancel: cancel, 45666- } 45667- if !t.supportsWorkDoneProgress { 45668- // Previous iterations of this fallback attempted to retain cancellation 45669- // support by using ShowMessageCommand with a 'Cancel' button, but this is 45670- // not ideal as the 'Cancel' dialog stays open even after the command 45671- // completes. 45672- // 45673- // Just show a simple message. Clients can implement workDone progress 45674- // reporting to get cancellation support. 45675- if err := wd.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 45676- Type: protocol.Log, 45677- Message: message, 45678- }); err != nil { 45679- event.Error(ctx, "showing start message for "+title, err) 45680- } 45681- return wd 45682- } 45683- if wd.token == nil { 45684- token = strconv.FormatInt(rand.Int63(), 10) 45685- err := wd.client.WorkDoneProgressCreate(ctx, &protocol.WorkDoneProgressCreateParams{ 45686- Token: token, 45687- }) 45688- if err != nil { 45689- wd.err = err 45690- event.Error(ctx, "starting work for "+title, err) 45691- return wd 45692- } 45693- wd.token = token 45694- } 45695- // At this point we have a token that the client knows about. Store the token 45696- // before starting work. 45697- t.mu.Lock() 45698- t.inProgress[wd.token] = wd 45699- t.mu.Unlock() 45700- wd.cleanup = func() { 45701- t.mu.Lock() 45702- delete(t.inProgress, token) 45703- t.mu.Unlock() 45704- } 45705- err := wd.client.Progress(ctx, &protocol.ProgressParams{ 45706- Token: wd.token, 45707- Value: &protocol.WorkDoneProgressBegin{ 45708- Kind: "begin", 45709- Cancellable: wd.cancel != nil, 45710- Message: message, 45711- Title: title, 45712- }, 45713- }) 45714- if err != nil { 45715- event.Error(ctx, "progress begin", err) 45716- } 45717- return wd 45718-} 45719- 45720-func (t *Tracker) Cancel(token protocol.ProgressToken) error { 45721- t.mu.Lock() 45722- defer t.mu.Unlock() 45723- wd, ok := t.inProgress[token] 45724- if !ok { 45725- return fmt.Errorf("token %q not found in progress", token) 45726- } 45727- if wd.cancel == nil { 45728- return fmt.Errorf("work %q is not cancellable", token) 45729- } 45730- wd.doCancel() 45731- return nil 45732-} 45733- 45734-// WorkDone represents a unit of work that is reported to the client via the 45735-// progress API. 45736-type WorkDone struct { 45737- client protocol.Client 45738- // If token is nil, this workDone object uses the ShowMessage API, rather 45739- // than $/progress. 45740- token protocol.ProgressToken 45741- // err is set if progress reporting is broken for some reason (for example, 45742- // if there was an initial error creating a token). 45743- err error 45744- 45745- cancelMu sync.Mutex 45746- cancelled bool 45747- cancel func() 45748- 45749- cleanup func() 45750-} 45751- 45752-func (wd *WorkDone) Token() protocol.ProgressToken { 45753- return wd.token 45754-} 45755- 45756-func (wd *WorkDone) doCancel() { 45757- wd.cancelMu.Lock() 45758- defer wd.cancelMu.Unlock() 45759- if !wd.cancelled { 45760- wd.cancel() 45761- } 45762-} 45763- 45764-// Report reports an update on WorkDone report back to the client. 45765-func (wd *WorkDone) Report(ctx context.Context, message string, percentage float64) { 45766- ctx = xcontext.Detach(ctx) // progress messages should not be cancelled 45767- if wd == nil { 45768- return 45769- } 45770- wd.cancelMu.Lock() 45771- cancelled := wd.cancelled 45772- wd.cancelMu.Unlock() 45773- if cancelled { 45774- return 45775- } 45776- if wd.err != nil || wd.token == nil { 45777- // Not using the workDone API, so we do nothing. It would be far too spammy 45778- // to send incremental messages. 45779- return 45780- } 45781- message = strings.TrimSuffix(message, "\n") 45782- err := wd.client.Progress(ctx, &protocol.ProgressParams{ 45783- Token: wd.token, 45784- Value: &protocol.WorkDoneProgressReport{ 45785- Kind: "report", 45786- // Note that in the LSP spec, the value of Cancellable may be changed to 45787- // control whether the cancel button in the UI is enabled. Since we don't 45788- // yet use this feature, the value is kept constant here. 45789- Cancellable: wd.cancel != nil, 45790- Message: message, 45791- Percentage: uint32(percentage), 45792- }, 45793- }) 45794- if err != nil { 45795- event.Error(ctx, "reporting progress", err) 45796- } 45797-} 45798- 45799-// End reports a workdone completion back to the client. 45800-func (wd *WorkDone) End(ctx context.Context, message string) { 45801- ctx = xcontext.Detach(ctx) // progress messages should not be cancelled 45802- if wd == nil { 45803- return 45804- } 45805- var err error 45806- switch { 45807- case wd.err != nil: 45808- // There is a prior error. 45809- case wd.token == nil: 45810- // We're falling back to message-based reporting. 45811- err = wd.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 45812- Type: protocol.Info, 45813- Message: message, 45814- }) 45815- default: 45816- err = wd.client.Progress(ctx, &protocol.ProgressParams{ 45817- Token: wd.token, 45818- Value: &protocol.WorkDoneProgressEnd{ 45819- Kind: "end", 45820- Message: message, 45821- }, 45822- }) 45823- } 45824- if err != nil { 45825- event.Error(ctx, "ending work", err) 45826- } 45827- if wd.cleanup != nil { 45828- wd.cleanup() 45829- } 45830-} 45831- 45832-// EventWriter writes every incoming []byte to 45833-// event.Print with the operation=generate tag 45834-// to distinguish its logs from others. 45835-type EventWriter struct { 45836- ctx context.Context 45837- operation string 45838-} 45839- 45840-func NewEventWriter(ctx context.Context, operation string) *EventWriter { 45841- return &EventWriter{ctx: ctx, operation: operation} 45842-} 45843- 45844-func (ew *EventWriter) Write(p []byte) (n int, err error) { 45845- event.Log(ew.ctx, string(p), tag.Operation.Of(ew.operation)) 45846- return len(p), nil 45847-} 45848- 45849-// WorkDoneWriter wraps a workDone handle to provide a Writer interface, 45850-// so that workDone reporting can more easily be hooked into commands. 45851-type WorkDoneWriter struct { 45852- // In order to implement the io.Writer interface, we must close over ctx. 45853- ctx context.Context 45854- wd *WorkDone 45855-} 45856- 45857-func NewWorkDoneWriter(ctx context.Context, wd *WorkDone) *WorkDoneWriter { 45858- return &WorkDoneWriter{ctx: ctx, wd: wd} 45859-} 45860- 45861-func (wdw *WorkDoneWriter) Write(p []byte) (n int, err error) { 45862- wdw.wd.Report(wdw.ctx, string(p), 0) 45863- // Don't fail just because of a failure to report progress. 45864- return len(p), nil 45865-} 45866diff -urN a/gopls/internal/lsp/progress/progress_test.go b/gopls/internal/lsp/progress/progress_test.go 45867--- a/gopls/internal/lsp/progress/progress_test.go 2000-01-01 00:00:00.000000000 -0000 45868+++ b/gopls/internal/lsp/progress/progress_test.go 1970-01-01 00:00:00.000000000 +0000 45869@@ -1,161 +0,0 @@ 45870-// Copyright 2020 The Go Authors. All rights reserved. 45871-// Use of this source code is governed by a BSD-style 45872-// license that can be found in the LICENSE file. 45873- 45874-package progress 45875- 45876-import ( 45877- "context" 45878- "fmt" 45879- "sync" 45880- "testing" 45881- 45882- "golang.org/x/tools/gopls/internal/lsp/protocol" 45883-) 45884- 45885-type fakeClient struct { 45886- protocol.Client 45887- 45888- token protocol.ProgressToken 45889- 45890- mu sync.Mutex 45891- created, begun, reported, messages, ended int 45892-} 45893- 45894-func (c *fakeClient) checkToken(token protocol.ProgressToken) { 45895- if token == nil { 45896- panic("nil token in progress message") 45897- } 45898- if c.token != nil && c.token != token { 45899- panic(fmt.Errorf("invalid token in progress message: got %v, want %v", token, c.token)) 45900- } 45901-} 45902- 45903-func (c *fakeClient) WorkDoneProgressCreate(ctx context.Context, params *protocol.WorkDoneProgressCreateParams) error { 45904- c.mu.Lock() 45905- defer c.mu.Unlock() 45906- c.checkToken(params.Token) 45907- c.created++ 45908- return nil 45909-} 45910- 45911-func (c *fakeClient) Progress(ctx context.Context, params *protocol.ProgressParams) error { 45912- c.mu.Lock() 45913- defer c.mu.Unlock() 45914- c.checkToken(params.Token) 45915- switch params.Value.(type) { 45916- case *protocol.WorkDoneProgressBegin: 45917- c.begun++ 45918- case *protocol.WorkDoneProgressReport: 45919- c.reported++ 45920- case *protocol.WorkDoneProgressEnd: 45921- c.ended++ 45922- default: 45923- panic(fmt.Errorf("unknown progress value %T", params.Value)) 45924- } 45925- return nil 45926-} 45927- 45928-func (c *fakeClient) ShowMessage(context.Context, *protocol.ShowMessageParams) error { 45929- c.mu.Lock() 45930- defer c.mu.Unlock() 45931- c.messages++ 45932- return nil 45933-} 45934- 45935-func setup(token protocol.ProgressToken) (context.Context, *Tracker, *fakeClient) { 45936- c := &fakeClient{} 45937- tracker := NewTracker(c) 45938- tracker.SetSupportsWorkDoneProgress(true) 45939- return context.Background(), tracker, c 45940-} 45941- 45942-func TestProgressTracker_Reporting(t *testing.T) { 45943- for _, test := range []struct { 45944- name string 45945- supported bool 45946- token protocol.ProgressToken 45947- wantReported, wantCreated, wantBegun, wantEnded int 45948- wantMessages int 45949- }{ 45950- { 45951- name: "unsupported", 45952- wantMessages: 2, 45953- }, 45954- { 45955- name: "random token", 45956- supported: true, 45957- wantCreated: 1, 45958- wantBegun: 1, 45959- wantReported: 1, 45960- wantEnded: 1, 45961- }, 45962- { 45963- name: "string token", 45964- supported: true, 45965- token: "token", 45966- wantBegun: 1, 45967- wantReported: 1, 45968- wantEnded: 1, 45969- }, 45970- { 45971- name: "numeric token", 45972- supported: true, 45973- token: 1, 45974- wantReported: 1, 45975- wantBegun: 1, 45976- wantEnded: 1, 45977- }, 45978- } { 45979- test := test 45980- t.Run(test.name, func(t *testing.T) { 45981- ctx, tracker, client := setup(test.token) 45982- ctx, cancel := context.WithCancel(ctx) 45983- defer cancel() 45984- tracker.supportsWorkDoneProgress = test.supported 45985- work := tracker.Start(ctx, "work", "message", test.token, nil) 45986- client.mu.Lock() 45987- gotCreated, gotBegun := client.created, client.begun 45988- client.mu.Unlock() 45989- if gotCreated != test.wantCreated { 45990- t.Errorf("got %d created tokens, want %d", gotCreated, test.wantCreated) 45991- } 45992- if gotBegun != test.wantBegun { 45993- t.Errorf("got %d work begun, want %d", gotBegun, test.wantBegun) 45994- } 45995- // Ignore errors: this is just testing the reporting behavior. 45996- work.Report(ctx, "report", 50) 45997- client.mu.Lock() 45998- gotReported := client.reported 45999- client.mu.Unlock() 46000- if gotReported != test.wantReported { 46001- t.Errorf("got %d progress reports, want %d", gotReported, test.wantCreated) 46002- } 46003- work.End(ctx, "done") 46004- client.mu.Lock() 46005- gotEnded, gotMessages := client.ended, client.messages 46006- client.mu.Unlock() 46007- if gotEnded != test.wantEnded { 46008- t.Errorf("got %d ended reports, want %d", gotEnded, test.wantEnded) 46009- } 46010- if gotMessages != test.wantMessages { 46011- t.Errorf("got %d messages, want %d", gotMessages, test.wantMessages) 46012- } 46013- }) 46014- } 46015-} 46016- 46017-func TestProgressTracker_Cancellation(t *testing.T) { 46018- for _, token := range []protocol.ProgressToken{nil, 1, "a"} { 46019- ctx, tracker, _ := setup(token) 46020- var canceled bool 46021- cancel := func() { canceled = true } 46022- work := tracker.Start(ctx, "work", "message", token, cancel) 46023- if err := tracker.Cancel(work.Token()); err != nil { 46024- t.Fatal(err) 46025- } 46026- if !canceled { 46027- t.Errorf("tracker.cancel(...): cancel not called") 46028- } 46029- } 46030-} 46031diff -urN a/gopls/internal/lsp/protocol/codeactionkind.go b/gopls/internal/lsp/protocol/codeactionkind.go 46032--- a/gopls/internal/lsp/protocol/codeactionkind.go 2000-01-01 00:00:00.000000000 -0000 46033+++ b/gopls/internal/lsp/protocol/codeactionkind.go 1970-01-01 00:00:00.000000000 +0000 46034@@ -1,11 +0,0 @@ 46035-// Copyright 2020 The Go Authors. All rights reserved. 46036-// Use of this source code is governed by a BSD-style 46037-// license that can be found in the LICENSE file. 46038- 46039-package protocol 46040- 46041-// Custom code actions that aren't explicitly stated in LSP 46042-const ( 46043- GoTest CodeActionKind = "goTest" 46044- // TODO: Add GoGenerate, RegenerateCgo etc. 46045-) 46046diff -urN a/gopls/internal/lsp/protocol/context.go b/gopls/internal/lsp/protocol/context.go 46047--- a/gopls/internal/lsp/protocol/context.go 2000-01-01 00:00:00.000000000 -0000 46048+++ b/gopls/internal/lsp/protocol/context.go 1970-01-01 00:00:00.000000000 +0000 46049@@ -1,43 +0,0 @@ 46050-// Copyright 2019 The Go Authors. All rights reserved. 46051-// Use of this source code is governed by a BSD-style 46052-// license that can be found in the LICENSE file. 46053- 46054-package protocol 46055- 46056-import ( 46057- "bytes" 46058- "context" 46059- 46060- "golang.org/x/tools/internal/event" 46061- "golang.org/x/tools/internal/event/core" 46062- "golang.org/x/tools/internal/event/export" 46063- "golang.org/x/tools/internal/event/label" 46064- "golang.org/x/tools/internal/xcontext" 46065-) 46066- 46067-type contextKey int 46068- 46069-const ( 46070- clientKey = contextKey(iota) 46071-) 46072- 46073-func WithClient(ctx context.Context, client Client) context.Context { 46074- return context.WithValue(ctx, clientKey, client) 46075-} 46076- 46077-func LogEvent(ctx context.Context, ev core.Event, lm label.Map, mt MessageType) context.Context { 46078- client, ok := ctx.Value(clientKey).(Client) 46079- if !ok { 46080- return ctx 46081- } 46082- buf := &bytes.Buffer{} 46083- p := export.Printer{} 46084- p.WriteEvent(buf, ev, lm) 46085- msg := &LogMessageParams{Type: mt, Message: buf.String()} 46086- // Handle messages generated via event.Error, which won't have a level Label. 46087- if event.IsError(ev) { 46088- msg.Type = Error 46089- } 46090- go client.LogMessage(xcontext.Detach(ctx), msg) 46091- return ctx 46092-} 46093diff -urN a/gopls/internal/lsp/protocol/doc.go b/gopls/internal/lsp/protocol/doc.go 46094--- a/gopls/internal/lsp/protocol/doc.go 2000-01-01 00:00:00.000000000 -0000 46095+++ b/gopls/internal/lsp/protocol/doc.go 1970-01-01 00:00:00.000000000 +0000 46096@@ -1,18 +0,0 @@ 46097-// Copyright 2018 The Go Authors. All rights reserved. 46098-// Use of this source code is governed by a BSD-style 46099-// license that can be found in the LICENSE file. 46100- 46101-//go:generate go run ./generate 46102- 46103-// Package protocol contains the structs that map directly to the 46104-// request and response messages of the Language Server Protocol. 46105-// 46106-// It is a literal transcription, with unmodified comments, and only the changes 46107-// required to make it go code. 46108-// Names are uppercased to export them. 46109-// All fields have JSON tags added to correct the names. 46110-// Fields marked with a ? are also marked as "omitempty" 46111-// Fields that are "|| null" are made pointers 46112-// Fields that are string or number are left as string 46113-// Fields that are type "number" are made float64 46114-package protocol 46115diff -urN a/gopls/internal/lsp/protocol/enums.go b/gopls/internal/lsp/protocol/enums.go 46116--- a/gopls/internal/lsp/protocol/enums.go 2000-01-01 00:00:00.000000000 -0000 46117+++ b/gopls/internal/lsp/protocol/enums.go 1970-01-01 00:00:00.000000000 +0000 46118@@ -1,231 +0,0 @@ 46119-// Copyright 2018 The Go Authors. All rights reserved. 46120-// Use of this source code is governed by a BSD-style 46121-// license that can be found in the LICENSE file. 46122- 46123-package protocol 46124- 46125-import ( 46126- "fmt" 46127-) 46128- 46129-var ( 46130- namesTextDocumentSyncKind [int(Incremental) + 1]string 46131- namesMessageType [int(Log) + 1]string 46132- namesFileChangeType [int(Deleted) + 1]string 46133- namesWatchKind [int(WatchDelete) + 1]string 46134- namesCompletionTriggerKind [int(TriggerForIncompleteCompletions) + 1]string 46135- namesDiagnosticSeverity [int(SeverityHint) + 1]string 46136- namesDiagnosticTag [int(Unnecessary) + 1]string 46137- namesCompletionItemKind [int(TypeParameterCompletion) + 1]string 46138- namesInsertTextFormat [int(SnippetTextFormat) + 1]string 46139- namesDocumentHighlightKind [int(Write) + 1]string 46140- namesSymbolKind [int(TypeParameter) + 1]string 46141- namesTextDocumentSaveReason [int(FocusOut) + 1]string 46142-) 46143- 46144-func init() { 46145- namesTextDocumentSyncKind[int(None)] = "None" 46146- namesTextDocumentSyncKind[int(Full)] = "Full" 46147- namesTextDocumentSyncKind[int(Incremental)] = "Incremental" 46148- 46149- namesMessageType[int(Error)] = "Error" 46150- namesMessageType[int(Warning)] = "Warning" 46151- namesMessageType[int(Info)] = "Info" 46152- namesMessageType[int(Log)] = "Log" 46153- 46154- namesFileChangeType[int(Created)] = "Created" 46155- namesFileChangeType[int(Changed)] = "Changed" 46156- namesFileChangeType[int(Deleted)] = "Deleted" 46157- 46158- namesWatchKind[int(WatchCreate)] = "WatchCreate" 46159- namesWatchKind[int(WatchChange)] = "WatchChange" 46160- namesWatchKind[int(WatchDelete)] = "WatchDelete" 46161- 46162- namesCompletionTriggerKind[int(Invoked)] = "Invoked" 46163- namesCompletionTriggerKind[int(TriggerCharacter)] = "TriggerCharacter" 46164- namesCompletionTriggerKind[int(TriggerForIncompleteCompletions)] = "TriggerForIncompleteCompletions" 46165- 46166- namesDiagnosticSeverity[int(SeverityError)] = "Error" 46167- namesDiagnosticSeverity[int(SeverityWarning)] = "Warning" 46168- namesDiagnosticSeverity[int(SeverityInformation)] = "Information" 46169- namesDiagnosticSeverity[int(SeverityHint)] = "Hint" 46170- 46171- namesDiagnosticTag[int(Unnecessary)] = "Unnecessary" 46172- 46173- namesCompletionItemKind[int(TextCompletion)] = "text" 46174- namesCompletionItemKind[int(MethodCompletion)] = "method" 46175- namesCompletionItemKind[int(FunctionCompletion)] = "func" 46176- namesCompletionItemKind[int(ConstructorCompletion)] = "constructor" 46177- namesCompletionItemKind[int(FieldCompletion)] = "field" 46178- namesCompletionItemKind[int(VariableCompletion)] = "var" 46179- namesCompletionItemKind[int(ClassCompletion)] = "type" 46180- namesCompletionItemKind[int(InterfaceCompletion)] = "interface" 46181- namesCompletionItemKind[int(ModuleCompletion)] = "package" 46182- namesCompletionItemKind[int(PropertyCompletion)] = "property" 46183- namesCompletionItemKind[int(UnitCompletion)] = "unit" 46184- namesCompletionItemKind[int(ValueCompletion)] = "value" 46185- namesCompletionItemKind[int(EnumCompletion)] = "enum" 46186- namesCompletionItemKind[int(KeywordCompletion)] = "keyword" 46187- namesCompletionItemKind[int(SnippetCompletion)] = "snippet" 46188- namesCompletionItemKind[int(ColorCompletion)] = "color" 46189- namesCompletionItemKind[int(FileCompletion)] = "file" 46190- namesCompletionItemKind[int(ReferenceCompletion)] = "reference" 46191- namesCompletionItemKind[int(FolderCompletion)] = "folder" 46192- namesCompletionItemKind[int(EnumMemberCompletion)] = "enumMember" 46193- namesCompletionItemKind[int(ConstantCompletion)] = "const" 46194- namesCompletionItemKind[int(StructCompletion)] = "struct" 46195- namesCompletionItemKind[int(EventCompletion)] = "event" 46196- namesCompletionItemKind[int(OperatorCompletion)] = "operator" 46197- namesCompletionItemKind[int(TypeParameterCompletion)] = "typeParam" 46198- 46199- namesInsertTextFormat[int(PlainTextTextFormat)] = "PlainText" 46200- namesInsertTextFormat[int(SnippetTextFormat)] = "Snippet" 46201- 46202- namesDocumentHighlightKind[int(Text)] = "Text" 46203- namesDocumentHighlightKind[int(Read)] = "Read" 46204- namesDocumentHighlightKind[int(Write)] = "Write" 46205- 46206- namesSymbolKind[int(File)] = "File" 46207- namesSymbolKind[int(Module)] = "Module" 46208- namesSymbolKind[int(Namespace)] = "Namespace" 46209- namesSymbolKind[int(Package)] = "Package" 46210- namesSymbolKind[int(Class)] = "Class" 46211- namesSymbolKind[int(Method)] = "Method" 46212- namesSymbolKind[int(Property)] = "Property" 46213- namesSymbolKind[int(Field)] = "Field" 46214- namesSymbolKind[int(Constructor)] = "Constructor" 46215- namesSymbolKind[int(Enum)] = "Enum" 46216- namesSymbolKind[int(Interface)] = "Interface" 46217- namesSymbolKind[int(Function)] = "Function" 46218- namesSymbolKind[int(Variable)] = "Variable" 46219- namesSymbolKind[int(Constant)] = "Constant" 46220- namesSymbolKind[int(String)] = "String" 46221- namesSymbolKind[int(Number)] = "Number" 46222- namesSymbolKind[int(Boolean)] = "Boolean" 46223- namesSymbolKind[int(Array)] = "Array" 46224- namesSymbolKind[int(Object)] = "Object" 46225- namesSymbolKind[int(Key)] = "Key" 46226- namesSymbolKind[int(Null)] = "Null" 46227- namesSymbolKind[int(EnumMember)] = "EnumMember" 46228- namesSymbolKind[int(Struct)] = "Struct" 46229- namesSymbolKind[int(Event)] = "Event" 46230- namesSymbolKind[int(Operator)] = "Operator" 46231- namesSymbolKind[int(TypeParameter)] = "TypeParameter" 46232- 46233- namesTextDocumentSaveReason[int(Manual)] = "Manual" 46234- namesTextDocumentSaveReason[int(AfterDelay)] = "AfterDelay" 46235- namesTextDocumentSaveReason[int(FocusOut)] = "FocusOut" 46236-} 46237- 46238-func formatEnum(f fmt.State, c rune, i int, names []string, unknown string) { 46239- s := "" 46240- if i >= 0 && i < len(names) { 46241- s = names[i] 46242- } 46243- if s != "" { 46244- fmt.Fprint(f, s) 46245- } else { 46246- fmt.Fprintf(f, "%s(%d)", unknown, i) 46247- } 46248-} 46249- 46250-func parseEnum(s string, names []string) int { 46251- for i, name := range names { 46252- if s == name { 46253- return i 46254- } 46255- } 46256- return 0 46257-} 46258- 46259-func (e TextDocumentSyncKind) Format(f fmt.State, c rune) { 46260- formatEnum(f, c, int(e), namesTextDocumentSyncKind[:], "TextDocumentSyncKind") 46261-} 46262- 46263-func ParseTextDocumentSyncKind(s string) TextDocumentSyncKind { 46264- return TextDocumentSyncKind(parseEnum(s, namesTextDocumentSyncKind[:])) 46265-} 46266- 46267-func (e MessageType) Format(f fmt.State, c rune) { 46268- formatEnum(f, c, int(e), namesMessageType[:], "MessageType") 46269-} 46270- 46271-func ParseMessageType(s string) MessageType { 46272- return MessageType(parseEnum(s, namesMessageType[:])) 46273-} 46274- 46275-func (e FileChangeType) Format(f fmt.State, c rune) { 46276- formatEnum(f, c, int(e), namesFileChangeType[:], "FileChangeType") 46277-} 46278- 46279-func ParseFileChangeType(s string) FileChangeType { 46280- return FileChangeType(parseEnum(s, namesFileChangeType[:])) 46281-} 46282- 46283-func ParseWatchKind(s string) WatchKind { 46284- return WatchKind(parseEnum(s, namesWatchKind[:])) 46285-} 46286- 46287-func (e CompletionTriggerKind) Format(f fmt.State, c rune) { 46288- formatEnum(f, c, int(e), namesCompletionTriggerKind[:], "CompletionTriggerKind") 46289-} 46290- 46291-func ParseCompletionTriggerKind(s string) CompletionTriggerKind { 46292- return CompletionTriggerKind(parseEnum(s, namesCompletionTriggerKind[:])) 46293-} 46294- 46295-func (e DiagnosticSeverity) Format(f fmt.State, c rune) { 46296- formatEnum(f, c, int(e), namesDiagnosticSeverity[:], "DiagnosticSeverity") 46297-} 46298- 46299-func ParseDiagnosticSeverity(s string) DiagnosticSeverity { 46300- return DiagnosticSeverity(parseEnum(s, namesDiagnosticSeverity[:])) 46301-} 46302- 46303-func (e DiagnosticTag) Format(f fmt.State, c rune) { 46304- formatEnum(f, c, int(e), namesDiagnosticTag[:], "DiagnosticTag") 46305-} 46306- 46307-func ParseDiagnosticTag(s string) DiagnosticTag { 46308- return DiagnosticTag(parseEnum(s, namesDiagnosticTag[:])) 46309-} 46310- 46311-func (e CompletionItemKind) Format(f fmt.State, c rune) { 46312- formatEnum(f, c, int(e), namesCompletionItemKind[:], "CompletionItemKind") 46313-} 46314- 46315-func ParseCompletionItemKind(s string) CompletionItemKind { 46316- return CompletionItemKind(parseEnum(s, namesCompletionItemKind[:])) 46317-} 46318- 46319-func (e InsertTextFormat) Format(f fmt.State, c rune) { 46320- formatEnum(f, c, int(e), namesInsertTextFormat[:], "InsertTextFormat") 46321-} 46322- 46323-func ParseInsertTextFormat(s string) InsertTextFormat { 46324- return InsertTextFormat(parseEnum(s, namesInsertTextFormat[:])) 46325-} 46326- 46327-func (e DocumentHighlightKind) Format(f fmt.State, c rune) { 46328- formatEnum(f, c, int(e), namesDocumentHighlightKind[:], "DocumentHighlightKind") 46329-} 46330- 46331-func ParseDocumentHighlightKind(s string) DocumentHighlightKind { 46332- return DocumentHighlightKind(parseEnum(s, namesDocumentHighlightKind[:])) 46333-} 46334- 46335-func (e SymbolKind) Format(f fmt.State, c rune) { 46336- formatEnum(f, c, int(e), namesSymbolKind[:], "SymbolKind") 46337-} 46338- 46339-func ParseSymbolKind(s string) SymbolKind { 46340- return SymbolKind(parseEnum(s, namesSymbolKind[:])) 46341-} 46342- 46343-func (e TextDocumentSaveReason) Format(f fmt.State, c rune) { 46344- formatEnum(f, c, int(e), namesTextDocumentSaveReason[:], "TextDocumentSaveReason") 46345-} 46346- 46347-func ParseTextDocumentSaveReason(s string) TextDocumentSaveReason { 46348- return TextDocumentSaveReason(parseEnum(s, namesTextDocumentSaveReason[:])) 46349-} 46350diff -urN a/gopls/internal/lsp/protocol/generate/generate.go b/gopls/internal/lsp/protocol/generate/generate.go 46351--- a/gopls/internal/lsp/protocol/generate/generate.go 2000-01-01 00:00:00.000000000 -0000 46352+++ b/gopls/internal/lsp/protocol/generate/generate.go 1970-01-01 00:00:00.000000000 +0000 46353@@ -1,121 +0,0 @@ 46354-// Copyright 2022 The Go Authors. All rights reserved. 46355-// Use of this source code is governed by a BSD-style 46356-// license that can be found in the LICENSE file. 46357- 46358-//go:build go1.19 46359-// +build go1.19 46360- 46361-package main 46362- 46363-import ( 46364- "bytes" 46365- "fmt" 46366- "log" 46367- "strings" 46368-) 46369- 46370-// a newType is a type that needs a name and a definition 46371-// These are the various types that the json specification doesn't name 46372-type newType struct { 46373- name string 46374- properties Properties // for struct/literal types 46375- items []*Type // for other types ("and", "tuple") 46376- line int 46377- kind string // Or, And, Tuple, Lit, Map 46378- typ *Type 46379-} 46380- 46381-func generateDoc(out *bytes.Buffer, doc string) { 46382- if doc == "" { 46383- return 46384- } 46385- 46386- if !strings.Contains(doc, "\n") { 46387- fmt.Fprintf(out, "// %s\n", doc) 46388- return 46389- } 46390- var list bool 46391- for _, line := range strings.Split(doc, "\n") { 46392- // Lists in metaModel.json start with a dash. 46393- // To make a go doc list they have to be preceded 46394- // by a blank line, and indented. 46395- // (see type TextDccumentFilter in protocol.go) 46396- if len(line) > 0 && line[0] == '-' { 46397- if !list { 46398- list = true 46399- fmt.Fprintf(out, "//\n") 46400- } 46401- fmt.Fprintf(out, "// %s\n", line) 46402- } else { 46403- if len(line) == 0 { 46404- list = false 46405- } 46406- fmt.Fprintf(out, "// %s\n", line) 46407- } 46408- } 46409-} 46410- 46411-// decide if a property is optional, and if it needs a * 46412-// return ",omitempty" if it is optional, and "*" if it needs a pointer 46413-func propStar(name string, t NameType, gotype string) (string, string) { 46414- var opt, star string 46415- if t.Optional { 46416- star = "*" 46417- opt = ",omitempty" 46418- } 46419- if strings.HasPrefix(gotype, "[]") || strings.HasPrefix(gotype, "map[") { 46420- star = "" // passed by reference, so no need for * 46421- } else { 46422- switch gotype { 46423- case "bool", "uint32", "int32", "string", "interface{}": 46424- star = "" // gopls compatibility if t.Optional 46425- } 46426- } 46427- ostar, oopt := star, opt 46428- if newStar, ok := goplsStar[prop{name, t.Name}]; ok { 46429- switch newStar { 46430- case nothing: 46431- star, opt = "", "" 46432- case wantStar: 46433- star, opt = "*", "" 46434- case wantOpt: 46435- star, opt = "", ",omitempty" 46436- case wantOptStar: 46437- star, opt = "*", ",omitempty" 46438- } 46439- if star == ostar && opt == oopt { // no change 46440- log.Printf("goplsStar[ {%q, %q} ](%d) useless %s/%s %s/%s", name, t.Name, t.Line, ostar, star, oopt, opt) 46441- } 46442- usedGoplsStar[prop{name, t.Name}] = true 46443- } 46444- 46445- return opt, star 46446-} 46447- 46448-func goName(s string) string { 46449- // Go naming conventions 46450- if strings.HasSuffix(s, "Id") { 46451- s = s[:len(s)-len("Id")] + "ID" 46452- } else if strings.HasSuffix(s, "Uri") { 46453- s = s[:len(s)-3] + "URI" 46454- } else if s == "uri" { 46455- s = "URI" 46456- } else if s == "id" { 46457- s = "ID" 46458- } 46459- 46460- // renames for temporary GOPLS compatibility 46461- if news := goplsType[s]; news != "" { 46462- usedGoplsType[s] = true 46463- s = news 46464- } 46465- // Names beginning _ are not exported 46466- if strings.HasPrefix(s, "_") { 46467- s = strings.Replace(s, "_", "X", 1) 46468- } 46469- if s != "string" { // base types are unchanged (textDocuemnt/diagnostic) 46470- // Title is deprecated, but a) s is only one word, b) replacement is too heavy-weight 46471- s = strings.Title(s) 46472- } 46473- return s 46474-} 46475diff -urN a/gopls/internal/lsp/protocol/generate/main.go b/gopls/internal/lsp/protocol/generate/main.go 46476--- a/gopls/internal/lsp/protocol/generate/main.go 2000-01-01 00:00:00.000000000 -0000 46477+++ b/gopls/internal/lsp/protocol/generate/main.go 1970-01-01 00:00:00.000000000 +0000 46478@@ -1,387 +0,0 @@ 46479-// Copyright 2022 The Go Authors. All rights reserved. 46480-// Use of this source code is governed by a BSD-style 46481-// license that can be found in the LICENSE file. 46482- 46483-//go:build go1.19 46484-// +build go1.19 46485- 46486-// The generate command generates Go declarations from VSCode's 46487-// description of the Language Server Protocol. 46488-// 46489-// To run it, type 'go generate' in the parent (protocol) directory. 46490-package main 46491- 46492-import ( 46493- "bytes" 46494- "encoding/json" 46495- "flag" 46496- "fmt" 46497- "go/format" 46498- "log" 46499- "os" 46500- "os/exec" 46501- "path/filepath" 46502- "strings" 46503-) 46504- 46505-const vscodeRepo = "https://github.com/microsoft/vscode-languageserver-node" 46506- 46507-// lspGitRef names a branch or tag in vscodeRepo. 46508-// It implicitly determines the protocol version of the LSP used by gopls. 46509-// For example, tag release/protocol/3.17.3 of the repo defines protocol version 3.17.0. 46510-// (Point releases are reflected in the git tag version even when they are cosmetic 46511-// and don't change the protocol.) 46512-var lspGitRef = "release/protocol/3.17.3-next.6" 46513- 46514-var ( 46515- repodir = flag.String("d", "", "directory containing clone of "+vscodeRepo) 46516- outputdir = flag.String("o", ".", "output directory") 46517- // PJW: not for real code 46518- cmpdir = flag.String("c", "", "directory of earlier code") 46519- doboth = flag.String("b", "", "generate and compare") 46520-) 46521- 46522-func main() { 46523- log.SetFlags(log.Lshortfile) // log file name and line number, not time 46524- flag.Parse() 46525- 46526- processinline() 46527-} 46528- 46529-func processinline() { 46530- // A local repository may be specified during debugging. 46531- // The default behavior is to download the canonical version. 46532- if *repodir == "" { 46533- tmpdir, err := os.MkdirTemp("", "") 46534- if err != nil { 46535- log.Fatal(err) 46536- } 46537- defer os.RemoveAll(tmpdir) // ignore error 46538- 46539- // Clone the repository. 46540- cmd := exec.Command("git", "clone", "--quiet", "--depth=1", "-c", "advice.detachedHead=false", vscodeRepo, "--branch="+lspGitRef, "--single-branch", tmpdir) 46541- cmd.Stdout = os.Stderr 46542- cmd.Stderr = os.Stderr 46543- if err := cmd.Run(); err != nil { 46544- log.Fatal(err) 46545- } 46546- 46547- *repodir = tmpdir 46548- } else { 46549- lspGitRef = fmt.Sprintf("(not git, local dir %s)", *repodir) 46550- } 46551- 46552- model := parse(filepath.Join(*repodir, "protocol/metaModel.json")) 46553- 46554- findTypeNames(model) 46555- generateOutput(model) 46556- 46557- fileHdr = fileHeader(model) 46558- 46559- // write the files 46560- writeclient() 46561- writeserver() 46562- writeprotocol() 46563- writejsons() 46564- 46565- checkTables() 46566-} 46567- 46568-// common file header for output files 46569-var fileHdr string 46570- 46571-func writeclient() { 46572- out := new(bytes.Buffer) 46573- fmt.Fprintln(out, fileHdr) 46574- out.WriteString( 46575- `import ( 46576- "context" 46577- "encoding/json" 46578- 46579- "golang.org/x/tools/internal/jsonrpc2" 46580-) 46581-`) 46582- out.WriteString("type Client interface {\n") 46583- for _, k := range cdecls.keys() { 46584- out.WriteString(cdecls[k]) 46585- } 46586- out.WriteString("}\n\n") 46587- out.WriteString("func clientDispatch(ctx context.Context, client Client, reply jsonrpc2.Replier, r jsonrpc2.Request) (bool, error) {\n") 46588- out.WriteString("\tswitch r.Method() {\n") 46589- for _, k := range ccases.keys() { 46590- out.WriteString(ccases[k]) 46591- } 46592- out.WriteString(("\tdefault:\n\t\treturn false, nil\n\t}\n}\n\n")) 46593- for _, k := range cfuncs.keys() { 46594- out.WriteString(cfuncs[k]) 46595- } 46596- 46597- x, err := format.Source(out.Bytes()) 46598- if err != nil { 46599- os.WriteFile("/tmp/a.go", out.Bytes(), 0644) 46600- log.Fatalf("tsclient.go: %v", err) 46601- } 46602- 46603- if err := os.WriteFile(filepath.Join(*outputdir, "tsclient.go"), x, 0644); err != nil { 46604- log.Fatalf("%v writing tsclient.go", err) 46605- } 46606-} 46607- 46608-func writeserver() { 46609- out := new(bytes.Buffer) 46610- fmt.Fprintln(out, fileHdr) 46611- out.WriteString( 46612- `import ( 46613- "context" 46614- "encoding/json" 46615- 46616- "golang.org/x/tools/internal/jsonrpc2" 46617-) 46618-`) 46619- out.WriteString("type Server interface {\n") 46620- for _, k := range sdecls.keys() { 46621- out.WriteString(sdecls[k]) 46622- } 46623- out.WriteString(` NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) 46624-} 46625- 46626-func serverDispatch(ctx context.Context, server Server, reply jsonrpc2.Replier, r jsonrpc2.Request) (bool, error) { 46627- switch r.Method() { 46628-`) 46629- for _, k := range scases.keys() { 46630- out.WriteString(scases[k]) 46631- } 46632- out.WriteString(("\tdefault:\n\t\treturn false, nil\n\t}\n}\n\n")) 46633- for _, k := range sfuncs.keys() { 46634- out.WriteString(sfuncs[k]) 46635- } 46636- out.WriteString(`func (s *serverDispatcher) NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) { 46637- var result interface{} 46638- if err := s.sender.Call(ctx, method, params, &result); err != nil { 46639- return nil, err 46640- } 46641- return result, nil 46642-} 46643-`) 46644- 46645- x, err := format.Source(out.Bytes()) 46646- if err != nil { 46647- os.WriteFile("/tmp/a.go", out.Bytes(), 0644) 46648- log.Fatalf("tsserver.go: %v", err) 46649- } 46650- 46651- if err := os.WriteFile(filepath.Join(*outputdir, "tsserver.go"), x, 0644); err != nil { 46652- log.Fatalf("%v writing tsserver.go", err) 46653- } 46654-} 46655- 46656-func writeprotocol() { 46657- out := new(bytes.Buffer) 46658- fmt.Fprintln(out, fileHdr) 46659- out.WriteString("import \"encoding/json\"\n\n") 46660- 46661- // The followiing are unneeded, but make the new code a superset of the old 46662- hack := func(newer, existing string) { 46663- if _, ok := types[existing]; !ok { 46664- log.Fatalf("types[%q] not found", existing) 46665- } 46666- types[newer] = strings.Replace(types[existing], existing, newer, 1) 46667- } 46668- hack("ConfigurationParams", "ParamConfiguration") 46669- hack("InitializeParams", "ParamInitialize") 46670- hack("PreviousResultId", "PreviousResultID") 46671- hack("WorkspaceFoldersServerCapabilities", "WorkspaceFolders5Gn") 46672- hack("_InitializeParams", "XInitializeParams") 46673- // and some aliases to make the new code contain the old 46674- types["PrepareRename2Gn"] = "type PrepareRename2Gn = Msg_PrepareRename2Gn // (alias) line 13927\n" 46675- types["PrepareRenameResult"] = "type PrepareRenameResult = Msg_PrepareRename2Gn // (alias) line 13927\n" 46676- for _, k := range types.keys() { 46677- if k == "WatchKind" { 46678- types[k] = "type WatchKind = uint32 // line 13505" // strict gopls compatibility needs the '=' 46679- } 46680- out.WriteString(types[k]) 46681- } 46682- 46683- out.WriteString("\nconst (\n") 46684- for _, k := range consts.keys() { 46685- out.WriteString(consts[k]) 46686- } 46687- out.WriteString(")\n\n") 46688- x, err := format.Source(out.Bytes()) 46689- if err != nil { 46690- os.WriteFile("/tmp/a.go", out.Bytes(), 0644) 46691- log.Fatalf("tsprotocol.go: %v", err) 46692- } 46693- if err := os.WriteFile(filepath.Join(*outputdir, "tsprotocol.go"), x, 0644); err != nil { 46694- log.Fatalf("%v writing tsprotocol.go", err) 46695- } 46696-} 46697- 46698-func writejsons() { 46699- out := new(bytes.Buffer) 46700- fmt.Fprintln(out, fileHdr) 46701- out.WriteString("import \"encoding/json\"\n\n") 46702- out.WriteString("import \"fmt\"\n") 46703- 46704- out.WriteString(` 46705-// UnmarshalError indicates that a JSON value did not conform to 46706-// one of the expected cases of an LSP union type. 46707-type UnmarshalError struct { 46708- msg string 46709-} 46710- 46711-func (e UnmarshalError) Error() string { 46712- return e.msg 46713-} 46714-`) 46715- 46716- for _, k := range jsons.keys() { 46717- out.WriteString(jsons[k]) 46718- } 46719- x, err := format.Source(out.Bytes()) 46720- if err != nil { 46721- os.WriteFile("/tmp/a.go", out.Bytes(), 0644) 46722- log.Fatalf("tsjson.go: %v", err) 46723- } 46724- if err := os.WriteFile(filepath.Join(*outputdir, "tsjson.go"), x, 0644); err != nil { 46725- log.Fatalf("%v writing tsjson.go", err) 46726- } 46727-} 46728- 46729-// create the common file header for the output files 46730-func fileHeader(model Model) string { 46731- fname := filepath.Join(*repodir, ".git", "HEAD") 46732- buf, err := os.ReadFile(fname) 46733- if err != nil { 46734- log.Fatal(err) 46735- } 46736- buf = bytes.TrimSpace(buf) 46737- var githash string 46738- if len(buf) == 40 { 46739- githash = string(buf[:40]) 46740- } else if bytes.HasPrefix(buf, []byte("ref: ")) { 46741- fname = filepath.Join(*repodir, ".git", string(buf[5:])) 46742- buf, err = os.ReadFile(fname) 46743- if err != nil { 46744- log.Fatal(err) 46745- } 46746- githash = string(buf[:40]) 46747- } else { 46748- log.Fatalf("githash cannot be recovered from %s", fname) 46749- } 46750- 46751- format := `// Copyright 2023 The Go Authors. All rights reserved. 46752-// Use of this source code is governed by a BSD-style 46753-// license that can be found in the LICENSE file. 46754- 46755-// Code generated for LSP. DO NOT EDIT. 46756- 46757-package protocol 46758- 46759-// Code generated from %[1]s at ref %[2]s (hash %[3]s). 46760-// %[4]s/blob/%[2]s/%[1]s 46761-// LSP metaData.version = %[5]s. 46762- 46763-` 46764- return fmt.Sprintf(format, 46765- "protocol/metaModel.json", // 1 46766- lspGitRef, // 2 46767- githash, // 3 46768- vscodeRepo, // 4 46769- model.Version.Version) // 5 46770-} 46771- 46772-func parse(fname string) Model { 46773- buf, err := os.ReadFile(fname) 46774- if err != nil { 46775- log.Fatal(err) 46776- } 46777- buf = addLineNumbers(buf) 46778- var model Model 46779- if err := json.Unmarshal(buf, &model); err != nil { 46780- log.Fatal(err) 46781- } 46782- return model 46783-} 46784- 46785-// Type.Value has to be treated specially for literals and maps 46786-func (t *Type) UnmarshalJSON(data []byte) error { 46787- // First unmarshal only the unambiguous fields. 46788- var x struct { 46789- Kind string `json:"kind"` 46790- Items []*Type `json:"items"` 46791- Element *Type `json:"element"` 46792- Name string `json:"name"` 46793- Key *Type `json:"key"` 46794- Value any `json:"value"` 46795- Line int `json:"line"` 46796- } 46797- if err := json.Unmarshal(data, &x); err != nil { 46798- return err 46799- } 46800- *t = Type{ 46801- Kind: x.Kind, 46802- Items: x.Items, 46803- Element: x.Element, 46804- Name: x.Name, 46805- Value: x.Value, 46806- Line: x.Line, 46807- } 46808- 46809- // Then unmarshal the 'value' field based on the kind. 46810- // This depends on Unmarshal ignoring fields it doesn't know about. 46811- switch x.Kind { 46812- case "map": 46813- var x struct { 46814- Key *Type `json:"key"` 46815- Value *Type `json:"value"` 46816- } 46817- if err := json.Unmarshal(data, &x); err != nil { 46818- return fmt.Errorf("Type.kind=map: %v", err) 46819- } 46820- t.Key = x.Key 46821- t.Value = x.Value 46822- 46823- case "literal": 46824- var z struct { 46825- Value ParseLiteral `json:"value"` 46826- } 46827- 46828- if err := json.Unmarshal(data, &z); err != nil { 46829- return fmt.Errorf("Type.kind=literal: %v", err) 46830- } 46831- t.Value = z.Value 46832- 46833- case "base", "reference", "array", "and", "or", "tuple", 46834- "stringLiteral": 46835- // no-op. never seen integerLiteral or booleanLiteral. 46836- 46837- default: 46838- return fmt.Errorf("cannot decode Type.kind %q: %s", x.Kind, data) 46839- } 46840- return nil 46841-} 46842- 46843-// which table entries were not used 46844-func checkTables() { 46845- for k := range disambiguate { 46846- if !usedDisambiguate[k] { 46847- log.Printf("disambiguate[%v] unused", k) 46848- } 46849- } 46850- for k := range renameProp { 46851- if !usedRenameProp[k] { 46852- log.Printf("renameProp {%q, %q} unused", k[0], k[1]) 46853- } 46854- } 46855- for k := range goplsStar { 46856- if !usedGoplsStar[k] { 46857- log.Printf("goplsStar {%q, %q} unused", k[0], k[1]) 46858- } 46859- } 46860- for k := range goplsType { 46861- if !usedGoplsType[k] { 46862- log.Printf("unused goplsType[%q]->%s", k, goplsType[k]) 46863- } 46864- } 46865-} 46866diff -urN a/gopls/internal/lsp/protocol/generate/main_test.go b/gopls/internal/lsp/protocol/generate/main_test.go 46867--- a/gopls/internal/lsp/protocol/generate/main_test.go 2000-01-01 00:00:00.000000000 -0000 46868+++ b/gopls/internal/lsp/protocol/generate/main_test.go 1970-01-01 00:00:00.000000000 +0000 46869@@ -1,118 +0,0 @@ 46870-// Copyright 2022 The Go Authors. All rights reserved. 46871-// Use of this source code is governed by a BSD-style 46872-// license that can be found in the LICENSE file. 46873- 46874-//go:build go1.19 46875-// +build go1.19 46876- 46877-package main 46878- 46879-import ( 46880- "encoding/json" 46881- "fmt" 46882- "log" 46883- "os" 46884- "testing" 46885-) 46886- 46887-// These tests require the result of 46888-//"git clone https://github.com/microsoft/vscode-languageserver-node" in the HOME directory 46889- 46890-// this is not a test, but a way to get code coverage, 46891-// (in vscode, just run the test with "go.coverOnSingleTest": true) 46892-func TestAll(t *testing.T) { 46893- t.Skip("needs vscode-languageserver-node repository") 46894- log.SetFlags(log.Lshortfile) 46895- main() 46896-} 46897- 46898-// check that the parsed file includes all the information 46899-// from the json file. This test will fail if the spec 46900-// introduces new fields. (one can test this test by 46901-// commenting out the version field in Model.) 46902-func TestParseContents(t *testing.T) { 46903- t.Skip("needs vscode-languageserver-node repository") 46904- log.SetFlags(log.Lshortfile) 46905- 46906- // compute our parse of the specification 46907- dir := os.Getenv("HOME") + "/vscode-languageserver-node" 46908- fname := dir + "/protocol/metaModel.json" 46909- v := parse(fname) 46910- out, err := json.Marshal(v) 46911- if err != nil { 46912- t.Fatal(err) 46913- } 46914- var our interface{} 46915- if err := json.Unmarshal(out, &our); err != nil { 46916- t.Fatal(err) 46917- } 46918- 46919- // process the json file 46920- buf, err := os.ReadFile(fname) 46921- if err != nil { 46922- t.Fatalf("could not read metaModel.json: %v", err) 46923- } 46924- var raw interface{} 46925- if err := json.Unmarshal(buf, &raw); err != nil { 46926- t.Fatal(err) 46927- } 46928- 46929- // convert to strings showing the fields 46930- them := flatten(raw) 46931- us := flatten(our) 46932- 46933- // everything in them should be in us 46934- lesser := make(sortedMap[bool]) 46935- for _, s := range them { 46936- lesser[s] = true 46937- } 46938- greater := make(sortedMap[bool]) // set of fields we have 46939- for _, s := range us { 46940- greater[s] = true 46941- } 46942- for _, k := range lesser.keys() { // set if fields they have 46943- if !greater[k] { 46944- t.Errorf("missing %s", k) 46945- } 46946- } 46947-} 46948- 46949-// flatten(nil) = "nil" 46950-// flatten(v string) = fmt.Sprintf("%q", v) 46951-// flatten(v float64)= fmt.Sprintf("%g", v) 46952-// flatten(v bool) = fmt.Sprintf("%v", v) 46953-// flatten(v []any) = []string{"[0]"flatten(v[0]), "[1]"flatten(v[1]), ...} 46954-// flatten(v map[string]any) = {"key1": flatten(v["key1"]), "key2": flatten(v["key2"]), ...} 46955-func flatten(x any) []string { 46956- switch v := x.(type) { 46957- case nil: 46958- return []string{"nil"} 46959- case string: 46960- return []string{fmt.Sprintf("%q", v)} 46961- case float64: 46962- return []string{fmt.Sprintf("%g", v)} 46963- case bool: 46964- return []string{fmt.Sprintf("%v", v)} 46965- case []any: 46966- var ans []string 46967- for i, x := range v { 46968- idx := fmt.Sprintf("[%.3d]", i) 46969- for _, s := range flatten(x) { 46970- ans = append(ans, idx+s) 46971- } 46972- } 46973- return ans 46974- case map[string]any: 46975- var ans []string 46976- for k, x := range v { 46977- idx := fmt.Sprintf("%q:", k) 46978- for _, s := range flatten(x) { 46979- ans = append(ans, idx+s) 46980- } 46981- } 46982- return ans 46983- default: 46984- log.Fatalf("unexpected type %T", x) 46985- return nil 46986- } 46987-} 46988diff -urN a/gopls/internal/lsp/protocol/generate/output.go b/gopls/internal/lsp/protocol/generate/output.go 46989--- a/gopls/internal/lsp/protocol/generate/output.go 2000-01-01 00:00:00.000000000 -0000 46990+++ b/gopls/internal/lsp/protocol/generate/output.go 1970-01-01 00:00:00.000000000 +0000 46991@@ -1,420 +0,0 @@ 46992-// Copyright 2022 The Go Authors. All rights reserved. 46993-// Use of this source code is governed by a BSD-style 46994-// license that can be found in the LICENSE file. 46995- 46996-//go:build go1.19 46997-// +build go1.19 46998- 46999-package main 47000- 47001-import ( 47002- "bytes" 47003- "fmt" 47004- "log" 47005- "sort" 47006- "strings" 47007-) 47008- 47009-var ( 47010- // tsclient.go has 3 sections 47011- cdecls = make(sortedMap[string]) 47012- ccases = make(sortedMap[string]) 47013- cfuncs = make(sortedMap[string]) 47014- // tsserver.go has 3 sections 47015- sdecls = make(sortedMap[string]) 47016- scases = make(sortedMap[string]) 47017- sfuncs = make(sortedMap[string]) 47018- // tsprotocol.go has 2 sections 47019- types = make(sortedMap[string]) 47020- consts = make(sortedMap[string]) 47021- // tsjson has 1 section 47022- jsons = make(sortedMap[string]) 47023-) 47024- 47025-func generateOutput(model Model) { 47026- for _, r := range model.Requests { 47027- genDecl(r.Method, r.Params, r.Result, r.Direction) 47028- genCase(r.Method, r.Params, r.Result, r.Direction) 47029- genFunc(r.Method, r.Params, r.Result, r.Direction, false) 47030- } 47031- for _, n := range model.Notifications { 47032- if n.Method == "$/cancelRequest" { 47033- continue // handled internally by jsonrpc2 47034- } 47035- genDecl(n.Method, n.Params, nil, n.Direction) 47036- genCase(n.Method, n.Params, nil, n.Direction) 47037- genFunc(n.Method, n.Params, nil, n.Direction, true) 47038- } 47039- genStructs(model) 47040- genAliases(model) 47041- genGenTypes() // generate the unnamed types 47042- genConsts(model) 47043- genMarshal() 47044-} 47045- 47046-func genDecl(method string, param, result *Type, dir string) { 47047- fname := methodNames[method] 47048- p := "" 47049- if notNil(param) { 47050- p = ", *" + goplsName(param) 47051- } 47052- ret := "error" 47053- if notNil(result) { 47054- tp := goplsName(result) 47055- if !hasNilValue(tp) { 47056- tp = "*" + tp 47057- } 47058- ret = fmt.Sprintf("(%s, error)", tp) 47059- } 47060- // special gopls compatibility case (PJW: still needed?) 47061- switch method { 47062- case "workspace/configuration": 47063- // was And_Param_workspace_configuration, but the type substitution doesn't work, 47064- // as ParamConfiguration is embedded in And_Param_workspace_configuration 47065- p = ", *ParamConfiguration" 47066- ret = "([]LSPAny, error)" 47067- } 47068- msg := fmt.Sprintf("\t%s(context.Context%s) %s // %s\n", fname, p, ret, method) 47069- switch dir { 47070- case "clientToServer": 47071- sdecls[method] = msg 47072- case "serverToClient": 47073- cdecls[method] = msg 47074- case "both": 47075- sdecls[method] = msg 47076- cdecls[method] = msg 47077- default: 47078- log.Fatalf("impossible direction %q", dir) 47079- } 47080-} 47081- 47082-func genCase(method string, param, result *Type, dir string) { 47083- out := new(bytes.Buffer) 47084- fmt.Fprintf(out, "\tcase %q:\n", method) 47085- var p string 47086- fname := methodNames[method] 47087- if notNil(param) { 47088- nm := goplsName(param) 47089- if method == "workspace/configuration" { // gopls compatibility 47090- // was And_Param_workspace_configuration, which contains ParamConfiguration 47091- // so renaming the type leads to circular definitions 47092- nm = "ParamConfiguration" // gopls compatibility 47093- } 47094- fmt.Fprintf(out, "\t\tvar params %s\n", nm) 47095- fmt.Fprintf(out, "\t\tif err := json.Unmarshal(r.Params(), ¶ms); err != nil {\n") 47096- fmt.Fprintf(out, "\t\t\treturn true, sendParseError(ctx, reply, err)\n\t\t}\n") 47097- p = ", ¶ms" 47098- } 47099- if notNil(result) { 47100- fmt.Fprintf(out, "\t\tresp, err := %%s.%s(ctx%s)\n", fname, p) 47101- out.WriteString("\t\tif err != nil {\n") 47102- out.WriteString("\t\t\treturn true, reply(ctx, nil, err)\n") 47103- out.WriteString("\t\t}\n") 47104- out.WriteString("\t\treturn true, reply(ctx, resp, nil)\n") 47105- } else { 47106- fmt.Fprintf(out, "\t\terr := %%s.%s(ctx%s)\n", fname, p) 47107- out.WriteString("\t\treturn true, reply(ctx, nil, err)\n") 47108- } 47109- msg := out.String() 47110- switch dir { 47111- case "clientToServer": 47112- scases[method] = fmt.Sprintf(msg, "server") 47113- case "serverToClient": 47114- ccases[method] = fmt.Sprintf(msg, "client") 47115- case "both": 47116- scases[method] = fmt.Sprintf(msg, "server") 47117- ccases[method] = fmt.Sprintf(msg, "client") 47118- default: 47119- log.Fatalf("impossible direction %q", dir) 47120- } 47121-} 47122- 47123-func genFunc(method string, param, result *Type, dir string, isnotify bool) { 47124- out := new(bytes.Buffer) 47125- var p, r string 47126- var goResult string 47127- if notNil(param) { 47128- p = ", params *" + goplsName(param) 47129- } 47130- if notNil(result) { 47131- goResult = goplsName(result) 47132- if !hasNilValue(goResult) { 47133- goResult = "*" + goResult 47134- } 47135- r = fmt.Sprintf("(%s, error)", goResult) 47136- } else { 47137- r = "error" 47138- } 47139- // special gopls compatibility case 47140- switch method { 47141- case "workspace/configuration": 47142- // was And_Param_workspace_configuration, but the type substitution doesn't work, 47143- // as ParamConfiguration is embedded in And_Param_workspace_configuration 47144- p = ", params *ParamConfiguration" 47145- r = "([]LSPAny, error)" 47146- goResult = "[]LSPAny" 47147- } 47148- fname := methodNames[method] 47149- fmt.Fprintf(out, "func (s *%%sDispatcher) %s(ctx context.Context%s) %s {\n", 47150- fname, p, r) 47151- 47152- if !notNil(result) { 47153- if isnotify { 47154- if notNil(param) { 47155- fmt.Fprintf(out, "\treturn s.sender.Notify(ctx, %q, params)\n", method) 47156- } else { 47157- fmt.Fprintf(out, "\treturn s.sender.Notify(ctx, %q, nil)\n", method) 47158- } 47159- } else { 47160- if notNil(param) { 47161- fmt.Fprintf(out, "\treturn s.sender.Call(ctx, %q, params, nil)\n", method) 47162- } else { 47163- fmt.Fprintf(out, "\treturn s.sender.Call(ctx, %q, nil, nil)\n", method) 47164- } 47165- } 47166- } else { 47167- fmt.Fprintf(out, "\tvar result %s\n", goResult) 47168- if isnotify { 47169- if notNil(param) { 47170- fmt.Fprintf(out, "\ts.sender.Notify(ctx, %q, params)\n", method) 47171- } else { 47172- fmt.Fprintf(out, "\t\tif err := s.sender.Notify(ctx, %q, nil); err != nil {\n", method) 47173- } 47174- } else { 47175- if notNil(param) { 47176- fmt.Fprintf(out, "\t\tif err := s.sender.Call(ctx, %q, params, &result); err != nil {\n", method) 47177- } else { 47178- fmt.Fprintf(out, "\t\tif err := s.sender.Call(ctx, %q, nil, &result); err != nil {\n", method) 47179- } 47180- } 47181- fmt.Fprintf(out, "\t\treturn nil, err\n\t}\n\treturn result, nil\n") 47182- } 47183- out.WriteString("}\n") 47184- msg := out.String() 47185- switch dir { 47186- case "clientToServer": 47187- sfuncs[method] = fmt.Sprintf(msg, "server") 47188- case "serverToClient": 47189- cfuncs[method] = fmt.Sprintf(msg, "client") 47190- case "both": 47191- sfuncs[method] = fmt.Sprintf(msg, "server") 47192- cfuncs[method] = fmt.Sprintf(msg, "client") 47193- default: 47194- log.Fatalf("impossible direction %q", dir) 47195- } 47196-} 47197- 47198-func genStructs(model Model) { 47199- structures := make(map[string]*Structure) // for expanding Extends 47200- for _, s := range model.Structures { 47201- structures[s.Name] = s 47202- } 47203- for _, s := range model.Structures { 47204- out := new(bytes.Buffer) 47205- generateDoc(out, s.Documentation) 47206- nm := goName(s.Name) 47207- if nm == "string" { // an unacceptable strut name 47208- // a weird case, and needed only so the generated code contains the old gopls code 47209- nm = "DocumentDiagnosticParams" 47210- } 47211- fmt.Fprintf(out, "type %s struct { // line %d\n", nm, s.Line) 47212- // for gpls compatibilitye, embed most extensions, but expand the rest some day 47213- props := append([]NameType{}, s.Properties...) 47214- if s.Name == "SymbolInformation" { // but expand this one 47215- for _, ex := range s.Extends { 47216- fmt.Fprintf(out, "\t// extends %s\n", ex.Name) 47217- props = append(props, structures[ex.Name].Properties...) 47218- } 47219- genProps(out, props, nm) 47220- } else { 47221- genProps(out, props, nm) 47222- for _, ex := range s.Extends { 47223- fmt.Fprintf(out, "\t%s\n", goName(ex.Name)) 47224- } 47225- } 47226- for _, ex := range s.Mixins { 47227- fmt.Fprintf(out, "\t%s\n", goName(ex.Name)) 47228- } 47229- out.WriteString("}\n") 47230- types[nm] = out.String() 47231- } 47232- // base types 47233- types["DocumentURI"] = "type DocumentURI string\n" 47234- types["URI"] = "type URI = string\n" 47235- 47236- types["LSPAny"] = "type LSPAny = interface{}\n" 47237- // A special case, the only previously existing Or type 47238- types["DocumentDiagnosticReport"] = "type DocumentDiagnosticReport = Or_DocumentDiagnosticReport // (alias) line 13909\n" 47239- 47240-} 47241- 47242-func genProps(out *bytes.Buffer, props []NameType, name string) { 47243- for _, p := range props { 47244- tp := goplsName(p.Type) 47245- if newNm, ok := renameProp[prop{name, p.Name}]; ok { 47246- usedRenameProp[prop{name, p.Name}] = true 47247- if tp == newNm { 47248- log.Printf("renameProp useless {%q, %q} for %s", name, p.Name, tp) 47249- } 47250- tp = newNm 47251- } 47252- // it's a pointer if it is optional, or for gopls compatibility 47253- opt, star := propStar(name, p, tp) 47254- json := fmt.Sprintf(" `json:\"%s%s\"`", p.Name, opt) 47255- generateDoc(out, p.Documentation) 47256- fmt.Fprintf(out, "\t%s %s%s %s\n", goName(p.Name), star, tp, json) 47257- } 47258-} 47259- 47260-func genAliases(model Model) { 47261- for _, ta := range model.TypeAliases { 47262- out := new(bytes.Buffer) 47263- generateDoc(out, ta.Documentation) 47264- nm := goName(ta.Name) 47265- if nm != ta.Name { 47266- continue // renamed the type, e.g., "DocumentDiagnosticReport", an or-type to "string" 47267- } 47268- tp := goplsName(ta.Type) 47269- fmt.Fprintf(out, "type %s = %s // (alias) line %d\n", nm, tp, ta.Line) 47270- types[nm] = out.String() 47271- } 47272-} 47273- 47274-func genGenTypes() { 47275- for _, nt := range genTypes { 47276- out := new(bytes.Buffer) 47277- nm := goplsName(nt.typ) 47278- switch nt.kind { 47279- case "literal": 47280- fmt.Fprintf(out, "// created for Literal (%s)\n", nt.name) 47281- fmt.Fprintf(out, "type %s struct { // line %d\n", nm, nt.line+1) 47282- genProps(out, nt.properties, nt.name) // systematic name, not gopls name; is this a good choice? 47283- case "or": 47284- if !strings.HasPrefix(nm, "Or") { 47285- // It was replaced by a narrower type defined elsewhere 47286- continue 47287- } 47288- names := []string{} 47289- for _, t := range nt.items { 47290- if notNil(t) { 47291- names = append(names, goplsName(t)) 47292- } 47293- } 47294- sort.Strings(names) 47295- fmt.Fprintf(out, "// created for Or %v\n", names) 47296- fmt.Fprintf(out, "type %s struct { // line %d\n", nm, nt.line+1) 47297- fmt.Fprintf(out, "\tValue interface{} `json:\"value\"`\n") 47298- case "and": 47299- fmt.Fprintf(out, "// created for And\n") 47300- fmt.Fprintf(out, "type %s struct { // line %d\n", nm, nt.line+1) 47301- for _, x := range nt.items { 47302- nm := goplsName(x) 47303- fmt.Fprintf(out, "\t%s\n", nm) 47304- } 47305- case "tuple": // there's only this one 47306- nt.name = "UIntCommaUInt" 47307- fmt.Fprintf(out, "//created for Tuple\ntype %s struct { // line %d\n", nm, nt.line+1) 47308- fmt.Fprintf(out, "\tFld0 uint32 `json:\"fld0\"`\n") 47309- fmt.Fprintf(out, "\tFld1 uint32 `json:\"fld1\"`\n") 47310- default: 47311- log.Fatalf("%s not handled", nt.kind) 47312- } 47313- out.WriteString("}\n") 47314- types[nm] = out.String() 47315- } 47316-} 47317-func genConsts(model Model) { 47318- for _, e := range model.Enumerations { 47319- out := new(bytes.Buffer) 47320- generateDoc(out, e.Documentation) 47321- tp := goplsName(e.Type) 47322- nm := goName(e.Name) 47323- fmt.Fprintf(out, "type %s %s // line %d\n", nm, tp, e.Line) 47324- types[nm] = out.String() 47325- vals := new(bytes.Buffer) 47326- generateDoc(vals, e.Documentation) 47327- for _, v := range e.Values { 47328- generateDoc(vals, v.Documentation) 47329- nm := goName(v.Name) 47330- more, ok := disambiguate[e.Name] 47331- if ok { 47332- usedDisambiguate[e.Name] = true 47333- nm = more.prefix + nm + more.suffix 47334- nm = goName(nm) // stringType 47335- } 47336- var val string 47337- switch v := v.Value.(type) { 47338- case string: 47339- val = fmt.Sprintf("%q", v) 47340- case float64: 47341- val = fmt.Sprintf("%d", int(v)) 47342- default: 47343- log.Fatalf("impossible type %T", v) 47344- } 47345- fmt.Fprintf(vals, "\t%s %s = %s // line %d\n", nm, e.Name, val, v.Line) 47346- } 47347- consts[nm] = vals.String() 47348- } 47349-} 47350-func genMarshal() { 47351- for _, nt := range genTypes { 47352- nm := goplsName(nt.typ) 47353- if !strings.HasPrefix(nm, "Or") { 47354- continue 47355- } 47356- names := []string{} 47357- for _, t := range nt.items { 47358- if notNil(t) { 47359- names = append(names, goplsName(t)) 47360- } 47361- } 47362- sort.Strings(names) 47363- var buf bytes.Buffer 47364- fmt.Fprintf(&buf, "// from line %d\n", nt.line) 47365- fmt.Fprintf(&buf, "func (t %s) MarshalJSON() ([]byte, error) {\n", nm) 47366- buf.WriteString("\tswitch x := t.Value.(type){\n") 47367- for _, nmx := range names { 47368- fmt.Fprintf(&buf, "\tcase %s:\n", nmx) 47369- fmt.Fprintf(&buf, "\t\treturn json.Marshal(x)\n") 47370- } 47371- buf.WriteString("\tcase nil:\n\t\treturn []byte(\"null\"), nil\n\t}\n") 47372- fmt.Fprintf(&buf, "\treturn nil, fmt.Errorf(\"type %%T not one of %v\", t)\n", names) 47373- buf.WriteString("}\n\n") 47374- 47375- fmt.Fprintf(&buf, "func (t *%s) UnmarshalJSON(x []byte) error {\n", nm) 47376- buf.WriteString("\tif string(x) == \"null\" {\n\t\tt.Value = nil\n\t\t\treturn nil\n\t}\n") 47377- for i, nmx := range names { 47378- fmt.Fprintf(&buf, "\tvar h%d %s\n", i, nmx) 47379- fmt.Fprintf(&buf, "\tif err := json.Unmarshal(x, &h%d); err == nil {\n\t\tt.Value = h%d\n\t\t\treturn nil\n\t\t}\n", i, i) 47380- } 47381- fmt.Fprintf(&buf, "return &UnmarshalError{\"unmarshal failed to match one of %v\"}", names) 47382- buf.WriteString("}\n\n") 47383- jsons[nm] = buf.String() 47384- } 47385-} 47386- 47387-func goplsName(t *Type) string { 47388- nm := typeNames[t] 47389- // translate systematic name to gopls name 47390- if newNm, ok := goplsType[nm]; ok { 47391- usedGoplsType[nm] = true 47392- nm = newNm 47393- } 47394- return nm 47395-} 47396- 47397-func notNil(t *Type) bool { // shutdwon is the special case that needs this 47398- return t != nil && (t.Kind != "base" || t.Name != "null") 47399-} 47400- 47401-func hasNilValue(t string) bool { 47402- // this may be unreliable, and need a supplementary table 47403- if strings.HasPrefix(t, "[]") || strings.HasPrefix(t, "*") { 47404- return true 47405- } 47406- if t == "interface{}" || t == "any" { 47407- return true 47408- } 47409- // that's all the cases that occur currently 47410- return false 47411-} 47412diff -urN a/gopls/internal/lsp/protocol/generate/README.md b/gopls/internal/lsp/protocol/generate/README.md 47413--- a/gopls/internal/lsp/protocol/generate/README.md 2000-01-01 00:00:00.000000000 -0000 47414+++ b/gopls/internal/lsp/protocol/generate/README.md 1970-01-01 00:00:00.000000000 +0000 47415@@ -1,136 +0,0 @@ 47416-# LSP Support for gopls 47417- 47418-## The protocol 47419- 47420-The LSP protocol exchanges json-encoded messages between the client and the server. 47421-(gopls is the server.) The messages are either Requests, which require Responses, or 47422-Notifications, which generate no response. Each Request or Notification has a method name 47423-such as "textDocument/hover" that indicates its meaning and determines which function in the server will handle it. 47424-The protocol is described in a 47425-[web page](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/), 47426-in words, and in a json file (metaModel.json) available either linked towards the bottom of the 47427-web page, or in the vscode-languageserver-node repository. This code uses the latter so the 47428-exact version can be tied to a githash. By default, the command will download the `github.com/microsoft/vscode-languageserver-node` repository to a temporary directory. 47429- 47430-The specification has five sections 47431-1. Requests, which describe the Request and Response types for request methods (e.g., *textDocument/didChange*), 47432-2. Notifications, which describe the Request types for notification methods, 47433-3. Structures, which describe named struct-like types, 47434-4. TypeAliases, which describe type aliases, 47435-5. Enumerations, which describe named constants. 47436- 47437-Requests and Notifications are tagged with a Method (e.g., `"textDocument/hover"`). 47438-The specification does not specify the names of the functions that handle the messages. These 47439-names are specified by the `methodNames` map. Enumerations generate Go `const`s, but 47440-in Typescript they are scoped to namespaces, while in Go they are scoped to a package, so the Go names 47441-may need to be modified to avoid name collisions. (See the `disambiguate` map, and its use.) 47442- 47443-Finally, the specified types are Typescript types, which are quite different from Go types. 47444- 47445-### Optionality 47446-The specification can mark fields in structs as Optional. The client distinguishes between missing 47447-fields and `null` fields in some cases. The Go translation for an optional type 47448-should be making sure the field's value 47449-can be `nil`, and adding the json tag `,omitempty`. The former condition would be satisfied by 47450-adding `*` to the field's type if the type is not a reference type. 47451- 47452-### Types 47453-The specification uses a number of different types, only a few of which correspond directly to Go types. 47454-The specification's types are "base", "reference", "map", "literal", "stringLiteral", "tuple", "and", "or". 47455-The "base" types correspond directly to Go types, although some Go types needs to be chosen for `URI` and `DocumentUri`. (The "base" types`RegExp`, `BooleanLiteral`, `NumericLiteral` never occur.) 47456- 47457-"reference" types are the struct-like types in the Structures section of the specification. The given 47458-names are suitable for Go to use, except the code needs to change names like `_Initialze` to `XInitialize` so 47459-they are exported for json marshaling and unmarshaling. 47460- 47461-"map" types are just like Go. (The key type in all of them is `DocumentUri`.) 47462- 47463-"stringLiteral" types are types whose type name and value are a single string. The chosen Go equivalent 47464-is to make the type `string` and the value a constant. (The alternative would be to generate a new 47465-named type, which seemed redundant.) 47466- 47467-"literal" types are like Go anonymous structs, so they have to be given a name. (All instances 47468-of the remaining types have to be given names. One approach is to construct the name from the components 47469-of the type, but this leads to misleading punning, and is unstable if components are added. The other approach 47470-is to construct the name from the context of the definition, that is, from the types it is defined within. 47471-For instance `Lit__InitializeParams_clientInfo` is the "literal" type at the 47472-`clientInfo` field in the `_InitializeParams` 47473-struct. Although this choice is sensitive to the ordering of the components, the code uses this approach, 47474-presuming that reordering components is an unlikely protocol change.) 47475- 47476-"tuple" types are generated as Go structs. (There is only one, with two `uint32` fields.) 47477- 47478-"and" types are Go structs with embedded type names. (There is only one, `And_Param_workspace_configuration`.) 47479- 47480-"or" types are the most complicated. There are a lot of them and there is no simple Go equivalent. 47481-They are defined as structs with a single `Value interface{}` field and custom json marshaling 47482-and unmarshaling code. Users can assign anything to `Value` but the type will be checked, and 47483-correctly marshaled, by the custom marshaling code. The unmarshaling code checks types, so `Value` 47484-will have one of the permitted types. (`nil` is always allowed.) There are about 40 "or" types that 47485-have a single non-null component, and these are converted to the component type. 47486- 47487-## Processing 47488-The code parses the json specification file, and scans all the types. It assigns names, as described 47489-above, to the types that are unnamed in the specification, and constructs Go equivalents as required. 47490-(Most of this code is in typenames.go.) 47491- 47492-There are four output files. tsclient.go and tsserver.go contain the definition and implementation 47493-of the `protocol.Client` and `protocol.Server` types and the code that dispatches on the Method 47494-of the Request or Notification. tsjson.go contains the custom marshaling and unmarshaling code. 47495-And tsprotocol.go contains the type and const definitions. 47496- 47497-### Accommodating gopls 47498-As the code generates output, mostly in generateoutput.go and main.go, 47499-it makes adjustments so that no changes are required to the existing Go code. 47500-(Organizing the computation this way makes the code's structure simpler, but results in 47501-a lot of unused types.) 47502-There are three major classes of these adjustments, and leftover special cases. 47503- 47504-The first major 47505-adjustment is to change generated type names to the ones gopls expects. Some of these don't change the 47506-semantics of the type, just the name. 47507-But for historical reasons a lot of them replace "or" types by a single 47508-component of the type. (Until fairly recently Go only saw or used only one of components.) 47509-The `goplsType` map in tables.go controls this process. 47510- 47511-The second major adjustment is to the types of fields of structs, which is done using the 47512-`renameProp` map in tables.go. 47513- 47514-The third major adjustment handles optionality, controlling `*` and `,omitempty` placement when 47515-the default rules don't match what gopls is expecting. (The map is `goplsStar`, also in tables.go) 47516-(If the intermediate components in expressions of the form `A.B.C.S` were optional, the code would need 47517-a lot of useless checking for nils. Typescript has a language construct to avoid most checks.) 47518- 47519-Then there are some additional special cases. There are a few places with adjustments to avoid 47520-recursive types. For instance `LSPArray` is `[]LSPAny`, but `LSPAny` is an "or" type including `LSPArray`. 47521-The solution is to make `LSPAny` an `interface{}`. Another instance is `_InitializeParams.trace` 47522-whose type is an "or" of 3 stringLiterals, which just becomes a `string`. 47523- 47524-### Checking 47525-`TestAll(t *testing.T)` checks that there are no unexpected fields in the json specification. 47526- 47527-While the code is executing, it checks that all the entries in the maps in tables.go are used. 47528-It also checks that the entries in `renameProp` and `goplsStar` are not redundant. 47529- 47530-As a one-time check on the first release of this code, diff-ing the existing and generated tsclient.go 47531-and tsserver.go code results in only whitespace and comment diffs. The existing and generated 47532-tsprotocol.go differ in whitespace and comments, and in a substantial number of new type definitions 47533-that the older, more heuristic, code did not generate. (And the unused type `_InitializeParams` differs 47534-slightly between the new and the old, and is not worth fixing.) 47535- 47536-### Some history 47537-The original stub code was written by hand, but with the protocol under active development, that 47538-couldn't last. The web page existed before the json specification, but it lagged the implementation 47539-and was hard to process by machine. So the earlier version of the generating code was written in Typescript, and 47540-used the Typescript compiler's API to parse the protocol code in the repository. 47541-It then used a set of heuristics 47542-to pick out the elements of the protocol, and another set of overlapping heuristics to create the Go code. 47543-The output was functional, but idiosyncratic, and the code was fragile and barely maintainable. 47544- 47545-### The future 47546-Most of the adjustments using the maps in tables.go could be removed by making changes, mostly to names, 47547-in the gopls code. Using more "or" types in gopls requires more elaborate, but stereotyped, changes. 47548-But even without all the adjustments, making this its own module would face problems; a number of 47549-dependencies would have to be factored out. And, it is fragile. The custom unmarshaling code knows what 47550-types it expects. A design that return an 'any' on unexpected types would match the json 47551-'ignore unexpected values' philosophy better, but the the Go code would need extra checking. 47552diff -urN a/gopls/internal/lsp/protocol/generate/tables.go b/gopls/internal/lsp/protocol/generate/tables.go 47553--- a/gopls/internal/lsp/protocol/generate/tables.go 2000-01-01 00:00:00.000000000 -0000 47554+++ b/gopls/internal/lsp/protocol/generate/tables.go 1970-01-01 00:00:00.000000000 +0000 47555@@ -1,327 +0,0 @@ 47556-// Copyright 2022 The Go Authors. All rights reserved. 47557-// Use of this source code is governed by a BSD-style 47558-// license that can be found in the LICENSE file. 47559- 47560-//go:build go1.19 47561-// +build go1.19 47562- 47563-package main 47564- 47565-// prop combines the name of a property with the name of the structure it is in. 47566-type prop [2]string 47567- 47568-const ( 47569- nothing = iota 47570- wantStar 47571- wantOpt 47572- wantOptStar 47573-) 47574- 47575-// goplsStar records the optionality of each field in the protocol. 47576-// The comments are vague hints as to why removing the line is not trivial. 47577-// A.B.C.D means that one of B or C would change to a pointer 47578-// so a test or initialization would be needed 47579-var goplsStar = map[prop]int{ 47580- {"ClientCapabilities", "textDocument"}: wantOpt, // A.B.C.D at fake/editor.go:255 47581- {"ClientCapabilities", "window"}: wantOpt, // regtest failures 47582- {"ClientCapabilities", "workspace"}: wantOpt, // regtest failures 47583- {"CodeAction", "kind"}: wantOpt, // A.B.C.D 47584- 47585- {"CodeActionClientCapabilities", "codeActionLiteralSupport"}: wantOpt, // regtest failures 47586- 47587- {"CompletionClientCapabilities", "completionItem"}: wantOpt, // A.B.C.D 47588- {"CompletionClientCapabilities", "insertTextMode"}: wantOpt, // A.B.C.D 47589- {"CompletionItem", "kind"}: wantOpt, // need temporary variables 47590- {"CompletionParams", "context"}: wantOpt, // needs nil checks 47591- 47592- {"Diagnostic", "severity"}: wantOpt, // nil checks or more careful thought 47593- {"DidSaveTextDocumentParams", "text"}: wantOptStar, // capabilities_test.go:112 logic 47594- {"DocumentHighlight", "kind"}: wantOpt, // need temporary variables 47595- {"Hover", "range"}: wantOpt, // complex expressions 47596- {"InlayHint", "kind"}: wantOpt, // temporary variables 47597- 47598- {"Lit_CompletionClientCapabilities_completionItem", "tagSupport"}: nothing, // A.B.C. 47599- {"Lit_SemanticTokensClientCapabilities_requests", "full"}: nothing, // A.B.C.D 47600- {"Lit_SemanticTokensClientCapabilities_requests", "range"}: nothing, // A.B.C.D 47601- {"Lit_SemanticTokensClientCapabilities_requests_full_Item1", "delta"}: nothing, // A.B.C.D 47602- {"Lit_SemanticTokensOptions_full_Item1", "delta"}: nothing, // A.B.C. 47603- 47604- {"Lit_TextDocumentContentChangeEvent_Item0", "range"}: wantStar, // == nil test 47605- 47606- {"TextDocumentClientCapabilities", "codeAction"}: wantOpt, // A.B.C.D 47607- {"TextDocumentClientCapabilities", "completion"}: wantOpt, // A.B.C.D 47608- {"TextDocumentClientCapabilities", "documentSymbol"}: wantOpt, // A.B.C.D 47609- {"TextDocumentClientCapabilities", "publishDiagnostics"}: wantOpt, //A.B.C.D 47610- {"TextDocumentClientCapabilities", "semanticTokens"}: wantOpt, // A.B.C.D 47611- {"TextDocumentSyncOptions", "change"}: wantOpt, // &constant 47612- {"WorkDoneProgressParams", "workDoneToken"}: wantOpt, // regtest 47613- {"WorkspaceClientCapabilities", "didChangeConfiguration"}: wantOpt, // A.B.C.D 47614- {"WorkspaceClientCapabilities", "didChangeWatchedFiles"}: wantOpt, // A.B.C.D 47615-} 47616- 47617-// keep track of which entries in goplsStar are used 47618-var usedGoplsStar = make(map[prop]bool) 47619- 47620-// For gopls compatibility, use a different, typically more restrictive, type for some fields. 47621-var renameProp = map[prop]string{ 47622- {"CancelParams", "id"}: "interface{}", 47623- {"Command", "arguments"}: "[]json.RawMessage", 47624- {"CompletionItem", "textEdit"}: "TextEdit", 47625- {"Diagnostic", "code"}: "interface{}", 47626- 47627- {"DocumentDiagnosticReportPartialResult", "relatedDocuments"}: "map[DocumentURI]interface{}", 47628- 47629- {"ExecuteCommandParams", "arguments"}: "[]json.RawMessage", 47630- {"FoldingRange", "kind"}: "string", 47631- {"Hover", "contents"}: "MarkupContent", 47632- {"InlayHint", "label"}: "[]InlayHintLabelPart", 47633- 47634- {"RelatedFullDocumentDiagnosticReport", "relatedDocuments"}: "map[DocumentURI]interface{}", 47635- {"RelatedUnchangedDocumentDiagnosticReport", "relatedDocuments"}: "map[DocumentURI]interface{}", 47636- 47637- // PJW: this one is tricky. 47638- {"ServerCapabilities", "codeActionProvider"}: "interface{}", 47639- 47640- {"ServerCapabilities", "inlayHintProvider"}: "interface{}", 47641- // slightly tricky 47642- {"ServerCapabilities", "renameProvider"}: "interface{}", 47643- // slightly tricky 47644- {"ServerCapabilities", "semanticTokensProvider"}: "interface{}", 47645- // slightly tricky 47646- {"ServerCapabilities", "textDocumentSync"}: "interface{}", 47647- {"TextDocumentEdit", "edits"}: "[]TextEdit", 47648- {"TextDocumentSyncOptions", "save"}: "SaveOptions", 47649- {"WorkspaceEdit", "documentChanges"}: "[]DocumentChanges", 47650-} 47651- 47652-// which entries of renameProp were used 47653-var usedRenameProp = make(map[prop]bool) 47654- 47655-type adjust struct { 47656- prefix, suffix string 47657-} 47658- 47659-// disambiguate specifies prefixes or suffixes to add to all values of 47660-// some enum types to avoid name conflicts 47661-var disambiguate = map[string]adjust{ 47662- "CodeActionTriggerKind": {"CodeAction", ""}, 47663- "CompletionItemKind": {"", "Completion"}, 47664- "CompletionItemTag": {"Compl", ""}, 47665- "DiagnosticSeverity": {"Severity", ""}, 47666- "DocumentDiagnosticReportKind": {"Diagnostic", ""}, 47667- "FileOperationPatternKind": {"", "Pattern"}, 47668- "InsertTextFormat": {"", "TextFormat"}, 47669- "SemanticTokenModifiers": {"Mod", ""}, 47670- "SemanticTokenTypes": {"", "Type"}, 47671- "SignatureHelpTriggerKind": {"Sig", ""}, 47672- "SymbolTag": {"", "Symbol"}, 47673- "WatchKind": {"Watch", ""}, 47674-} 47675- 47676-// which entries of disambiguate got used 47677-var usedDisambiguate = make(map[string]bool) 47678- 47679-// for gopls compatibility, replace generated type names with existing ones 47680-var goplsType = map[string]string{ 47681- "And_RegOpt_textDocument_colorPresentation": "WorkDoneProgressOptionsAndTextDocumentRegistrationOptions", 47682- "ConfigurationParams": "ParamConfiguration", 47683- "DocumentDiagnosticParams": "string", 47684- "DocumentDiagnosticReport": "string", 47685- "DocumentUri": "DocumentURI", 47686- "InitializeParams": "ParamInitialize", 47687- "LSPAny": "interface{}", 47688- 47689- "Lit_CodeActionClientCapabilities_codeActionLiteralSupport": "PCodeActionLiteralSupportPCodeAction", 47690- "Lit_CodeActionClientCapabilities_codeActionLiteralSupport_codeActionKind": "FCodeActionKindPCodeActionLiteralSupport", 47691- 47692- "Lit_CodeActionClientCapabilities_resolveSupport": "PResolveSupportPCodeAction", 47693- "Lit_CodeAction_disabled": "PDisabledMsg_textDocument_codeAction", 47694- "Lit_CompletionClientCapabilities_completionItem": "PCompletionItemPCompletion", 47695- "Lit_CompletionClientCapabilities_completionItemKind": "PCompletionItemKindPCompletion", 47696- 47697- "Lit_CompletionClientCapabilities_completionItem_insertTextModeSupport": "FInsertTextModeSupportPCompletionItem", 47698- 47699- "Lit_CompletionClientCapabilities_completionItem_resolveSupport": "FResolveSupportPCompletionItem", 47700- "Lit_CompletionClientCapabilities_completionItem_tagSupport": "FTagSupportPCompletionItem", 47701- 47702- "Lit_CompletionClientCapabilities_completionList": "PCompletionListPCompletion", 47703- "Lit_CompletionList_itemDefaults": "PItemDefaultsMsg_textDocument_completion", 47704- "Lit_CompletionList_itemDefaults_editRange_Item1": "FEditRangePItemDefaults", 47705- "Lit_CompletionOptions_completionItem": "PCompletionItemPCompletionProvider", 47706- "Lit_DocumentSymbolClientCapabilities_symbolKind": "PSymbolKindPDocumentSymbol", 47707- "Lit_DocumentSymbolClientCapabilities_tagSupport": "PTagSupportPDocumentSymbol", 47708- "Lit_FoldingRangeClientCapabilities_foldingRange": "PFoldingRangePFoldingRange", 47709- "Lit_FoldingRangeClientCapabilities_foldingRangeKind": "PFoldingRangeKindPFoldingRange", 47710- "Lit_GeneralClientCapabilities_staleRequestSupport": "PStaleRequestSupportPGeneral", 47711- "Lit_InitializeResult_serverInfo": "PServerInfoMsg_initialize", 47712- "Lit_InlayHintClientCapabilities_resolveSupport": "PResolveSupportPInlayHint", 47713- "Lit_MarkedString_Item1": "Msg_MarkedString", 47714- "Lit_NotebookDocumentChangeEvent_cells": "PCellsPChange", 47715- "Lit_NotebookDocumentChangeEvent_cells_structure": "FStructurePCells", 47716- "Lit_NotebookDocumentFilter_Item0": "Msg_NotebookDocumentFilter", 47717- 47718- "Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0": "PNotebookSelectorPNotebookDocumentSync", 47719- 47720- "Lit_PrepareRenameResult_Item1": "Msg_PrepareRename2Gn", 47721- 47722- "Lit_PublishDiagnosticsClientCapabilities_tagSupport": "PTagSupportPPublishDiagnostics", 47723- "Lit_SemanticTokensClientCapabilities_requests": "PRequestsPSemanticTokens", 47724- "Lit_SemanticTokensClientCapabilities_requests_full_Item1": "FFullPRequests", 47725- "Lit_SemanticTokensClientCapabilities_requests_range_Item1": "FRangePRequests", 47726- 47727- "Lit_SemanticTokensOptions_full_Item1": "PFullESemanticTokensOptions", 47728- "Lit_SemanticTokensOptions_range_Item1": "PRangeESemanticTokensOptions", 47729- "Lit_ServerCapabilities_workspace": "Workspace6Gn", 47730- 47731- "Lit_ShowMessageRequestClientCapabilities_messageActionItem": "PMessageActionItemPShowMessage", 47732- "Lit_SignatureHelpClientCapabilities_signatureInformation": "PSignatureInformationPSignatureHelp", 47733- 47734- "Lit_SignatureHelpClientCapabilities_signatureInformation_parameterInformation": "FParameterInformationPSignatureInformation", 47735- 47736- "Lit_TextDocumentContentChangeEvent_Item0": "Msg_TextDocumentContentChangeEvent", 47737- "Lit_TextDocumentFilter_Item0": "Msg_TextDocumentFilter", 47738- "Lit_TextDocumentFilter_Item1": "Msg_TextDocumentFilter", 47739- "Lit_WorkspaceEditClientCapabilities_changeAnnotationSupport": "PChangeAnnotationSupportPWorkspaceEdit", 47740- "Lit_WorkspaceSymbolClientCapabilities_resolveSupport": "PResolveSupportPSymbol", 47741- "Lit_WorkspaceSymbolClientCapabilities_symbolKind": "PSymbolKindPSymbol", 47742- "Lit_WorkspaceSymbolClientCapabilities_tagSupport": "PTagSupportPSymbol", 47743- "Lit_WorkspaceSymbol_location_Item1": "PLocationMsg_workspace_symbol", 47744- "Lit__InitializeParams_clientInfo": "Msg_XInitializeParams_clientInfo", 47745- "Or_CompletionList_itemDefaults_editRange": "OrFEditRangePItemDefaults", 47746- "Or_Declaration": "[]Location", 47747- "Or_DidChangeConfigurationRegistrationOptions_section": "OrPSection_workspace_didChangeConfiguration", 47748- "Or_GlobPattern": "string", 47749- "Or_InlayHintLabelPart_tooltip": "OrPTooltipPLabel", 47750- "Or_InlayHint_tooltip": "OrPTooltip_textDocument_inlayHint", 47751- "Or_LSPAny": "interface{}", 47752- "Or_NotebookDocumentFilter": "Msg_NotebookDocumentFilter", 47753- "Or_NotebookDocumentSyncOptions_notebookSelector_Elem": "PNotebookSelectorPNotebookDocumentSync", 47754- 47755- "Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_notebook": "OrFNotebookPNotebookSelector", 47756- 47757- "Or_ParameterInformation_documentation": "string", 47758- "Or_ParameterInformation_label": "string", 47759- "Or_PrepareRenameResult": "Msg_PrepareRename2Gn", 47760- "Or_ProgressToken": "interface{}", 47761- "Or_Result_textDocument_completion": "CompletionList", 47762- "Or_Result_textDocument_declaration": "Or_textDocument_declaration", 47763- "Or_Result_textDocument_definition": "[]Location", 47764- "Or_Result_textDocument_documentSymbol": "[]interface{}", 47765- "Or_Result_textDocument_implementation": "[]Location", 47766- "Or_Result_textDocument_semanticTokens_full_delta": "interface{}", 47767- "Or_Result_textDocument_typeDefinition": "[]Location", 47768- "Or_Result_workspace_symbol": "[]SymbolInformation", 47769- "Or_TextDocumentContentChangeEvent": "Msg_TextDocumentContentChangeEvent", 47770- "Or_TextDocumentFilter": "Msg_TextDocumentFilter", 47771- "Or_WorkspaceFoldersServerCapabilities_changeNotifications": "string", 47772- "Or_WorkspaceSymbol_location": "OrPLocation_workspace_symbol", 47773- "PrepareRenameResult": "PrepareRename2Gn", 47774- "Tuple_ParameterInformation_label_Item1": "UIntCommaUInt", 47775- "WorkspaceFoldersServerCapabilities": "WorkspaceFolders5Gn", 47776- "[]LSPAny": "[]interface{}", 47777- "[]Or_NotebookDocumentSyncOptions_notebookSelector_Elem": "[]PNotebookSelectorPNotebookDocumentSync", 47778- "[]Or_Result_textDocument_codeAction_Item0_Elem": "[]CodeAction", 47779- "[]PreviousResultId": "[]PreviousResultID", 47780- "[]uinteger": "[]uint32", 47781- "boolean": "bool", 47782- "decimal": "float64", 47783- "integer": "int32", 47784- "map[DocumentUri][]TextEdit": "map[DocumentURI][]TextEdit", 47785- "uinteger": "uint32", 47786-} 47787- 47788-var usedGoplsType = make(map[string]bool) 47789- 47790-// methodNames is a map from the method to the name of the function that handles it 47791-var methodNames = map[string]string{ 47792- "$/cancelRequest": "CancelRequest", 47793- "$/logTrace": "LogTrace", 47794- "$/progress": "Progress", 47795- "$/setTrace": "SetTrace", 47796- "callHierarchy/incomingCalls": "IncomingCalls", 47797- "callHierarchy/outgoingCalls": "OutgoingCalls", 47798- "client/registerCapability": "RegisterCapability", 47799- "client/unregisterCapability": "UnregisterCapability", 47800- "codeAction/resolve": "ResolveCodeAction", 47801- "codeLens/resolve": "ResolveCodeLens", 47802- "completionItem/resolve": "ResolveCompletionItem", 47803- "documentLink/resolve": "ResolveDocumentLink", 47804- "exit": "Exit", 47805- "initialize": "Initialize", 47806- "initialized": "Initialized", 47807- "inlayHint/resolve": "Resolve", 47808- "notebookDocument/didChange": "DidChangeNotebookDocument", 47809- "notebookDocument/didClose": "DidCloseNotebookDocument", 47810- "notebookDocument/didOpen": "DidOpenNotebookDocument", 47811- "notebookDocument/didSave": "DidSaveNotebookDocument", 47812- "shutdown": "Shutdown", 47813- "telemetry/event": "Event", 47814- "textDocument/codeAction": "CodeAction", 47815- "textDocument/codeLens": "CodeLens", 47816- "textDocument/colorPresentation": "ColorPresentation", 47817- "textDocument/completion": "Completion", 47818- "textDocument/declaration": "Declaration", 47819- "textDocument/definition": "Definition", 47820- "textDocument/diagnostic": "Diagnostic", 47821- "textDocument/didChange": "DidChange", 47822- "textDocument/didClose": "DidClose", 47823- "textDocument/didOpen": "DidOpen", 47824- "textDocument/didSave": "DidSave", 47825- "textDocument/documentColor": "DocumentColor", 47826- "textDocument/documentHighlight": "DocumentHighlight", 47827- "textDocument/documentLink": "DocumentLink", 47828- "textDocument/documentSymbol": "DocumentSymbol", 47829- "textDocument/foldingRange": "FoldingRange", 47830- "textDocument/formatting": "Formatting", 47831- "textDocument/hover": "Hover", 47832- "textDocument/implementation": "Implementation", 47833- "textDocument/inlayHint": "InlayHint", 47834- "textDocument/inlineValue": "InlineValue", 47835- "textDocument/linkedEditingRange": "LinkedEditingRange", 47836- "textDocument/moniker": "Moniker", 47837- "textDocument/onTypeFormatting": "OnTypeFormatting", 47838- "textDocument/prepareCallHierarchy": "PrepareCallHierarchy", 47839- "textDocument/prepareRename": "PrepareRename", 47840- "textDocument/prepareTypeHierarchy": "PrepareTypeHierarchy", 47841- "textDocument/publishDiagnostics": "PublishDiagnostics", 47842- "textDocument/rangeFormatting": "RangeFormatting", 47843- "textDocument/references": "References", 47844- "textDocument/rename": "Rename", 47845- "textDocument/selectionRange": "SelectionRange", 47846- "textDocument/semanticTokens/full": "SemanticTokensFull", 47847- "textDocument/semanticTokens/full/delta": "SemanticTokensFullDelta", 47848- "textDocument/semanticTokens/range": "SemanticTokensRange", 47849- "textDocument/signatureHelp": "SignatureHelp", 47850- "textDocument/typeDefinition": "TypeDefinition", 47851- "textDocument/willSave": "WillSave", 47852- "textDocument/willSaveWaitUntil": "WillSaveWaitUntil", 47853- "typeHierarchy/subtypes": "Subtypes", 47854- "typeHierarchy/supertypes": "Supertypes", 47855- "window/logMessage": "LogMessage", 47856- "window/showDocument": "ShowDocument", 47857- "window/showMessage": "ShowMessage", 47858- "window/showMessageRequest": "ShowMessageRequest", 47859- "window/workDoneProgress/cancel": "WorkDoneProgressCancel", 47860- "window/workDoneProgress/create": "WorkDoneProgressCreate", 47861- "workspace/applyEdit": "ApplyEdit", 47862- "workspace/codeLens/refresh": "CodeLensRefresh", 47863- "workspace/configuration": "Configuration", 47864- "workspace/diagnostic": "DiagnosticWorkspace", 47865- "workspace/diagnostic/refresh": "DiagnosticRefresh", 47866- "workspace/didChangeConfiguration": "DidChangeConfiguration", 47867- "workspace/didChangeWatchedFiles": "DidChangeWatchedFiles", 47868- "workspace/didChangeWorkspaceFolders": "DidChangeWorkspaceFolders", 47869- "workspace/didCreateFiles": "DidCreateFiles", 47870- "workspace/didDeleteFiles": "DidDeleteFiles", 47871- "workspace/didRenameFiles": "DidRenameFiles", 47872- "workspace/executeCommand": "ExecuteCommand", 47873- "workspace/inlayHint/refresh": "InlayHintRefresh", 47874- "workspace/inlineValue/refresh": "InlineValueRefresh", 47875- "workspace/semanticTokens/refresh": "SemanticTokensRefresh", 47876- "workspace/symbol": "Symbol", 47877- "workspace/willCreateFiles": "WillCreateFiles", 47878- "workspace/willDeleteFiles": "WillDeleteFiles", 47879- "workspace/willRenameFiles": "WillRenameFiles", 47880- "workspace/workspaceFolders": "WorkspaceFolders", 47881- "workspaceSymbol/resolve": "ResolveWorkspaceSymbol", 47882-} 47883diff -urN a/gopls/internal/lsp/protocol/generate/typenames.go b/gopls/internal/lsp/protocol/generate/typenames.go 47884--- a/gopls/internal/lsp/protocol/generate/typenames.go 2000-01-01 00:00:00.000000000 -0000 47885+++ b/gopls/internal/lsp/protocol/generate/typenames.go 1970-01-01 00:00:00.000000000 +0000 47886@@ -1,184 +0,0 @@ 47887-// Copyright 2022 The Go Authors. All rights reserved. 47888-// Use of this source code is governed by a BSD-style 47889-// license that can be found in the LICENSE file. 47890- 47891-//go:build go1.19 47892-// +build go1.19 47893- 47894-package main 47895- 47896-import ( 47897- "fmt" 47898- "log" 47899- "strings" 47900-) 47901- 47902-var typeNames = make(map[*Type]string) 47903-var genTypes []*newType 47904- 47905-func findTypeNames(model Model) { 47906- for _, s := range model.Structures { 47907- for _, e := range s.Extends { 47908- nameType(e, nil) // all references 47909- } 47910- for _, m := range s.Mixins { 47911- nameType(m, nil) // all references 47912- } 47913- for _, p := range s.Properties { 47914- nameType(p.Type, []string{s.Name, p.Name}) 47915- } 47916- } 47917- for _, t := range model.Enumerations { 47918- nameType(t.Type, []string{t.Name}) 47919- } 47920- for _, t := range model.TypeAliases { 47921- nameType(t.Type, []string{t.Name}) 47922- } 47923- for _, r := range model.Requests { 47924- nameType(r.Params, []string{"Param", r.Method}) 47925- nameType(r.Result, []string{"Result", r.Method}) 47926- nameType(r.RegistrationOptions, []string{"RegOpt", r.Method}) 47927- } 47928- for _, n := range model.Notifications { 47929- nameType(n.Params, []string{"Param", n.Method}) 47930- nameType(n.RegistrationOptions, []string{"RegOpt", n.Method}) 47931- } 47932-} 47933- 47934-// nameType populates typeNames[t] with the computed name of the type. 47935-// path is the list of enclosing constructs in the JSON model. 47936-func nameType(t *Type, path []string) string { 47937- if t == nil || typeNames[t] != "" { 47938- return "" 47939- } 47940- switch t.Kind { 47941- case "base": 47942- typeNames[t] = t.Name 47943- return t.Name 47944- case "reference": 47945- typeNames[t] = t.Name 47946- return t.Name 47947- case "array": 47948- nm := "[]" + nameType(t.Element, append(path, "Elem")) 47949- typeNames[t] = nm 47950- return nm 47951- case "map": 47952- key := nameType(t.Key, nil) // never a generated type 47953- value := nameType(t.Value.(*Type), append(path, "Value")) 47954- nm := "map[" + key + "]" + value 47955- typeNames[t] = nm 47956- return nm 47957- // generated types 47958- case "and": 47959- nm := nameFromPath("And", path) 47960- typeNames[t] = nm 47961- for _, it := range t.Items { 47962- nameType(it, append(path, "Item")) 47963- } 47964- genTypes = append(genTypes, &newType{ 47965- name: nm, 47966- typ: t, 47967- kind: "and", 47968- items: t.Items, 47969- line: t.Line, 47970- }) 47971- return nm 47972- case "literal": 47973- nm := nameFromPath("Lit", path) 47974- typeNames[t] = nm 47975- for _, p := range t.Value.(ParseLiteral).Properties { 47976- nameType(p.Type, append(path, p.Name)) 47977- } 47978- genTypes = append(genTypes, &newType{ 47979- name: nm, 47980- typ: t, 47981- kind: "literal", 47982- properties: t.Value.(ParseLiteral).Properties, 47983- line: t.Line, 47984- }) 47985- return nm 47986- case "tuple": 47987- nm := nameFromPath("Tuple", path) 47988- typeNames[t] = nm 47989- for _, it := range t.Items { 47990- nameType(it, append(path, "Item")) 47991- } 47992- genTypes = append(genTypes, &newType{ 47993- name: nm, 47994- typ: t, 47995- kind: "tuple", 47996- items: t.Items, 47997- line: t.Line, 47998- }) 47999- return nm 48000- case "or": 48001- nm := nameFromPath("Or", path) 48002- typeNames[t] = nm 48003- for i, it := range t.Items { 48004- // these names depend on the ordering within the "or" type 48005- nameType(it, append(path, fmt.Sprintf("Item%d", i))) 48006- } 48007- // this code handles an "or" of stringLiterals (_InitializeParams.trace) 48008- names := make(map[string]int) 48009- msg := "" 48010- for _, it := range t.Items { 48011- if line, ok := names[typeNames[it]]; ok { 48012- // duplicate component names are bad 48013- msg += fmt.Sprintf("lines %d %d dup, %s for %s\n", line, it.Line, typeNames[it], nm) 48014- } 48015- names[typeNames[it]] = t.Line 48016- } 48017- // this code handles an "or" of stringLiterals (_InitializeParams.trace) 48018- if len(names) == 1 { 48019- var solekey string 48020- for k := range names { 48021- solekey = k // the sole name 48022- } 48023- if solekey == "string" { // _InitializeParams.trace 48024- typeNames[t] = "string" 48025- return "string" 48026- } 48027- // otherwise unexpected 48028- log.Printf("unexpected: single-case 'or' type has non-string key %s: %s", nm, solekey) 48029- log.Fatal(msg) 48030- } else if len(names) == 2 { 48031- // if one of the names is null, just use the other, rather than generating an "or". 48032- // This removes about 40 types from the generated code. An entry in goplsStar 48033- // could be added to handle the null case, if necessary. 48034- newNm := "" 48035- sawNull := false 48036- for k := range names { 48037- if k == "null" { 48038- sawNull = true 48039- } else { 48040- newNm = k 48041- } 48042- } 48043- if sawNull { 48044- typeNames[t] = newNm 48045- return newNm 48046- } 48047- } 48048- genTypes = append(genTypes, &newType{ 48049- name: nm, 48050- typ: t, 48051- kind: "or", 48052- items: t.Items, 48053- line: t.Line, 48054- }) 48055- return nm 48056- case "stringLiteral": // a single type, like 'kind' or 'rename' 48057- typeNames[t] = "string" 48058- return "string" 48059- default: 48060- log.Fatalf("nameType: %T unexpected, line:%d path:%v", t, t.Line, path) 48061- panic("unreachable in nameType") 48062- } 48063-} 48064- 48065-func nameFromPath(prefix string, path []string) string { 48066- nm := prefix + "_" + strings.Join(path, "_") 48067- // methods have slashes 48068- nm = strings.ReplaceAll(nm, "/", "_") 48069- return nm 48070-} 48071diff -urN a/gopls/internal/lsp/protocol/generate/types.go b/gopls/internal/lsp/protocol/generate/types.go 48072--- a/gopls/internal/lsp/protocol/generate/types.go 2000-01-01 00:00:00.000000000 -0000 48073+++ b/gopls/internal/lsp/protocol/generate/types.go 1970-01-01 00:00:00.000000000 +0000 48074@@ -1,170 +0,0 @@ 48075-// Copyright 2022 The Go Authors. All rights reserved. 48076-// Use of this source code is governed by a BSD-style 48077-// license that can be found in the LICENSE file. 48078- 48079-//go:build go1.19 48080-// +build go1.19 48081- 48082-package main 48083- 48084-import ( 48085- "fmt" 48086- "sort" 48087-) 48088- 48089-// Model contains the parsed version of the spec 48090-type Model struct { 48091- Version Metadata `json:"metaData"` 48092- Requests []*Request `json:"requests"` 48093- Notifications []*Notification `json:"notifications"` 48094- Structures []*Structure `json:"structures"` 48095- Enumerations []*Enumeration `json:"enumerations"` 48096- TypeAliases []*TypeAlias `json:"typeAliases"` 48097- Line int `json:"line"` 48098-} 48099- 48100-// Metadata is information about the version of the spec 48101-type Metadata struct { 48102- Version string `json:"version"` 48103- Line int `json:"line"` 48104-} 48105- 48106-// A Request is the parsed version of an LSP request 48107-type Request struct { 48108- Documentation string `json:"documentation"` 48109- ErrorData *Type `json:"errorData"` 48110- Direction string `json:"messageDirection"` 48111- Method string `json:"method"` 48112- Params *Type `json:"params"` 48113- PartialResult *Type `json:"partialResult"` 48114- Proposed bool `json:"proposed"` 48115- RegistrationMethod string `json:"registrationMethod"` 48116- RegistrationOptions *Type `json:"registrationOptions"` 48117- Result *Type `json:"result"` 48118- Since string `json:"since"` 48119- Line int `json:"line"` 48120-} 48121- 48122-// A Notificatin is the parsed version of an LSP notification 48123-type Notification struct { 48124- Documentation string `json:"documentation"` 48125- Direction string `json:"messageDirection"` 48126- Method string `json:"method"` 48127- Params *Type `json:"params"` 48128- Proposed bool `json:"proposed"` 48129- RegistrationMethod string `json:"registrationMethod"` 48130- RegistrationOptions *Type `json:"registrationOptions"` 48131- Since string `json:"since"` 48132- Line int `json:"line"` 48133-} 48134- 48135-// A Structure is the parsed version of an LSP structure from the spec 48136-type Structure struct { 48137- Documentation string `json:"documentation"` 48138- Extends []*Type `json:"extends"` 48139- Mixins []*Type `json:"mixins"` 48140- Name string `json:"name"` 48141- Properties []NameType `json:"properties"` 48142- Proposed bool `json:"proposed"` 48143- Since string `json:"since"` 48144- Line int `json:"line"` 48145-} 48146- 48147-// An enumeration is the parsed version of an LSP enumeration from the spec 48148-type Enumeration struct { 48149- Documentation string `json:"documentation"` 48150- Name string `json:"name"` 48151- Proposed bool `json:"proposed"` 48152- Since string `json:"since"` 48153- SupportsCustomValues bool `json:"supportsCustomValues"` 48154- Type *Type `json:"type"` 48155- Values []NameValue `json:"values"` 48156- Line int `json:"line"` 48157-} 48158- 48159-// A TypeAlias is the parsed version of an LSP type alias from the spec 48160-type TypeAlias struct { 48161- Documentation string `json:"documentation"` 48162- Deprecated string `json:"deprecated"` 48163- Name string `json:"name"` 48164- Proposed bool `json:"proposed"` 48165- Since string `json:"since"` 48166- Type *Type `json:"type"` 48167- Line int `json:"line"` 48168-} 48169- 48170-// A NameValue describes an enumeration constant 48171-type NameValue struct { 48172- Documentation string `json:"documentation"` 48173- Name string `json:"name"` 48174- Proposed bool `json:"proposed"` 48175- Since string `json:"since"` 48176- Value any `json:"value"` // number or string 48177- Line int `json:"line"` 48178-} 48179- 48180-// A Type is the parsed version of an LSP type from the spec, 48181-// or a Type the code constructs 48182-type Type struct { 48183- Kind string `json:"kind"` // -- which kind goes with which field -- 48184- Items []*Type `json:"items"` // "and", "or", "tuple" 48185- Element *Type `json:"element"` // "array" 48186- Name string `json:"name"` // "base", "reference" 48187- Key *Type `json:"key"` // "map" 48188- Value any `json:"value"` // "map", "stringLiteral", "literal" 48189- Line int `json:"line"` // JSON source line 48190-} 48191- 48192-// ParsedLiteral is Type.Value when Type.Kind is "literal" 48193-type ParseLiteral struct { 48194- Properties `json:"properties"` 48195-} 48196- 48197-// A NameType represents the name and type of a structure element 48198-type NameType struct { 48199- Name string `json:"name"` 48200- Type *Type `json:"type"` 48201- Optional bool `json:"optional"` 48202- Documentation string `json:"documentation"` 48203- Deprecated string `json:"deprecated"` 48204- Since string `json:"since"` 48205- Proposed bool `json:"proposed"` 48206- Line int `json:"line"` 48207-} 48208- 48209-// Properties are the collection of structure fields 48210-type Properties []NameType 48211- 48212-// addLineNumbers adds a "line" field to each object in the JSON. 48213-func addLineNumbers(buf []byte) []byte { 48214- var ans []byte 48215- // In the specification .json file, the delimiter '{' is 48216- // always followed by a newline. There are other {s embedded in strings. 48217- // json.Token does not return \n, or :, or , so using it would 48218- // require parsing the json to reconstruct the missing information. 48219- for linecnt, i := 1, 0; i < len(buf); i++ { 48220- ans = append(ans, buf[i]) 48221- switch buf[i] { 48222- case '{': 48223- if buf[i+1] == '\n' { 48224- ans = append(ans, fmt.Sprintf(`"line": %d, `, linecnt)...) 48225- // warning: this would fail if the spec file had 48226- // `"value": {\n}`, but it does not, as comma is a separator. 48227- } 48228- case '\n': 48229- linecnt++ 48230- } 48231- } 48232- return ans 48233-} 48234- 48235-type sortedMap[T any] map[string]T 48236- 48237-func (s sortedMap[T]) keys() []string { 48238- var keys []string 48239- for k := range s { 48240- keys = append(keys, k) 48241- } 48242- sort.Strings(keys) 48243- return keys 48244-} 48245diff -urN a/gopls/internal/lsp/protocol/log.go b/gopls/internal/lsp/protocol/log.go 48246--- a/gopls/internal/lsp/protocol/log.go 2000-01-01 00:00:00.000000000 -0000 48247+++ b/gopls/internal/lsp/protocol/log.go 1970-01-01 00:00:00.000000000 +0000 48248@@ -1,136 +0,0 @@ 48249-// Copyright 2019 The Go Authors. All rights reserved. 48250-// Use of this source code is governed by a BSD-style 48251-// license that can be found in the LICENSE file. 48252- 48253-package protocol 48254- 48255-import ( 48256- "context" 48257- "fmt" 48258- "io" 48259- "strings" 48260- "sync" 48261- "time" 48262- 48263- "golang.org/x/tools/internal/jsonrpc2" 48264-) 48265- 48266-type loggingStream struct { 48267- stream jsonrpc2.Stream 48268- logMu sync.Mutex 48269- log io.Writer 48270-} 48271- 48272-// LoggingStream returns a stream that does LSP protocol logging too 48273-func LoggingStream(str jsonrpc2.Stream, w io.Writer) jsonrpc2.Stream { 48274- return &loggingStream{stream: str, log: w} 48275-} 48276- 48277-func (s *loggingStream) Read(ctx context.Context) (jsonrpc2.Message, int64, error) { 48278- msg, count, err := s.stream.Read(ctx) 48279- if err == nil { 48280- s.logCommon(msg, true) 48281- } 48282- return msg, count, err 48283-} 48284- 48285-func (s *loggingStream) Write(ctx context.Context, msg jsonrpc2.Message) (int64, error) { 48286- s.logCommon(msg, false) 48287- count, err := s.stream.Write(ctx, msg) 48288- return count, err 48289-} 48290- 48291-func (s *loggingStream) Close() error { 48292- return s.stream.Close() 48293-} 48294- 48295-type req struct { 48296- method string 48297- start time.Time 48298-} 48299- 48300-type mapped struct { 48301- mu sync.Mutex 48302- clientCalls map[string]req 48303- serverCalls map[string]req 48304-} 48305- 48306-var maps = &mapped{ 48307- sync.Mutex{}, 48308- make(map[string]req), 48309- make(map[string]req), 48310-} 48311- 48312-// these 4 methods are each used exactly once, but it seemed 48313-// better to have the encapsulation rather than ad hoc mutex 48314-// code in 4 places 48315-func (m *mapped) client(id string) req { 48316- m.mu.Lock() 48317- defer m.mu.Unlock() 48318- v := m.clientCalls[id] 48319- delete(m.clientCalls, id) 48320- return v 48321-} 48322- 48323-func (m *mapped) server(id string) req { 48324- m.mu.Lock() 48325- defer m.mu.Unlock() 48326- v := m.serverCalls[id] 48327- delete(m.serverCalls, id) 48328- return v 48329-} 48330- 48331-func (m *mapped) setClient(id string, r req) { 48332- m.mu.Lock() 48333- defer m.mu.Unlock() 48334- m.clientCalls[id] = r 48335-} 48336- 48337-func (m *mapped) setServer(id string, r req) { 48338- m.mu.Lock() 48339- defer m.mu.Unlock() 48340- m.serverCalls[id] = r 48341-} 48342- 48343-const eor = "\r\n\r\n\r\n" 48344- 48345-func (s *loggingStream) logCommon(msg jsonrpc2.Message, isRead bool) { 48346- s.logMu.Lock() 48347- defer s.logMu.Unlock() 48348- direction, pastTense := "Received", "Received" 48349- get, set := maps.client, maps.setServer 48350- if isRead { 48351- direction, pastTense = "Sending", "Sent" 48352- get, set = maps.server, maps.setClient 48353- } 48354- if msg == nil || s.log == nil { 48355- return 48356- } 48357- tm := time.Now() 48358- tmfmt := tm.Format("15:04:05.000 PM") 48359- 48360- buf := strings.Builder{} 48361- fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning 48362- switch msg := msg.(type) { 48363- case *jsonrpc2.Call: 48364- id := fmt.Sprint(msg.ID()) 48365- fmt.Fprintf(&buf, "%s request '%s - (%s)'.\n", direction, msg.Method(), id) 48366- fmt.Fprintf(&buf, "Params: %s%s", msg.Params(), eor) 48367- set(id, req{method: msg.Method(), start: tm}) 48368- case *jsonrpc2.Notification: 48369- fmt.Fprintf(&buf, "%s notification '%s'.\n", direction, msg.Method()) 48370- fmt.Fprintf(&buf, "Params: %s%s", msg.Params(), eor) 48371- case *jsonrpc2.Response: 48372- id := fmt.Sprint(msg.ID()) 48373- if err := msg.Err(); err != nil { 48374- fmt.Fprintf(s.log, "[Error - %s] %s #%s %s%s", pastTense, tmfmt, id, err, eor) 48375- return 48376- } 48377- cc := get(id) 48378- elapsed := tm.Sub(cc.start) 48379- fmt.Fprintf(&buf, "%s response '%s - (%s)' in %dms.\n", 48380- direction, cc.method, id, elapsed/time.Millisecond) 48381- fmt.Fprintf(&buf, "Result: %s%s", msg.Result(), eor) 48382- } 48383- s.log.Write([]byte(buf.String())) 48384-} 48385diff -urN a/gopls/internal/lsp/protocol/mapper.go b/gopls/internal/lsp/protocol/mapper.go 48386--- a/gopls/internal/lsp/protocol/mapper.go 2000-01-01 00:00:00.000000000 -0000 48387+++ b/gopls/internal/lsp/protocol/mapper.go 1970-01-01 00:00:00.000000000 +0000 48388@@ -1,529 +0,0 @@ 48389-// Copyright 2023 The Go Authors. All rights reserved. 48390-// Use of this source code is governed by a BSD-style 48391-// license that can be found in the LICENSE file. 48392- 48393-package protocol 48394- 48395-// This file defines Mapper, which wraps a file content buffer 48396-// ([]byte) and provides efficient conversion between every kind of 48397-// position representation. 48398-// 48399-// gopls uses four main representations of position: 48400-// 48401-// 1. byte offsets, e.g. (start, end int), starting from zero. 48402-// 48403-// 2. go/token notation. Use these types when interacting directly 48404-// with the go/* syntax packages: 48405-// 48406-// token.Pos 48407-// token.FileSet 48408-// token.File 48409-// 48410-// Because File.Offset and File.Pos panic on invalid inputs, 48411-// we do not call them directly and instead use the safetoken package 48412-// for these conversions. This is enforced by a static check. 48413-// 48414-// Beware also that the methods of token.File have two bugs for which 48415-// safetoken contains workarounds: 48416-// - #57490, whereby the parser may create ast.Nodes during error 48417-// recovery whose computed positions are out of bounds (EOF+1). 48418-// - #41029, whereby the wrong line number is returned for the EOF position. 48419-// 48420-// 3. the span package. 48421-// 48422-// span.Point = (line, col8, offset). 48423-// span.Span = (uri URI, start, end span.Point) 48424-// 48425-// Line and column are 1-based. 48426-// Columns are measured in bytes (UTF-8 codes). 48427-// All fields are optional. 48428-// 48429-// These types are useful as intermediate conversions of validated 48430-// ranges (though MappedRange is superior as it is self contained 48431-// and universally convertible). Since their fields are optional 48432-// they are also useful for parsing user-provided positions (e.g. in 48433-// the CLI) before we have access to file contents. 48434-// 48435-// 4. protocol, the LSP RPC message format. 48436-// 48437-// protocol.Position = (Line, Character uint32) 48438-// protocol.Range = (start, end Position) 48439-// protocol.Location = (URI, protocol.Range) 48440-// 48441-// Line and Character are 0-based. 48442-// Characters (columns) are measured in UTF-16 codes. 48443-// 48444-// protocol.Mapper holds the (URI, Content) of a file, enabling 48445-// efficient mapping between byte offsets, span ranges, and 48446-// protocol ranges. 48447-// 48448-// protocol.MappedRange holds a protocol.Mapper and valid (start, 48449-// end int) byte offsets, enabling infallible, efficient conversion 48450-// to any other format. 48451- 48452-import ( 48453- "bytes" 48454- "fmt" 48455- "go/ast" 48456- "go/token" 48457- "path/filepath" 48458- "sort" 48459- "strings" 48460- "sync" 48461- "unicode/utf8" 48462- 48463- "golang.org/x/tools/gopls/internal/lsp/safetoken" 48464- "golang.org/x/tools/gopls/internal/span" 48465- "golang.org/x/tools/internal/bug" 48466-) 48467- 48468-// A Mapper wraps the content of a file and provides mapping 48469-// between byte offsets and notations of position such as: 48470-// 48471-// - (line, col8) pairs, where col8 is a 1-based UTF-8 column number 48472-// (bytes), as used by the go/token and span packages. 48473-// 48474-// - (line, col16) pairs, where col16 is a 1-based UTF-16 column 48475-// number, as used by the LSP protocol. 48476-// 48477-// All conversion methods are named "FromTo", where From and To are the two types. 48478-// For example, the PointPosition method converts from a Point to a Position. 48479-// 48480-// Mapper does not intrinsically depend on go/token-based 48481-// representations. Use safetoken to map between token.Pos <=> byte 48482-// offsets, or the convenience methods such as PosPosition, 48483-// NodePosition, or NodeRange. 48484-// 48485-// See overview comments at top of this file. 48486-type Mapper struct { 48487- URI span.URI 48488- Content []byte 48489- 48490- // Line-number information is requested only for a tiny 48491- // fraction of Mappers, so we compute it lazily. 48492- // Call initLines() before accessing fields below. 48493- linesOnce sync.Once 48494- lineStart []int // byte offset of start of ith line (0-based); last=EOF iff \n-terminated 48495- nonASCII bool 48496- 48497- // TODO(adonovan): adding an extra lineStart entry for EOF 48498- // might simplify every method that accesses it. Try it out. 48499-} 48500- 48501-// NewMapper creates a new mapper for the given URI and content. 48502-func NewMapper(uri span.URI, content []byte) *Mapper { 48503- return &Mapper{URI: uri, Content: content} 48504-} 48505- 48506-// initLines populates the lineStart table. 48507-func (m *Mapper) initLines() { 48508- m.linesOnce.Do(func() { 48509- nlines := bytes.Count(m.Content, []byte("\n")) 48510- m.lineStart = make([]int, 1, nlines+1) // initially []int{0} 48511- for offset, b := range m.Content { 48512- if b == '\n' { 48513- m.lineStart = append(m.lineStart, offset+1) 48514- } 48515- if b >= utf8.RuneSelf { 48516- m.nonASCII = true 48517- } 48518- } 48519- }) 48520-} 48521- 48522-// -- conversions from span (UTF-8) domain -- 48523- 48524-// SpanLocation converts a (UTF-8) span to a protocol (UTF-16) range. 48525-// Precondition: the URIs of SpanLocation and Mapper match. 48526-func (m *Mapper) SpanLocation(s span.Span) (Location, error) { 48527- rng, err := m.SpanRange(s) 48528- if err != nil { 48529- return Location{}, err 48530- } 48531- return m.RangeLocation(rng), nil 48532-} 48533- 48534-// SpanRange converts a (UTF-8) span to a protocol (UTF-16) range. 48535-// Precondition: the URIs of Span and Mapper match. 48536-func (m *Mapper) SpanRange(s span.Span) (Range, error) { 48537- // Assert that we aren't using the wrong mapper. 48538- // We check only the base name, and case insensitively, 48539- // because we can't assume clean paths, no symbolic links, 48540- // case-sensitive directories. The authoritative answer 48541- // requires querying the file system, and we don't want 48542- // to do that. 48543- if !strings.EqualFold(filepath.Base(string(m.URI)), filepath.Base(string(s.URI()))) { 48544- return Range{}, bug.Errorf("mapper is for file %q instead of %q", m.URI, s.URI()) 48545- } 48546- start, err := m.PointPosition(s.Start()) 48547- if err != nil { 48548- return Range{}, fmt.Errorf("start: %w", err) 48549- } 48550- end, err := m.PointPosition(s.End()) 48551- if err != nil { 48552- return Range{}, fmt.Errorf("end: %w", err) 48553- } 48554- return Range{Start: start, End: end}, nil 48555-} 48556- 48557-// PointPosition converts a valid span (UTF-8) point to a protocol (UTF-16) position. 48558-func (m *Mapper) PointPosition(p span.Point) (Position, error) { 48559- if p.HasPosition() { 48560- line, col8 := p.Line()-1, p.Column()-1 // both 0-based 48561- m.initLines() 48562- if line >= len(m.lineStart) { 48563- return Position{}, fmt.Errorf("line number %d out of range (max %d)", line, len(m.lineStart)) 48564- } 48565- offset := m.lineStart[line] 48566- end := offset + col8 48567- 48568- // Validate column. 48569- if end > len(m.Content) { 48570- return Position{}, fmt.Errorf("column is beyond end of file") 48571- } else if line+1 < len(m.lineStart) && end >= m.lineStart[line+1] { 48572- return Position{}, fmt.Errorf("column is beyond end of line") 48573- } 48574- 48575- char := UTF16Len(m.Content[offset:end]) 48576- return Position{Line: uint32(line), Character: uint32(char)}, nil 48577- } 48578- if p.HasOffset() { 48579- return m.OffsetPosition(p.Offset()) 48580- } 48581- return Position{}, fmt.Errorf("point has neither offset nor line/column") 48582-} 48583- 48584-// -- conversions from byte offsets -- 48585- 48586-// OffsetLocation converts a byte-offset interval to a protocol (UTF-16) location. 48587-func (m *Mapper) OffsetLocation(start, end int) (Location, error) { 48588- rng, err := m.OffsetRange(start, end) 48589- if err != nil { 48590- return Location{}, err 48591- } 48592- return m.RangeLocation(rng), nil 48593-} 48594- 48595-// OffsetRange converts a byte-offset interval to a protocol (UTF-16) range. 48596-func (m *Mapper) OffsetRange(start, end int) (Range, error) { 48597- if start > end { 48598- return Range{}, fmt.Errorf("start offset (%d) > end (%d)", start, end) 48599- } 48600- startPosition, err := m.OffsetPosition(start) 48601- if err != nil { 48602- return Range{}, fmt.Errorf("start: %v", err) 48603- } 48604- endPosition, err := m.OffsetPosition(end) 48605- if err != nil { 48606- return Range{}, fmt.Errorf("end: %v", err) 48607- } 48608- return Range{Start: startPosition, End: endPosition}, nil 48609-} 48610- 48611-// OffsetSpan converts a byte-offset interval to a (UTF-8) span. 48612-// The resulting span contains line, column, and offset information. 48613-func (m *Mapper) OffsetSpan(start, end int) (span.Span, error) { 48614- if start > end { 48615- return span.Span{}, fmt.Errorf("start offset (%d) > end (%d)", start, end) 48616- } 48617- startPoint, err := m.OffsetPoint(start) 48618- if err != nil { 48619- return span.Span{}, fmt.Errorf("start: %v", err) 48620- } 48621- endPoint, err := m.OffsetPoint(end) 48622- if err != nil { 48623- return span.Span{}, fmt.Errorf("end: %v", err) 48624- } 48625- return span.New(m.URI, startPoint, endPoint), nil 48626-} 48627- 48628-// OffsetPosition converts a byte offset to a protocol (UTF-16) position. 48629-func (m *Mapper) OffsetPosition(offset int) (Position, error) { 48630- if !(0 <= offset && offset <= len(m.Content)) { 48631- return Position{}, fmt.Errorf("invalid offset %d (want 0-%d)", offset, len(m.Content)) 48632- } 48633- // No error may be returned after this point, 48634- // even if the offset does not fall at a rune boundary. 48635- // (See panic in MappedRange.Range reachable.) 48636- 48637- line, col16 := m.lineCol16(offset) 48638- return Position{Line: uint32(line), Character: uint32(col16)}, nil 48639-} 48640- 48641-// lineCol16 converts a valid byte offset to line and UTF-16 column numbers, both 0-based. 48642-func (m *Mapper) lineCol16(offset int) (int, int) { 48643- line, start, cr := m.line(offset) 48644- var col16 int 48645- if m.nonASCII { 48646- col16 = UTF16Len(m.Content[start:offset]) 48647- } else { 48648- col16 = offset - start 48649- } 48650- if cr { 48651- col16-- // retreat from \r at line end 48652- } 48653- return line, col16 48654-} 48655- 48656-// lineCol8 converts a valid byte offset to line and UTF-8 column numbers, both 0-based. 48657-func (m *Mapper) lineCol8(offset int) (int, int) { 48658- line, start, cr := m.line(offset) 48659- col8 := offset - start 48660- if cr { 48661- col8-- // retreat from \r at line end 48662- } 48663- return line, col8 48664-} 48665- 48666-// line returns: 48667-// - the 0-based index of the line that encloses the (valid) byte offset; 48668-// - the start offset of that line; and 48669-// - whether the offset denotes a carriage return (\r) at line end. 48670-func (m *Mapper) line(offset int) (int, int, bool) { 48671- m.initLines() 48672- // In effect, binary search returns a 1-based result. 48673- line := sort.Search(len(m.lineStart), func(i int) bool { 48674- return offset < m.lineStart[i] 48675- }) 48676- 48677- // Adjustment for line-endings: \r|\n is the same as |\r\n. 48678- var eol int 48679- if line == len(m.lineStart) { 48680- eol = len(m.Content) // EOF 48681- } else { 48682- eol = m.lineStart[line] - 1 48683- } 48684- cr := offset == eol && offset > 0 && m.Content[offset-1] == '\r' 48685- 48686- line-- // 0-based 48687- 48688- return line, m.lineStart[line], cr 48689-} 48690- 48691-// OffsetPoint converts a byte offset to a span (UTF-8) point. 48692-// The resulting point contains line, column, and offset information. 48693-func (m *Mapper) OffsetPoint(offset int) (span.Point, error) { 48694- if !(0 <= offset && offset <= len(m.Content)) { 48695- return span.Point{}, fmt.Errorf("invalid offset %d (want 0-%d)", offset, len(m.Content)) 48696- } 48697- line, col8 := m.lineCol8(offset) 48698- return span.NewPoint(line+1, col8+1, offset), nil 48699-} 48700- 48701-// OffsetMappedRange returns a MappedRange for the given byte offsets. 48702-// A MappedRange can be converted to any other form. 48703-func (m *Mapper) OffsetMappedRange(start, end int) (MappedRange, error) { 48704- if !(0 <= start && start <= end && end <= len(m.Content)) { 48705- return MappedRange{}, fmt.Errorf("invalid offsets (%d, %d) (file %s has size %d)", start, end, m.URI, len(m.Content)) 48706- } 48707- return MappedRange{m, start, end}, nil 48708-} 48709- 48710-// -- conversions from protocol (UTF-16) domain -- 48711- 48712-// LocationSpan converts a protocol (UTF-16) Location to a (UTF-8) span. 48713-// Precondition: the URIs of Location and Mapper match. 48714-func (m *Mapper) LocationSpan(l Location) (span.Span, error) { 48715- // TODO(adonovan): check that l.URI matches m.URI. 48716- return m.RangeSpan(l.Range) 48717-} 48718- 48719-// RangeSpan converts a protocol (UTF-16) range to a (UTF-8) span. 48720-// The resulting span has valid Positions and Offsets. 48721-func (m *Mapper) RangeSpan(r Range) (span.Span, error) { 48722- start, end, err := m.RangeOffsets(r) 48723- if err != nil { 48724- return span.Span{}, err 48725- } 48726- return m.OffsetSpan(start, end) 48727-} 48728- 48729-// RangeOffsets converts a protocol (UTF-16) range to start/end byte offsets. 48730-func (m *Mapper) RangeOffsets(r Range) (int, int, error) { 48731- start, err := m.PositionOffset(r.Start) 48732- if err != nil { 48733- return 0, 0, err 48734- } 48735- end, err := m.PositionOffset(r.End) 48736- if err != nil { 48737- return 0, 0, err 48738- } 48739- return start, end, nil 48740-} 48741- 48742-// PositionOffset converts a protocol (UTF-16) position to a byte offset. 48743-func (m *Mapper) PositionOffset(p Position) (int, error) { 48744- m.initLines() 48745- 48746- // Validate line number. 48747- if p.Line > uint32(len(m.lineStart)) { 48748- return 0, fmt.Errorf("line number %d out of range 0-%d", p.Line, len(m.lineStart)) 48749- } else if p.Line == uint32(len(m.lineStart)) { 48750- if p.Character == 0 { 48751- return len(m.Content), nil // EOF 48752- } 48753- return 0, fmt.Errorf("column is beyond end of file") 48754- } 48755- 48756- offset := m.lineStart[p.Line] 48757- content := m.Content[offset:] // rest of file from start of enclosing line 48758- 48759- // Advance bytes up to the required number of UTF-16 codes. 48760- col8 := 0 48761- for col16 := 0; col16 < int(p.Character); col16++ { 48762- r, sz := utf8.DecodeRune(content) 48763- if sz == 0 { 48764- return 0, fmt.Errorf("column is beyond end of file") 48765- } 48766- if r == '\n' { 48767- return 0, fmt.Errorf("column is beyond end of line") 48768- } 48769- if sz == 1 && r == utf8.RuneError { 48770- return 0, fmt.Errorf("buffer contains invalid UTF-8 text") 48771- } 48772- content = content[sz:] 48773- 48774- if r >= 0x10000 { 48775- col16++ // rune was encoded by a pair of surrogate UTF-16 codes 48776- 48777- if col16 == int(p.Character) { 48778- break // requested position is in the middle of a rune 48779- } 48780- } 48781- col8 += sz 48782- } 48783- return offset + col8, nil 48784-} 48785- 48786-// PositionPoint converts a protocol (UTF-16) position to a span (UTF-8) point. 48787-// The resulting point has a valid Position and Offset. 48788-func (m *Mapper) PositionPoint(p Position) (span.Point, error) { 48789- offset, err := m.PositionOffset(p) 48790- if err != nil { 48791- return span.Point{}, err 48792- } 48793- line, col8 := m.lineCol8(offset) 48794- 48795- return span.NewPoint(line+1, col8+1, offset), nil 48796-} 48797- 48798-// -- go/token domain convenience methods -- 48799- 48800-// PosPosition converts a token pos to a protocol (UTF-16) position. 48801-func (m *Mapper) PosPosition(tf *token.File, pos token.Pos) (Position, error) { 48802- offset, err := safetoken.Offset(tf, pos) 48803- if err != nil { 48804- return Position{}, err 48805- } 48806- return m.OffsetPosition(offset) 48807-} 48808- 48809-// PosLocation converts a token range to a protocol (UTF-16) location. 48810-func (m *Mapper) PosLocation(tf *token.File, start, end token.Pos) (Location, error) { 48811- startOffset, endOffset, err := safetoken.Offsets(tf, start, end) 48812- if err != nil { 48813- return Location{}, err 48814- } 48815- rng, err := m.OffsetRange(startOffset, endOffset) 48816- if err != nil { 48817- return Location{}, err 48818- } 48819- return m.RangeLocation(rng), nil 48820-} 48821- 48822-// PosRange converts a token range to a protocol (UTF-16) range. 48823-func (m *Mapper) PosRange(tf *token.File, start, end token.Pos) (Range, error) { 48824- startOffset, endOffset, err := safetoken.Offsets(tf, start, end) 48825- if err != nil { 48826- return Range{}, err 48827- } 48828- return m.OffsetRange(startOffset, endOffset) 48829-} 48830- 48831-// NodeRange converts a syntax node range to a protocol (UTF-16) range. 48832-func (m *Mapper) NodeRange(tf *token.File, node ast.Node) (Range, error) { 48833- return m.PosRange(tf, node.Pos(), node.End()) 48834-} 48835- 48836-// RangeLocation pairs a protocol Range with its URI, in a Location. 48837-func (m *Mapper) RangeLocation(rng Range) Location { 48838- return Location{URI: URIFromSpanURI(m.URI), Range: rng} 48839-} 48840- 48841-// PosMappedRange returns a MappedRange for the given token.Pos range. 48842-func (m *Mapper) PosMappedRange(tf *token.File, start, end token.Pos) (MappedRange, error) { 48843- startOffset, endOffset, err := safetoken.Offsets(tf, start, end) 48844- if err != nil { 48845- return MappedRange{}, nil 48846- } 48847- return m.OffsetMappedRange(startOffset, endOffset) 48848-} 48849- 48850-// NodeMappedRange returns a MappedRange for the given node range. 48851-func (m *Mapper) NodeMappedRange(tf *token.File, node ast.Node) (MappedRange, error) { 48852- return m.PosMappedRange(tf, node.Pos(), node.End()) 48853-} 48854- 48855-// -- MappedRange -- 48856- 48857-// A MappedRange represents a valid byte-offset range of a file. 48858-// Through its Mapper it can be converted into other forms such 48859-// as protocol.Range or span.Span. 48860-// 48861-// Construct one by calling Mapper.OffsetMappedRange with start/end offsets. 48862-// From the go/token domain, call safetoken.Offsets first, 48863-// or use a helper such as ParsedGoFile.MappedPosRange. 48864-// 48865-// Two MappedRanges produced the same Mapper are equal if and only if they 48866-// denote the same range. Two MappedRanges produced by different Mappers 48867-// are unequal even when they represent the same range of the same file. 48868-type MappedRange struct { 48869- Mapper *Mapper 48870- start, end int // valid byte offsets: 0 <= start <= end <= len(Mapper.Content) 48871-} 48872- 48873-// Offsets returns the (start, end) byte offsets of this range. 48874-func (mr MappedRange) Offsets() (start, end int) { return mr.start, mr.end } 48875- 48876-// -- convenience functions -- 48877- 48878-// URI returns the URI of the range's file. 48879-func (mr MappedRange) URI() span.URI { 48880- return mr.Mapper.URI 48881-} 48882- 48883-// Range returns the range in protocol (UTF-16) form. 48884-func (mr MappedRange) Range() Range { 48885- rng, err := mr.Mapper.OffsetRange(mr.start, mr.end) 48886- if err != nil { 48887- panic(err) // can't happen 48888- } 48889- return rng 48890-} 48891- 48892-// Location returns the range in protocol location (UTF-16) form. 48893-func (mr MappedRange) Location() Location { 48894- return mr.Mapper.RangeLocation(mr.Range()) 48895-} 48896- 48897-// Span returns the range in span (UTF-8) form. 48898-func (mr MappedRange) Span() span.Span { 48899- spn, err := mr.Mapper.OffsetSpan(mr.start, mr.end) 48900- if err != nil { 48901- panic(err) // can't happen 48902- } 48903- return spn 48904-} 48905- 48906-// String formats the range in span (UTF-8) notation. 48907-func (mr MappedRange) String() string { 48908- return fmt.Sprint(mr.Span()) 48909-} 48910- 48911-// LocationTextDocumentPositionParams converts its argument to its result. 48912-func LocationTextDocumentPositionParams(loc Location) TextDocumentPositionParams { 48913- return TextDocumentPositionParams{ 48914- TextDocument: TextDocumentIdentifier{URI: loc.URI}, 48915- Position: loc.Range.Start, 48916- } 48917-} 48918diff -urN a/gopls/internal/lsp/protocol/mapper_test.go b/gopls/internal/lsp/protocol/mapper_test.go 48919--- a/gopls/internal/lsp/protocol/mapper_test.go 2000-01-01 00:00:00.000000000 -0000 48920+++ b/gopls/internal/lsp/protocol/mapper_test.go 1970-01-01 00:00:00.000000000 +0000 48921@@ -1,441 +0,0 @@ 48922-// Copyright 2023 The Go Authors. All rights reserved. 48923-// Use of this source code is governed by a BSD-style 48924-// license that can be found in the LICENSE file. 48925- 48926-package protocol_test 48927- 48928-import ( 48929- "fmt" 48930- "strings" 48931- "testing" 48932- 48933- "golang.org/x/tools/gopls/internal/lsp/protocol" 48934- "golang.org/x/tools/gopls/internal/span" 48935-) 48936- 48937-// This file tests Mapper's logic for converting between 48938-// span.Point and UTF-16 columns. (The strange form attests to an 48939-// earlier abstraction.) 48940- 48941-// is U+10400 = [F0 90 90 80] in UTF-8, [D801 DC00] in UTF-16. 48942-var funnyString = []byte("23\n45") 48943- 48944-var toUTF16Tests = []struct { 48945- scenario string 48946- input []byte 48947- line int // 1-indexed count 48948- col int // 1-indexed byte position in line 48949- offset int // 0-indexed byte offset into input 48950- resUTF16col int // 1-indexed UTF-16 col number 48951- pre string // everything before the cursor on the line 48952- post string // everything from the cursor onwards 48953- err string // expected error string in call to ToUTF16Column 48954- issue *bool 48955-}{ 48956- { 48957- scenario: "cursor missing content", 48958- input: nil, 48959- offset: -1, 48960- err: "point has neither offset nor line/column", 48961- }, 48962- { 48963- scenario: "cursor missing position", 48964- input: funnyString, 48965- line: -1, 48966- col: -1, 48967- offset: -1, 48968- err: "point has neither offset nor line/column", 48969- }, 48970- { 48971- scenario: "zero length input; cursor at first col, first line", 48972- input: []byte(""), 48973- line: 1, 48974- col: 1, 48975- offset: 0, 48976- resUTF16col: 1, 48977- }, 48978- { 48979- scenario: "cursor before funny character; first line", 48980- input: funnyString, 48981- line: 1, 48982- col: 1, 48983- offset: 0, 48984- resUTF16col: 1, 48985- pre: "", 48986- post: "23", 48987- }, 48988- { 48989- scenario: "cursor after funny character; first line", 48990- input: funnyString, 48991- line: 1, 48992- col: 5, // 4 + 1 (1-indexed) 48993- offset: 4, // (unused since we have line+col) 48994- resUTF16col: 3, // 2 + 1 (1-indexed) 48995- pre: "", 48996- post: "23", 48997- }, 48998- { 48999- scenario: "cursor after last character on first line", 49000- input: funnyString, 49001- line: 1, 49002- col: 7, // 4 + 1 + 1 + 1 (1-indexed) 49003- offset: 6, // 4 + 1 + 1 (unused since we have line+col) 49004- resUTF16col: 5, // 2 + 1 + 1 + 1 (1-indexed) 49005- pre: "23", 49006- post: "", 49007- }, 49008- { 49009- scenario: "cursor before funny character; second line", 49010- input: funnyString, 49011- line: 2, 49012- col: 1, 49013- offset: 7, // length of first line (unused since we have line+col) 49014- resUTF16col: 1, 49015- pre: "", 49016- post: "45", 49017- }, 49018- { 49019- scenario: "cursor after funny character; second line", 49020- input: funnyString, 49021- line: 1, 49022- col: 5, // 4 + 1 (1-indexed) 49023- offset: 11, // 7 (length of first line) + 4 (unused since we have line+col) 49024- resUTF16col: 3, // 2 + 1 (1-indexed) 49025- pre: "", 49026- post: "45", 49027- }, 49028- { 49029- scenario: "cursor after last character on second line", 49030- input: funnyString, 49031- line: 2, 49032- col: 7, // 4 + 1 + 1 + 1 (1-indexed) 49033- offset: 13, // 7 (length of first line) + 4 + 1 + 1 (unused since we have line+col) 49034- resUTF16col: 5, // 2 + 1 + 1 + 1 (1-indexed) 49035- pre: "45", 49036- post: "", 49037- }, 49038- { 49039- scenario: "cursor beyond end of file", 49040- input: funnyString, 49041- line: 2, 49042- col: 8, // 4 + 1 + 1 + 1 + 1 (1-indexed) 49043- offset: 14, // 4 + 1 + 1 + 1 (unused since we have line+col) 49044- err: "column is beyond end of file", 49045- }, 49046-} 49047- 49048-var fromUTF16Tests = []struct { 49049- scenario string 49050- input []byte 49051- line int // 1-indexed line number (isn't actually used) 49052- utf16col int // 1-indexed UTF-16 col number 49053- resCol int // 1-indexed byte position in line 49054- resOffset int // 0-indexed byte offset into input 49055- pre string // everything before the cursor on the line 49056- post string // everything from the cursor onwards 49057- err string // expected error string in call to ToUTF16Column 49058-}{ 49059- { 49060- scenario: "zero length input; cursor at first col, first line", 49061- input: []byte(""), 49062- line: 1, 49063- utf16col: 1, 49064- resCol: 1, 49065- resOffset: 0, 49066- pre: "", 49067- post: "", 49068- }, 49069- { 49070- scenario: "cursor before funny character", 49071- input: funnyString, 49072- line: 1, 49073- utf16col: 1, 49074- resCol: 1, 49075- resOffset: 0, 49076- pre: "", 49077- post: "23", 49078- }, 49079- { 49080- scenario: "cursor after funny character", 49081- input: funnyString, 49082- line: 1, 49083- utf16col: 3, 49084- resCol: 5, 49085- resOffset: 4, 49086- pre: "", 49087- post: "23", 49088- }, 49089- { 49090- scenario: "cursor after last character on line", 49091- input: funnyString, 49092- line: 1, 49093- utf16col: 5, 49094- resCol: 7, 49095- resOffset: 6, 49096- pre: "23", 49097- post: "", 49098- }, 49099- { 49100- scenario: "cursor beyond last character on line", 49101- input: funnyString, 49102- line: 1, 49103- utf16col: 6, 49104- resCol: 7, 49105- resOffset: 6, 49106- pre: "23", 49107- post: "", 49108- err: "column is beyond end of line", 49109- }, 49110- { 49111- scenario: "cursor before funny character; second line", 49112- input: funnyString, 49113- line: 2, 49114- utf16col: 1, 49115- resCol: 1, 49116- resOffset: 7, 49117- pre: "", 49118- post: "45", 49119- }, 49120- { 49121- scenario: "cursor after funny character; second line", 49122- input: funnyString, 49123- line: 2, 49124- utf16col: 3, // 2 + 1 (1-indexed) 49125- resCol: 5, // 4 + 1 (1-indexed) 49126- resOffset: 11, // 7 (length of first line) + 4 49127- pre: "", 49128- post: "45", 49129- }, 49130- { 49131- scenario: "cursor after last character on second line", 49132- input: funnyString, 49133- line: 2, 49134- utf16col: 5, // 2 + 1 + 1 + 1 (1-indexed) 49135- resCol: 7, // 4 + 1 + 1 + 1 (1-indexed) 49136- resOffset: 13, // 7 (length of first line) + 4 + 1 + 1 49137- pre: "45", 49138- post: "", 49139- }, 49140- { 49141- scenario: "cursor beyond end of file", 49142- input: funnyString, 49143- line: 2, 49144- utf16col: 6, // 2 + 1 + 1 + 1 + 1(1-indexed) 49145- resCol: 8, // 4 + 1 + 1 + 1 + 1 (1-indexed) 49146- resOffset: 14, // 7 (length of first line) + 4 + 1 + 1 + 1 49147- err: "column is beyond end of file", 49148- }, 49149-} 49150- 49151-func TestToUTF16(t *testing.T) { 49152- for _, e := range toUTF16Tests { 49153- t.Run(e.scenario, func(t *testing.T) { 49154- if e.issue != nil && !*e.issue { 49155- t.Skip("expected to fail") 49156- } 49157- p := span.NewPoint(e.line, e.col, e.offset) 49158- m := protocol.NewMapper("", e.input) 49159- pos, err := m.PointPosition(p) 49160- if err != nil { 49161- if err.Error() != e.err { 49162- t.Fatalf("expected error %v; got %v", e.err, err) 49163- } 49164- return 49165- } 49166- if e.err != "" { 49167- t.Fatalf("unexpected success; wanted %v", e.err) 49168- } 49169- got := int(pos.Character) + 1 49170- if got != e.resUTF16col { 49171- t.Fatalf("expected result %v; got %v", e.resUTF16col, got) 49172- } 49173- pre, post := getPrePost(e.input, p.Offset()) 49174- if string(pre) != e.pre { 49175- t.Fatalf("expected #%d pre %q; got %q", p.Offset(), e.pre, pre) 49176- } 49177- if string(post) != e.post { 49178- t.Fatalf("expected #%d, post %q; got %q", p.Offset(), e.post, post) 49179- } 49180- }) 49181- } 49182-} 49183- 49184-func TestFromUTF16(t *testing.T) { 49185- for _, e := range fromUTF16Tests { 49186- t.Run(e.scenario, func(t *testing.T) { 49187- m := protocol.NewMapper("", []byte(e.input)) 49188- p, err := m.PositionPoint(protocol.Position{ 49189- Line: uint32(e.line - 1), 49190- Character: uint32(e.utf16col - 1), 49191- }) 49192- if err != nil { 49193- if err.Error() != e.err { 49194- t.Fatalf("expected error %v; got %v", e.err, err) 49195- } 49196- return 49197- } 49198- if e.err != "" { 49199- t.Fatalf("unexpected success; wanted %v", e.err) 49200- } 49201- if p.Column() != e.resCol { 49202- t.Fatalf("expected resulting col %v; got %v", e.resCol, p.Column()) 49203- } 49204- if p.Offset() != e.resOffset { 49205- t.Fatalf("expected resulting offset %v; got %v", e.resOffset, p.Offset()) 49206- } 49207- pre, post := getPrePost(e.input, p.Offset()) 49208- if string(pre) != e.pre { 49209- t.Fatalf("expected #%d pre %q; got %q", p.Offset(), e.pre, pre) 49210- } 49211- if string(post) != e.post { 49212- t.Fatalf("expected #%d post %q; got %q", p.Offset(), e.post, post) 49213- } 49214- }) 49215- } 49216-} 49217- 49218-func getPrePost(content []byte, offset int) (string, string) { 49219- pre, post := string(content)[:offset], string(content)[offset:] 49220- if i := strings.LastIndex(pre, "\n"); i >= 0 { 49221- pre = pre[i+1:] 49222- } 49223- if i := strings.IndexRune(post, '\n'); i >= 0 { 49224- post = post[:i] 49225- } 49226- return pre, post 49227-} 49228- 49229-// -- these are the historical lsppos tests -- 49230- 49231-type testCase struct { 49232- content string // input text 49233- substrOrOffset interface{} // explicit integer offset, or a substring 49234- wantLine, wantChar int // expected LSP position information 49235-} 49236- 49237-// offset returns the test case byte offset 49238-func (c testCase) offset() int { 49239- switch x := c.substrOrOffset.(type) { 49240- case int: 49241- return x 49242- case string: 49243- i := strings.Index(c.content, x) 49244- if i < 0 { 49245- panic(fmt.Sprintf("%q does not contain substring %q", c.content, x)) 49246- } 49247- return i 49248- } 49249- panic("substrOrIndex must be an integer or string") 49250-} 49251- 49252-var tests = []testCase{ 49253- {"ab", "a", 0, 0}, 49254- {"ab", "", 0, 1}, 49255- {"ab", "b", 0, 3}, 49256- {"ab\n", "\n", 0, 4}, 49257- {"ab\r\n", "\n", 0, 4}, // \r|\n is not a valid position, so we move back to the end of the first line. 49258- {"ab\r\nx", "x", 1, 0}, 49259- {"ab\r\nx\ny", "y", 2, 0}, 49260- 49261- // Testing EOL and EOF positions 49262- {"", 0, 0, 0}, // 0th position of an empty buffer is (0, 0) 49263- {"abc", "c", 0, 2}, 49264- {"abc", 3, 0, 3}, 49265- {"abc\n", "\n", 0, 3}, 49266- {"abc\n", 4, 1, 0}, // position after a newline is on the next line 49267-} 49268- 49269-func TestLineChar(t *testing.T) { 49270- for _, test := range tests { 49271- m := protocol.NewMapper("", []byte(test.content)) 49272- offset := test.offset() 49273- posn, _ := m.OffsetPosition(offset) 49274- gotLine, gotChar := int(posn.Line), int(posn.Character) 49275- if gotLine != test.wantLine || gotChar != test.wantChar { 49276- t.Errorf("LineChar(%d) = (%d,%d), want (%d,%d)", offset, gotLine, gotChar, test.wantLine, test.wantChar) 49277- } 49278- } 49279-} 49280- 49281-func TestInvalidOffset(t *testing.T) { 49282- content := []byte("ab\r\nx\ny") 49283- m := protocol.NewMapper("", content) 49284- for _, offset := range []int{-1, 100} { 49285- posn, err := m.OffsetPosition(offset) 49286- if err == nil { 49287- t.Errorf("OffsetPosition(%d) = %s, want error", offset, posn) 49288- } 49289- } 49290-} 49291- 49292-func TestPosition(t *testing.T) { 49293- for _, test := range tests { 49294- m := protocol.NewMapper("", []byte(test.content)) 49295- offset := test.offset() 49296- got, err := m.OffsetPosition(offset) 49297- if err != nil { 49298- t.Errorf("OffsetPosition(%d) failed: %v", offset, err) 49299- continue 49300- } 49301- want := protocol.Position{Line: uint32(test.wantLine), Character: uint32(test.wantChar)} 49302- if got != want { 49303- t.Errorf("Position(%d) = %v, want %v", offset, got, want) 49304- } 49305- } 49306-} 49307- 49308-func TestRange(t *testing.T) { 49309- for _, test := range tests { 49310- m := protocol.NewMapper("", []byte(test.content)) 49311- offset := test.offset() 49312- got, err := m.OffsetRange(0, offset) 49313- if err != nil { 49314- t.Fatal(err) 49315- } 49316- want := protocol.Range{ 49317- End: protocol.Position{Line: uint32(test.wantLine), Character: uint32(test.wantChar)}, 49318- } 49319- if got != want { 49320- t.Errorf("Range(%d) = %v, want %v", offset, got, want) 49321- } 49322- } 49323-} 49324- 49325-func TestBytesOffset(t *testing.T) { 49326- tests := []struct { 49327- text string 49328- pos protocol.Position 49329- want int 49330- }{ 49331- // U+10400 encodes as [F0 90 90 80] in UTF-8 and [D801 DC00] in UTF-16. 49332- {text: `ab`, pos: protocol.Position{Line: 0, Character: 0}, want: 0}, 49333- {text: `ab`, pos: protocol.Position{Line: 0, Character: 1}, want: 1}, 49334- {text: `ab`, pos: protocol.Position{Line: 0, Character: 2}, want: 1}, 49335- {text: `ab`, pos: protocol.Position{Line: 0, Character: 3}, want: 5}, 49336- {text: `ab`, pos: protocol.Position{Line: 0, Character: 4}, want: 6}, 49337- {text: `ab`, pos: protocol.Position{Line: 0, Character: 5}, want: -1}, 49338- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 0, Character: 3}, want: 3}, 49339- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 0, Character: 4}, want: -1}, 49340- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 1, Character: 0}, want: 4}, 49341- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 1, Character: 3}, want: 7}, 49342- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 1, Character: 4}, want: -1}, 49343- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 2, Character: 0}, want: 8}, 49344- {text: "aaa\nbbb\n", pos: protocol.Position{Line: 2, Character: 1}, want: -1}, 49345- {text: "aaa\nbbb\n\n", pos: protocol.Position{Line: 2, Character: 0}, want: 8}, 49346- } 49347- 49348- for i, test := range tests { 49349- fname := fmt.Sprintf("test %d", i) 49350- uri := span.URIFromPath(fname) 49351- mapper := protocol.NewMapper(uri, []byte(test.text)) 49352- got, err := mapper.PositionPoint(test.pos) 49353- if err != nil && test.want != -1 { 49354- t.Errorf("%d: unexpected error: %v", i, err) 49355- } 49356- if err == nil && got.Offset() != test.want { 49357- t.Errorf("want %d for %q(Line:%d,Character:%d), but got %d", test.want, test.text, int(test.pos.Line), int(test.pos.Character), got.Offset()) 49358- } 49359- } 49360-} 49361- 49362-// -- end -- 49363diff -urN a/gopls/internal/lsp/protocol/protocol.go b/gopls/internal/lsp/protocol/protocol.go 49364--- a/gopls/internal/lsp/protocol/protocol.go 2000-01-01 00:00:00.000000000 -0000 49365+++ b/gopls/internal/lsp/protocol/protocol.go 1970-01-01 00:00:00.000000000 +0000 49366@@ -1,284 +0,0 @@ 49367-// Copyright 2018 The Go Authors. All rights reserved. 49368-// Use of this source code is governed by a BSD-style 49369-// license that can be found in the LICENSE file. 49370- 49371-package protocol 49372- 49373-import ( 49374- "context" 49375- "encoding/json" 49376- "fmt" 49377- "io" 49378- 49379- "golang.org/x/tools/internal/event" 49380- "golang.org/x/tools/internal/jsonrpc2" 49381- jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 49382- "golang.org/x/tools/internal/xcontext" 49383-) 49384- 49385-var ( 49386- // RequestCancelledError should be used when a request is cancelled early. 49387- RequestCancelledError = jsonrpc2.NewError(-32800, "JSON RPC cancelled") 49388- RequestCancelledErrorV2 = jsonrpc2_v2.NewError(-32800, "JSON RPC cancelled") 49389-) 49390- 49391-type ClientCloser interface { 49392- Client 49393- io.Closer 49394-} 49395- 49396-type connSender interface { 49397- io.Closer 49398- 49399- Notify(ctx context.Context, method string, params interface{}) error 49400- Call(ctx context.Context, method string, params, result interface{}) error 49401-} 49402- 49403-type clientDispatcher struct { 49404- sender connSender 49405-} 49406- 49407-func (c *clientDispatcher) Close() error { 49408- return c.sender.Close() 49409-} 49410- 49411-// ClientDispatcher returns a Client that dispatches LSP requests across the 49412-// given jsonrpc2 connection. 49413-func ClientDispatcher(conn jsonrpc2.Conn) ClientCloser { 49414- return &clientDispatcher{sender: clientConn{conn}} 49415-} 49416- 49417-type clientConn struct { 49418- conn jsonrpc2.Conn 49419-} 49420- 49421-func (c clientConn) Close() error { 49422- return c.conn.Close() 49423-} 49424- 49425-func (c clientConn) Notify(ctx context.Context, method string, params interface{}) error { 49426- return c.conn.Notify(ctx, method, params) 49427-} 49428- 49429-func (c clientConn) Call(ctx context.Context, method string, params interface{}, result interface{}) error { 49430- id, err := c.conn.Call(ctx, method, params, result) 49431- if ctx.Err() != nil { 49432- cancelCall(ctx, c, id) 49433- } 49434- return err 49435-} 49436- 49437-func ClientDispatcherV2(conn *jsonrpc2_v2.Connection) ClientCloser { 49438- return &clientDispatcher{clientConnV2{conn}} 49439-} 49440- 49441-type clientConnV2 struct { 49442- conn *jsonrpc2_v2.Connection 49443-} 49444- 49445-func (c clientConnV2) Close() error { 49446- return c.conn.Close() 49447-} 49448- 49449-func (c clientConnV2) Notify(ctx context.Context, method string, params interface{}) error { 49450- return c.conn.Notify(ctx, method, params) 49451-} 49452- 49453-func (c clientConnV2) Call(ctx context.Context, method string, params interface{}, result interface{}) error { 49454- call := c.conn.Call(ctx, method, params) 49455- err := call.Await(ctx, result) 49456- if ctx.Err() != nil { 49457- detached := xcontext.Detach(ctx) 49458- c.conn.Notify(detached, "$/cancelRequest", &CancelParams{ID: call.ID().Raw()}) 49459- } 49460- return err 49461-} 49462- 49463-// ServerDispatcher returns a Server that dispatches LSP requests across the 49464-// given jsonrpc2 connection. 49465-func ServerDispatcher(conn jsonrpc2.Conn) Server { 49466- return &serverDispatcher{sender: clientConn{conn}} 49467-} 49468- 49469-func ServerDispatcherV2(conn *jsonrpc2_v2.Connection) Server { 49470- return &serverDispatcher{sender: clientConnV2{conn}} 49471-} 49472- 49473-type serverDispatcher struct { 49474- sender connSender 49475-} 49476- 49477-func ClientHandler(client Client, handler jsonrpc2.Handler) jsonrpc2.Handler { 49478- return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { 49479- if ctx.Err() != nil { 49480- ctx := xcontext.Detach(ctx) 49481- return reply(ctx, nil, RequestCancelledError) 49482- } 49483- handled, err := clientDispatch(ctx, client, reply, req) 49484- if handled || err != nil { 49485- return err 49486- } 49487- return handler(ctx, reply, req) 49488- } 49489-} 49490- 49491-func ClientHandlerV2(client Client) jsonrpc2_v2.Handler { 49492- return jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 49493- if ctx.Err() != nil { 49494- return nil, RequestCancelledErrorV2 49495- } 49496- req1 := req2to1(req) 49497- var ( 49498- result interface{} 49499- resErr error 49500- ) 49501- replier := func(_ context.Context, res interface{}, err error) error { 49502- if err != nil { 49503- resErr = err 49504- return nil 49505- } 49506- result = res 49507- return nil 49508- } 49509- _, err := clientDispatch(ctx, client, replier, req1) 49510- if err != nil { 49511- return nil, err 49512- } 49513- return result, resErr 49514- }) 49515-} 49516- 49517-func ServerHandler(server Server, handler jsonrpc2.Handler) jsonrpc2.Handler { 49518- return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { 49519- if ctx.Err() != nil { 49520- ctx := xcontext.Detach(ctx) 49521- return reply(ctx, nil, RequestCancelledError) 49522- } 49523- handled, err := serverDispatch(ctx, server, reply, req) 49524- if handled || err != nil { 49525- return err 49526- } 49527- //TODO: This code is wrong, it ignores handler and assumes non standard 49528- // request handles everything 49529- // non standard request should just be a layered handler. 49530- var params interface{} 49531- if err := json.Unmarshal(req.Params(), ¶ms); err != nil { 49532- return sendParseError(ctx, reply, err) 49533- } 49534- resp, err := server.NonstandardRequest(ctx, req.Method(), params) 49535- return reply(ctx, resp, err) 49536- 49537- } 49538-} 49539- 49540-func ServerHandlerV2(server Server) jsonrpc2_v2.Handler { 49541- return jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 49542- if ctx.Err() != nil { 49543- return nil, RequestCancelledErrorV2 49544- } 49545- req1 := req2to1(req) 49546- var ( 49547- result interface{} 49548- resErr error 49549- ) 49550- replier := func(_ context.Context, res interface{}, err error) error { 49551- if err != nil { 49552- resErr = err 49553- return nil 49554- } 49555- result = res 49556- return nil 49557- } 49558- _, err := serverDispatch(ctx, server, replier, req1) 49559- if err != nil { 49560- return nil, err 49561- } 49562- return result, resErr 49563- }) 49564-} 49565- 49566-func req2to1(req2 *jsonrpc2_v2.Request) jsonrpc2.Request { 49567- if req2.ID.IsValid() { 49568- raw := req2.ID.Raw() 49569- var idv1 jsonrpc2.ID 49570- switch v := raw.(type) { 49571- case int64: 49572- idv1 = jsonrpc2.NewIntID(v) 49573- case string: 49574- idv1 = jsonrpc2.NewStringID(v) 49575- default: 49576- panic(fmt.Sprintf("unsupported ID type %T", raw)) 49577- } 49578- req1, err := jsonrpc2.NewCall(idv1, req2.Method, req2.Params) 49579- if err != nil { 49580- panic(err) 49581- } 49582- return req1 49583- } 49584- req1, err := jsonrpc2.NewNotification(req2.Method, req2.Params) 49585- if err != nil { 49586- panic(err) 49587- } 49588- return req1 49589-} 49590- 49591-func Handlers(handler jsonrpc2.Handler) jsonrpc2.Handler { 49592- return CancelHandler( 49593- jsonrpc2.AsyncHandler( 49594- jsonrpc2.MustReplyHandler(handler))) 49595-} 49596- 49597-func CancelHandler(handler jsonrpc2.Handler) jsonrpc2.Handler { 49598- handler, canceller := jsonrpc2.CancelHandler(handler) 49599- return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { 49600- if req.Method() != "$/cancelRequest" { 49601- // TODO(iancottrell): See if we can generate a reply for the request to be cancelled 49602- // at the point of cancellation rather than waiting for gopls to naturally reply. 49603- // To do that, we need to keep track of whether a reply has been sent already and 49604- // be careful about racing between the two paths. 49605- // TODO(iancottrell): Add a test that watches the stream and verifies the response 49606- // for the cancelled request flows. 49607- replyWithDetachedContext := func(ctx context.Context, resp interface{}, err error) error { 49608- // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest 49609- if ctx.Err() != nil && err == nil { 49610- err = RequestCancelledError 49611- } 49612- ctx = xcontext.Detach(ctx) 49613- return reply(ctx, resp, err) 49614- } 49615- return handler(ctx, replyWithDetachedContext, req) 49616- } 49617- var params CancelParams 49618- if err := json.Unmarshal(req.Params(), ¶ms); err != nil { 49619- return sendParseError(ctx, reply, err) 49620- } 49621- if n, ok := params.ID.(float64); ok { 49622- canceller(jsonrpc2.NewIntID(int64(n))) 49623- } else if s, ok := params.ID.(string); ok { 49624- canceller(jsonrpc2.NewStringID(s)) 49625- } else { 49626- return sendParseError(ctx, reply, fmt.Errorf("request ID %v malformed", params.ID)) 49627- } 49628- return reply(ctx, nil, nil) 49629- } 49630-} 49631- 49632-func Call(ctx context.Context, conn jsonrpc2.Conn, method string, params interface{}, result interface{}) error { 49633- id, err := conn.Call(ctx, method, params, result) 49634- if ctx.Err() != nil { 49635- cancelCall(ctx, clientConn{conn}, id) 49636- } 49637- return err 49638-} 49639- 49640-func cancelCall(ctx context.Context, sender connSender, id jsonrpc2.ID) { 49641- ctx = xcontext.Detach(ctx) 49642- ctx, done := event.Start(ctx, "protocol.canceller") 49643- defer done() 49644- // Note that only *jsonrpc2.ID implements json.Marshaler. 49645- sender.Notify(ctx, "$/cancelRequest", &CancelParams{ID: &id}) 49646-} 49647- 49648-func sendParseError(ctx context.Context, reply jsonrpc2.Replier, err error) error { 49649- return reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)) 49650-} 49651diff -urN a/gopls/internal/lsp/protocol/span.go b/gopls/internal/lsp/protocol/span.go 49652--- a/gopls/internal/lsp/protocol/span.go 2000-01-01 00:00:00.000000000 -0000 49653+++ b/gopls/internal/lsp/protocol/span.go 1970-01-01 00:00:00.000000000 +0000 49654@@ -1,118 +0,0 @@ 49655-// Copyright 2018 The Go Authors. All rights reserved. 49656-// Use of this source code is governed by a BSD-style 49657-// license that can be found in the LICENSE file. 49658- 49659-package protocol 49660- 49661-import ( 49662- "fmt" 49663- "unicode/utf8" 49664- 49665- "golang.org/x/tools/gopls/internal/span" 49666-) 49667- 49668-func URIFromSpanURI(uri span.URI) DocumentURI { 49669- return DocumentURI(uri) // simple conversion 49670-} 49671- 49672-func URIFromPath(path string) DocumentURI { 49673- return URIFromSpanURI(span.URIFromPath(path)) // normalizing conversion 49674-} 49675- 49676-func (u DocumentURI) SpanURI() span.URI { 49677- return span.URIFromURI(string(u)) // normalizing conversion 49678-} 49679- 49680-func IsPoint(r Range) bool { 49681- return r.Start.Line == r.End.Line && r.Start.Character == r.End.Character 49682-} 49683- 49684-// CompareLocation defines a three-valued comparison over locations, 49685-// lexicographically ordered by (URI, Range). 49686-func CompareLocation(x, y Location) int { 49687- if x.URI != y.URI { 49688- if x.URI < y.URI { 49689- return -1 49690- } else { 49691- return +1 49692- } 49693- } 49694- return CompareRange(x.Range, y.Range) 49695-} 49696- 49697-// CompareRange returns -1 if a is before b, 0 if a == b, and 1 if a is after b. 49698-// 49699-// A range a is defined to be 'before' b if a.Start is before b.Start, or 49700-// a.Start == b.Start and a.End is before b.End. 49701-func CompareRange(a, b Range) int { 49702- if r := ComparePosition(a.Start, b.Start); r != 0 { 49703- return r 49704- } 49705- return ComparePosition(a.End, b.End) 49706-} 49707- 49708-// ComparePosition returns -1 if a is before b, 0 if a == b, and 1 if a is after b. 49709-func ComparePosition(a, b Position) int { 49710- if a.Line != b.Line { 49711- if a.Line < b.Line { 49712- return -1 49713- } else { 49714- return +1 49715- } 49716- } 49717- if a.Character != b.Character { 49718- if a.Character < b.Character { 49719- return -1 49720- } else { 49721- return +1 49722- } 49723- } 49724- return 0 49725-} 49726- 49727-func Intersect(a, b Range) bool { 49728- if a.Start.Line > b.End.Line || a.End.Line < b.Start.Line { 49729- return false 49730- } 49731- return !((a.Start.Line == b.End.Line) && a.Start.Character > b.End.Character || 49732- (a.End.Line == b.Start.Line) && a.End.Character < b.Start.Character) 49733-} 49734- 49735-// Format implements fmt.Formatter. 49736-// 49737-// Note: Formatter is implemented instead of Stringer (presumably) for 49738-// performance reasons, though it is not clear that it matters in practice. 49739-func (r Range) Format(f fmt.State, _ rune) { 49740- fmt.Fprintf(f, "%v-%v", r.Start, r.End) 49741-} 49742- 49743-// Format implements fmt.Formatter. 49744-// 49745-// See Range.Format for discussion of why the Formatter interface is 49746-// implemented rather than Stringer. 49747-func (p Position) Format(f fmt.State, _ rune) { 49748- fmt.Fprintf(f, "%v:%v", p.Line, p.Character) 49749-} 49750- 49751-// -- implementation helpers -- 49752- 49753-// UTF16Len returns the number of codes in the UTF-16 transcoding of s. 49754-func UTF16Len(s []byte) int { 49755- var n int 49756- for len(s) > 0 { 49757- n++ 49758- 49759- // Fast path for ASCII. 49760- if s[0] < 0x80 { 49761- s = s[1:] 49762- continue 49763- } 49764- 49765- r, size := utf8.DecodeRune(s) 49766- if r >= 0x10000 { 49767- n++ // surrogate pair 49768- } 49769- s = s[size:] 49770- } 49771- return n 49772-} 49773diff -urN a/gopls/internal/lsp/protocol/tsclient.go b/gopls/internal/lsp/protocol/tsclient.go 49774--- a/gopls/internal/lsp/protocol/tsclient.go 2000-01-01 00:00:00.000000000 -0000 49775+++ b/gopls/internal/lsp/protocol/tsclient.go 1970-01-01 00:00:00.000000000 +0000 49776@@ -1,249 +0,0 @@ 49777-// Copyright 2023 The Go Authors. All rights reserved. 49778-// Use of this source code is governed by a BSD-style 49779-// license that can be found in the LICENSE file. 49780- 49781-// Code generated for LSP. DO NOT EDIT. 49782- 49783-package protocol 49784- 49785-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f). 49786-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json 49787-// LSP metaData.version = 3.17.0. 49788- 49789-import ( 49790- "context" 49791- "encoding/json" 49792- 49793- "golang.org/x/tools/internal/jsonrpc2" 49794-) 49795- 49796-type Client interface { 49797- LogTrace(context.Context, *LogTraceParams) error // $/logTrace 49798- Progress(context.Context, *ProgressParams) error // $/progress 49799- RegisterCapability(context.Context, *RegistrationParams) error // client/registerCapability 49800- UnregisterCapability(context.Context, *UnregistrationParams) error // client/unregisterCapability 49801- Event(context.Context, *interface{}) error // telemetry/event 49802- PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error // textDocument/publishDiagnostics 49803- LogMessage(context.Context, *LogMessageParams) error // window/logMessage 49804- ShowDocument(context.Context, *ShowDocumentParams) (*ShowDocumentResult, error) // window/showDocument 49805- ShowMessage(context.Context, *ShowMessageParams) error // window/showMessage 49806- ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem, error) // window/showMessageRequest 49807- WorkDoneProgressCreate(context.Context, *WorkDoneProgressCreateParams) error // window/workDoneProgress/create 49808- ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResult, error) // workspace/applyEdit 49809- CodeLensRefresh(context.Context) error // workspace/codeLens/refresh 49810- Configuration(context.Context, *ParamConfiguration) ([]LSPAny, error) // workspace/configuration 49811- DiagnosticRefresh(context.Context) error // workspace/diagnostic/refresh 49812- InlayHintRefresh(context.Context) error // workspace/inlayHint/refresh 49813- InlineValueRefresh(context.Context) error // workspace/inlineValue/refresh 49814- SemanticTokensRefresh(context.Context) error // workspace/semanticTokens/refresh 49815- WorkspaceFolders(context.Context) ([]WorkspaceFolder, error) // workspace/workspaceFolders 49816-} 49817- 49818-func clientDispatch(ctx context.Context, client Client, reply jsonrpc2.Replier, r jsonrpc2.Request) (bool, error) { 49819- switch r.Method() { 49820- case "$/logTrace": 49821- var params LogTraceParams 49822- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49823- return true, sendParseError(ctx, reply, err) 49824- } 49825- err := client.LogTrace(ctx, ¶ms) 49826- return true, reply(ctx, nil, err) 49827- case "$/progress": 49828- var params ProgressParams 49829- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49830- return true, sendParseError(ctx, reply, err) 49831- } 49832- err := client.Progress(ctx, ¶ms) 49833- return true, reply(ctx, nil, err) 49834- case "client/registerCapability": 49835- var params RegistrationParams 49836- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49837- return true, sendParseError(ctx, reply, err) 49838- } 49839- err := client.RegisterCapability(ctx, ¶ms) 49840- return true, reply(ctx, nil, err) 49841- case "client/unregisterCapability": 49842- var params UnregistrationParams 49843- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49844- return true, sendParseError(ctx, reply, err) 49845- } 49846- err := client.UnregisterCapability(ctx, ¶ms) 49847- return true, reply(ctx, nil, err) 49848- case "telemetry/event": 49849- var params interface{} 49850- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49851- return true, sendParseError(ctx, reply, err) 49852- } 49853- err := client.Event(ctx, ¶ms) 49854- return true, reply(ctx, nil, err) 49855- case "textDocument/publishDiagnostics": 49856- var params PublishDiagnosticsParams 49857- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49858- return true, sendParseError(ctx, reply, err) 49859- } 49860- err := client.PublishDiagnostics(ctx, ¶ms) 49861- return true, reply(ctx, nil, err) 49862- case "window/logMessage": 49863- var params LogMessageParams 49864- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49865- return true, sendParseError(ctx, reply, err) 49866- } 49867- err := client.LogMessage(ctx, ¶ms) 49868- return true, reply(ctx, nil, err) 49869- case "window/showDocument": 49870- var params ShowDocumentParams 49871- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49872- return true, sendParseError(ctx, reply, err) 49873- } 49874- resp, err := client.ShowDocument(ctx, ¶ms) 49875- if err != nil { 49876- return true, reply(ctx, nil, err) 49877- } 49878- return true, reply(ctx, resp, nil) 49879- case "window/showMessage": 49880- var params ShowMessageParams 49881- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49882- return true, sendParseError(ctx, reply, err) 49883- } 49884- err := client.ShowMessage(ctx, ¶ms) 49885- return true, reply(ctx, nil, err) 49886- case "window/showMessageRequest": 49887- var params ShowMessageRequestParams 49888- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49889- return true, sendParseError(ctx, reply, err) 49890- } 49891- resp, err := client.ShowMessageRequest(ctx, ¶ms) 49892- if err != nil { 49893- return true, reply(ctx, nil, err) 49894- } 49895- return true, reply(ctx, resp, nil) 49896- case "window/workDoneProgress/create": 49897- var params WorkDoneProgressCreateParams 49898- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49899- return true, sendParseError(ctx, reply, err) 49900- } 49901- err := client.WorkDoneProgressCreate(ctx, ¶ms) 49902- return true, reply(ctx, nil, err) 49903- case "workspace/applyEdit": 49904- var params ApplyWorkspaceEditParams 49905- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49906- return true, sendParseError(ctx, reply, err) 49907- } 49908- resp, err := client.ApplyEdit(ctx, ¶ms) 49909- if err != nil { 49910- return true, reply(ctx, nil, err) 49911- } 49912- return true, reply(ctx, resp, nil) 49913- case "workspace/codeLens/refresh": 49914- err := client.CodeLensRefresh(ctx) 49915- return true, reply(ctx, nil, err) 49916- case "workspace/configuration": 49917- var params ParamConfiguration 49918- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 49919- return true, sendParseError(ctx, reply, err) 49920- } 49921- resp, err := client.Configuration(ctx, ¶ms) 49922- if err != nil { 49923- return true, reply(ctx, nil, err) 49924- } 49925- return true, reply(ctx, resp, nil) 49926- case "workspace/diagnostic/refresh": 49927- err := client.DiagnosticRefresh(ctx) 49928- return true, reply(ctx, nil, err) 49929- case "workspace/inlayHint/refresh": 49930- err := client.InlayHintRefresh(ctx) 49931- return true, reply(ctx, nil, err) 49932- case "workspace/inlineValue/refresh": 49933- err := client.InlineValueRefresh(ctx) 49934- return true, reply(ctx, nil, err) 49935- case "workspace/semanticTokens/refresh": 49936- err := client.SemanticTokensRefresh(ctx) 49937- return true, reply(ctx, nil, err) 49938- case "workspace/workspaceFolders": 49939- resp, err := client.WorkspaceFolders(ctx) 49940- if err != nil { 49941- return true, reply(ctx, nil, err) 49942- } 49943- return true, reply(ctx, resp, nil) 49944- default: 49945- return false, nil 49946- } 49947-} 49948- 49949-func (s *clientDispatcher) LogTrace(ctx context.Context, params *LogTraceParams) error { 49950- return s.sender.Notify(ctx, "$/logTrace", params) 49951-} 49952-func (s *clientDispatcher) Progress(ctx context.Context, params *ProgressParams) error { 49953- return s.sender.Notify(ctx, "$/progress", params) 49954-} 49955-func (s *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error { 49956- return s.sender.Call(ctx, "client/registerCapability", params, nil) 49957-} 49958-func (s *clientDispatcher) UnregisterCapability(ctx context.Context, params *UnregistrationParams) error { 49959- return s.sender.Call(ctx, "client/unregisterCapability", params, nil) 49960-} 49961-func (s *clientDispatcher) Event(ctx context.Context, params *interface{}) error { 49962- return s.sender.Notify(ctx, "telemetry/event", params) 49963-} 49964-func (s *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error { 49965- return s.sender.Notify(ctx, "textDocument/publishDiagnostics", params) 49966-} 49967-func (s *clientDispatcher) LogMessage(ctx context.Context, params *LogMessageParams) error { 49968- return s.sender.Notify(ctx, "window/logMessage", params) 49969-} 49970-func (s *clientDispatcher) ShowDocument(ctx context.Context, params *ShowDocumentParams) (*ShowDocumentResult, error) { 49971- var result *ShowDocumentResult 49972- if err := s.sender.Call(ctx, "window/showDocument", params, &result); err != nil { 49973- return nil, err 49974- } 49975- return result, nil 49976-} 49977-func (s *clientDispatcher) ShowMessage(ctx context.Context, params *ShowMessageParams) error { 49978- return s.sender.Notify(ctx, "window/showMessage", params) 49979-} 49980-func (s *clientDispatcher) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (*MessageActionItem, error) { 49981- var result *MessageActionItem 49982- if err := s.sender.Call(ctx, "window/showMessageRequest", params, &result); err != nil { 49983- return nil, err 49984- } 49985- return result, nil 49986-} 49987-func (s *clientDispatcher) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) error { 49988- return s.sender.Call(ctx, "window/workDoneProgress/create", params, nil) 49989-} 49990-func (s *clientDispatcher) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResult, error) { 49991- var result *ApplyWorkspaceEditResult 49992- if err := s.sender.Call(ctx, "workspace/applyEdit", params, &result); err != nil { 49993- return nil, err 49994- } 49995- return result, nil 49996-} 49997-func (s *clientDispatcher) CodeLensRefresh(ctx context.Context) error { 49998- return s.sender.Call(ctx, "workspace/codeLens/refresh", nil, nil) 49999-} 50000-func (s *clientDispatcher) Configuration(ctx context.Context, params *ParamConfiguration) ([]LSPAny, error) { 50001- var result []LSPAny 50002- if err := s.sender.Call(ctx, "workspace/configuration", params, &result); err != nil { 50003- return nil, err 50004- } 50005- return result, nil 50006-} 50007-func (s *clientDispatcher) DiagnosticRefresh(ctx context.Context) error { 50008- return s.sender.Call(ctx, "workspace/diagnostic/refresh", nil, nil) 50009-} 50010-func (s *clientDispatcher) InlayHintRefresh(ctx context.Context) error { 50011- return s.sender.Call(ctx, "workspace/inlayHint/refresh", nil, nil) 50012-} 50013-func (s *clientDispatcher) InlineValueRefresh(ctx context.Context) error { 50014- return s.sender.Call(ctx, "workspace/inlineValue/refresh", nil, nil) 50015-} 50016-func (s *clientDispatcher) SemanticTokensRefresh(ctx context.Context) error { 50017- return s.sender.Call(ctx, "workspace/semanticTokens/refresh", nil, nil) 50018-} 50019-func (s *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder, error) { 50020- var result []WorkspaceFolder 50021- if err := s.sender.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil { 50022- return nil, err 50023- } 50024- return result, nil 50025-} 50026diff -urN a/gopls/internal/lsp/protocol/tsdocument_changes.go b/gopls/internal/lsp/protocol/tsdocument_changes.go 50027--- a/gopls/internal/lsp/protocol/tsdocument_changes.go 2000-01-01 00:00:00.000000000 -0000 50028+++ b/gopls/internal/lsp/protocol/tsdocument_changes.go 1970-01-01 00:00:00.000000000 +0000 50029@@ -1,42 +0,0 @@ 50030-// Copyright 2022 The Go Authors. All rights reserved. 50031-// Use of this source code is governed by a BSD-style 50032-// license that can be found in the LICENSE file. 50033- 50034-package protocol 50035- 50036-import ( 50037- "encoding/json" 50038- "fmt" 50039-) 50040- 50041-// DocumentChanges is a union of a file edit and directory rename operations 50042-// for package renaming feature. At most one field of this struct is non-nil. 50043-type DocumentChanges struct { 50044- TextDocumentEdit *TextDocumentEdit 50045- RenameFile *RenameFile 50046-} 50047- 50048-func (d *DocumentChanges) UnmarshalJSON(data []byte) error { 50049- var m map[string]interface{} 50050- 50051- if err := json.Unmarshal(data, &m); err != nil { 50052- return err 50053- } 50054- 50055- if _, ok := m["textDocument"]; ok { 50056- d.TextDocumentEdit = new(TextDocumentEdit) 50057- return json.Unmarshal(data, d.TextDocumentEdit) 50058- } 50059- 50060- d.RenameFile = new(RenameFile) 50061- return json.Unmarshal(data, d.RenameFile) 50062-} 50063- 50064-func (d *DocumentChanges) MarshalJSON() ([]byte, error) { 50065- if d.TextDocumentEdit != nil { 50066- return json.Marshal(d.TextDocumentEdit) 50067- } else if d.RenameFile != nil { 50068- return json.Marshal(d.RenameFile) 50069- } 50070- return nil, fmt.Errorf("Empty DocumentChanges union value") 50071-} 50072diff -urN a/gopls/internal/lsp/protocol/tsjson.go b/gopls/internal/lsp/protocol/tsjson.go 50073--- a/gopls/internal/lsp/protocol/tsjson.go 2000-01-01 00:00:00.000000000 -0000 50074+++ b/gopls/internal/lsp/protocol/tsjson.go 1970-01-01 00:00:00.000000000 +0000 50075@@ -1,1997 +0,0 @@ 50076-// Copyright 2023 The Go Authors. All rights reserved. 50077-// Use of this source code is governed by a BSD-style 50078-// license that can be found in the LICENSE file. 50079- 50080-// Code generated for LSP. DO NOT EDIT. 50081- 50082-package protocol 50083- 50084-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f). 50085-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json 50086-// LSP metaData.version = 3.17.0. 50087- 50088-import "encoding/json" 50089- 50090-import "fmt" 50091- 50092-// UnmarshalError indicates that a JSON value did not conform to 50093-// one of the expected cases of an LSP union type. 50094-type UnmarshalError struct { 50095- msg string 50096-} 50097- 50098-func (e UnmarshalError) Error() string { 50099- return e.msg 50100-} 50101- 50102-// from line 4769 50103-func (t OrFEditRangePItemDefaults) MarshalJSON() ([]byte, error) { 50104- switch x := t.Value.(type) { 50105- case FEditRangePItemDefaults: 50106- return json.Marshal(x) 50107- case Range: 50108- return json.Marshal(x) 50109- case nil: 50110- return []byte("null"), nil 50111- } 50112- return nil, fmt.Errorf("type %T not one of [FEditRangePItemDefaults Range]", t) 50113-} 50114- 50115-func (t *OrFEditRangePItemDefaults) UnmarshalJSON(x []byte) error { 50116- if string(x) == "null" { 50117- t.Value = nil 50118- return nil 50119- } 50120- var h0 FEditRangePItemDefaults 50121- if err := json.Unmarshal(x, &h0); err == nil { 50122- t.Value = h0 50123- return nil 50124- } 50125- var h1 Range 50126- if err := json.Unmarshal(x, &h1); err == nil { 50127- t.Value = h1 50128- return nil 50129- } 50130- return &UnmarshalError{"unmarshal failed to match one of [FEditRangePItemDefaults Range]"} 50131-} 50132- 50133-// from line 9811 50134-func (t OrFNotebookPNotebookSelector) MarshalJSON() ([]byte, error) { 50135- switch x := t.Value.(type) { 50136- case NotebookDocumentFilter: 50137- return json.Marshal(x) 50138- case string: 50139- return json.Marshal(x) 50140- case nil: 50141- return []byte("null"), nil 50142- } 50143- return nil, fmt.Errorf("type %T not one of [NotebookDocumentFilter string]", t) 50144-} 50145- 50146-func (t *OrFNotebookPNotebookSelector) UnmarshalJSON(x []byte) error { 50147- if string(x) == "null" { 50148- t.Value = nil 50149- return nil 50150- } 50151- var h0 NotebookDocumentFilter 50152- if err := json.Unmarshal(x, &h0); err == nil { 50153- t.Value = h0 50154- return nil 50155- } 50156- var h1 string 50157- if err := json.Unmarshal(x, &h1); err == nil { 50158- t.Value = h1 50159- return nil 50160- } 50161- return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentFilter string]"} 50162-} 50163- 50164-// from line 5520 50165-func (t OrPLocation_workspace_symbol) MarshalJSON() ([]byte, error) { 50166- switch x := t.Value.(type) { 50167- case Location: 50168- return json.Marshal(x) 50169- case PLocationMsg_workspace_symbol: 50170- return json.Marshal(x) 50171- case nil: 50172- return []byte("null"), nil 50173- } 50174- return nil, fmt.Errorf("type %T not one of [Location PLocationMsg_workspace_symbol]", t) 50175-} 50176- 50177-func (t *OrPLocation_workspace_symbol) UnmarshalJSON(x []byte) error { 50178- if string(x) == "null" { 50179- t.Value = nil 50180- return nil 50181- } 50182- var h0 Location 50183- if err := json.Unmarshal(x, &h0); err == nil { 50184- t.Value = h0 50185- return nil 50186- } 50187- var h1 PLocationMsg_workspace_symbol 50188- if err := json.Unmarshal(x, &h1); err == nil { 50189- t.Value = h1 50190- return nil 50191- } 50192- return &UnmarshalError{"unmarshal failed to match one of [Location PLocationMsg_workspace_symbol]"} 50193-} 50194- 50195-// from line 4163 50196-func (t OrPSection_workspace_didChangeConfiguration) MarshalJSON() ([]byte, error) { 50197- switch x := t.Value.(type) { 50198- case []string: 50199- return json.Marshal(x) 50200- case string: 50201- return json.Marshal(x) 50202- case nil: 50203- return []byte("null"), nil 50204- } 50205- return nil, fmt.Errorf("type %T not one of [[]string string]", t) 50206-} 50207- 50208-func (t *OrPSection_workspace_didChangeConfiguration) UnmarshalJSON(x []byte) error { 50209- if string(x) == "null" { 50210- t.Value = nil 50211- return nil 50212- } 50213- var h0 []string 50214- if err := json.Unmarshal(x, &h0); err == nil { 50215- t.Value = h0 50216- return nil 50217- } 50218- var h1 string 50219- if err := json.Unmarshal(x, &h1); err == nil { 50220- t.Value = h1 50221- return nil 50222- } 50223- return &UnmarshalError{"unmarshal failed to match one of [[]string string]"} 50224-} 50225- 50226-// from line 7075 50227-func (t OrPTooltipPLabel) MarshalJSON() ([]byte, error) { 50228- switch x := t.Value.(type) { 50229- case MarkupContent: 50230- return json.Marshal(x) 50231- case string: 50232- return json.Marshal(x) 50233- case nil: 50234- return []byte("null"), nil 50235- } 50236- return nil, fmt.Errorf("type %T not one of [MarkupContent string]", t) 50237-} 50238- 50239-func (t *OrPTooltipPLabel) UnmarshalJSON(x []byte) error { 50240- if string(x) == "null" { 50241- t.Value = nil 50242- return nil 50243- } 50244- var h0 MarkupContent 50245- if err := json.Unmarshal(x, &h0); err == nil { 50246- t.Value = h0 50247- return nil 50248- } 50249- var h1 string 50250- if err := json.Unmarshal(x, &h1); err == nil { 50251- t.Value = h1 50252- return nil 50253- } 50254- return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"} 50255-} 50256- 50257-// from line 3699 50258-func (t OrPTooltip_textDocument_inlayHint) MarshalJSON() ([]byte, error) { 50259- switch x := t.Value.(type) { 50260- case MarkupContent: 50261- return json.Marshal(x) 50262- case string: 50263- return json.Marshal(x) 50264- case nil: 50265- return []byte("null"), nil 50266- } 50267- return nil, fmt.Errorf("type %T not one of [MarkupContent string]", t) 50268-} 50269- 50270-func (t *OrPTooltip_textDocument_inlayHint) UnmarshalJSON(x []byte) error { 50271- if string(x) == "null" { 50272- t.Value = nil 50273- return nil 50274- } 50275- var h0 MarkupContent 50276- if err := json.Unmarshal(x, &h0); err == nil { 50277- t.Value = h0 50278- return nil 50279- } 50280- var h1 string 50281- if err := json.Unmarshal(x, &h1); err == nil { 50282- t.Value = h1 50283- return nil 50284- } 50285- return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"} 50286-} 50287- 50288-// from line 6184 50289-func (t Or_CancelParams_id) MarshalJSON() ([]byte, error) { 50290- switch x := t.Value.(type) { 50291- case int32: 50292- return json.Marshal(x) 50293- case string: 50294- return json.Marshal(x) 50295- case nil: 50296- return []byte("null"), nil 50297- } 50298- return nil, fmt.Errorf("type %T not one of [int32 string]", t) 50299-} 50300- 50301-func (t *Or_CancelParams_id) UnmarshalJSON(x []byte) error { 50302- if string(x) == "null" { 50303- t.Value = nil 50304- return nil 50305- } 50306- var h0 int32 50307- if err := json.Unmarshal(x, &h0); err == nil { 50308- t.Value = h0 50309- return nil 50310- } 50311- var h1 string 50312- if err := json.Unmarshal(x, &h1); err == nil { 50313- t.Value = h1 50314- return nil 50315- } 50316- return &UnmarshalError{"unmarshal failed to match one of [int32 string]"} 50317-} 50318- 50319-// from line 4582 50320-func (t Or_CompletionItem_documentation) MarshalJSON() ([]byte, error) { 50321- switch x := t.Value.(type) { 50322- case MarkupContent: 50323- return json.Marshal(x) 50324- case string: 50325- return json.Marshal(x) 50326- case nil: 50327- return []byte("null"), nil 50328- } 50329- return nil, fmt.Errorf("type %T not one of [MarkupContent string]", t) 50330-} 50331- 50332-func (t *Or_CompletionItem_documentation) UnmarshalJSON(x []byte) error { 50333- if string(x) == "null" { 50334- t.Value = nil 50335- return nil 50336- } 50337- var h0 MarkupContent 50338- if err := json.Unmarshal(x, &h0); err == nil { 50339- t.Value = h0 50340- return nil 50341- } 50342- var h1 string 50343- if err := json.Unmarshal(x, &h1); err == nil { 50344- t.Value = h1 50345- return nil 50346- } 50347- return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"} 50348-} 50349- 50350-// from line 4665 50351-func (t Or_CompletionItem_textEdit) MarshalJSON() ([]byte, error) { 50352- switch x := t.Value.(type) { 50353- case InsertReplaceEdit: 50354- return json.Marshal(x) 50355- case TextEdit: 50356- return json.Marshal(x) 50357- case nil: 50358- return []byte("null"), nil 50359- } 50360- return nil, fmt.Errorf("type %T not one of [InsertReplaceEdit TextEdit]", t) 50361-} 50362- 50363-func (t *Or_CompletionItem_textEdit) UnmarshalJSON(x []byte) error { 50364- if string(x) == "null" { 50365- t.Value = nil 50366- return nil 50367- } 50368- var h0 InsertReplaceEdit 50369- if err := json.Unmarshal(x, &h0); err == nil { 50370- t.Value = h0 50371- return nil 50372- } 50373- var h1 TextEdit 50374- if err := json.Unmarshal(x, &h1); err == nil { 50375- t.Value = h1 50376- return nil 50377- } 50378- return &UnmarshalError{"unmarshal failed to match one of [InsertReplaceEdit TextEdit]"} 50379-} 50380- 50381-// from line 13753 50382-func (t Or_Definition) MarshalJSON() ([]byte, error) { 50383- switch x := t.Value.(type) { 50384- case Location: 50385- return json.Marshal(x) 50386- case []Location: 50387- return json.Marshal(x) 50388- case nil: 50389- return []byte("null"), nil 50390- } 50391- return nil, fmt.Errorf("type %T not one of [Location []Location]", t) 50392-} 50393- 50394-func (t *Or_Definition) UnmarshalJSON(x []byte) error { 50395- if string(x) == "null" { 50396- t.Value = nil 50397- return nil 50398- } 50399- var h0 Location 50400- if err := json.Unmarshal(x, &h0); err == nil { 50401- t.Value = h0 50402- return nil 50403- } 50404- var h1 []Location 50405- if err := json.Unmarshal(x, &h1); err == nil { 50406- t.Value = h1 50407- return nil 50408- } 50409- return &UnmarshalError{"unmarshal failed to match one of [Location []Location]"} 50410-} 50411- 50412-// from line 8547 50413-func (t Or_Diagnostic_code) MarshalJSON() ([]byte, error) { 50414- switch x := t.Value.(type) { 50415- case int32: 50416- return json.Marshal(x) 50417- case string: 50418- return json.Marshal(x) 50419- case nil: 50420- return []byte("null"), nil 50421- } 50422- return nil, fmt.Errorf("type %T not one of [int32 string]", t) 50423-} 50424- 50425-func (t *Or_Diagnostic_code) UnmarshalJSON(x []byte) error { 50426- if string(x) == "null" { 50427- t.Value = nil 50428- return nil 50429- } 50430- var h0 int32 50431- if err := json.Unmarshal(x, &h0); err == nil { 50432- t.Value = h0 50433- return nil 50434- } 50435- var h1 string 50436- if err := json.Unmarshal(x, &h1); err == nil { 50437- t.Value = h1 50438- return nil 50439- } 50440- return &UnmarshalError{"unmarshal failed to match one of [int32 string]"} 50441-} 50442- 50443-// from line 13885 50444-func (t Or_DocumentDiagnosticReport) MarshalJSON() ([]byte, error) { 50445- switch x := t.Value.(type) { 50446- case RelatedFullDocumentDiagnosticReport: 50447- return json.Marshal(x) 50448- case RelatedUnchangedDocumentDiagnosticReport: 50449- return json.Marshal(x) 50450- case nil: 50451- return []byte("null"), nil 50452- } 50453- return nil, fmt.Errorf("type %T not one of [RelatedFullDocumentDiagnosticReport RelatedUnchangedDocumentDiagnosticReport]", t) 50454-} 50455- 50456-func (t *Or_DocumentDiagnosticReport) UnmarshalJSON(x []byte) error { 50457- if string(x) == "null" { 50458- t.Value = nil 50459- return nil 50460- } 50461- var h0 RelatedFullDocumentDiagnosticReport 50462- if err := json.Unmarshal(x, &h0); err == nil { 50463- t.Value = h0 50464- return nil 50465- } 50466- var h1 RelatedUnchangedDocumentDiagnosticReport 50467- if err := json.Unmarshal(x, &h1); err == nil { 50468- t.Value = h1 50469- return nil 50470- } 50471- return &UnmarshalError{"unmarshal failed to match one of [RelatedFullDocumentDiagnosticReport RelatedUnchangedDocumentDiagnosticReport]"} 50472-} 50473- 50474-// from line 3822 50475-func (t Or_DocumentDiagnosticReportPartialResult_relatedDocuments_Value) MarshalJSON() ([]byte, error) { 50476- switch x := t.Value.(type) { 50477- case FullDocumentDiagnosticReport: 50478- return json.Marshal(x) 50479- case UnchangedDocumentDiagnosticReport: 50480- return json.Marshal(x) 50481- case nil: 50482- return []byte("null"), nil 50483- } 50484- return nil, fmt.Errorf("type %T not one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]", t) 50485-} 50486- 50487-func (t *Or_DocumentDiagnosticReportPartialResult_relatedDocuments_Value) UnmarshalJSON(x []byte) error { 50488- if string(x) == "null" { 50489- t.Value = nil 50490- return nil 50491- } 50492- var h0 FullDocumentDiagnosticReport 50493- if err := json.Unmarshal(x, &h0); err == nil { 50494- t.Value = h0 50495- return nil 50496- } 50497- var h1 UnchangedDocumentDiagnosticReport 50498- if err := json.Unmarshal(x, &h1); err == nil { 50499- t.Value = h1 50500- return nil 50501- } 50502- return &UnmarshalError{"unmarshal failed to match one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]"} 50503-} 50504- 50505-// from line 14095 50506-func (t Or_DocumentFilter) MarshalJSON() ([]byte, error) { 50507- switch x := t.Value.(type) { 50508- case NotebookCellTextDocumentFilter: 50509- return json.Marshal(x) 50510- case TextDocumentFilter: 50511- return json.Marshal(x) 50512- case nil: 50513- return []byte("null"), nil 50514- } 50515- return nil, fmt.Errorf("type %T not one of [NotebookCellTextDocumentFilter TextDocumentFilter]", t) 50516-} 50517- 50518-func (t *Or_DocumentFilter) UnmarshalJSON(x []byte) error { 50519- if string(x) == "null" { 50520- t.Value = nil 50521- return nil 50522- } 50523- var h0 NotebookCellTextDocumentFilter 50524- if err := json.Unmarshal(x, &h0); err == nil { 50525- t.Value = h0 50526- return nil 50527- } 50528- var h1 TextDocumentFilter 50529- if err := json.Unmarshal(x, &h1); err == nil { 50530- t.Value = h1 50531- return nil 50532- } 50533- return &UnmarshalError{"unmarshal failed to match one of [NotebookCellTextDocumentFilter TextDocumentFilter]"} 50534-} 50535- 50536-// from line 4891 50537-func (t Or_Hover_contents) MarshalJSON() ([]byte, error) { 50538- switch x := t.Value.(type) { 50539- case MarkedString: 50540- return json.Marshal(x) 50541- case MarkupContent: 50542- return json.Marshal(x) 50543- case []MarkedString: 50544- return json.Marshal(x) 50545- case nil: 50546- return []byte("null"), nil 50547- } 50548- return nil, fmt.Errorf("type %T not one of [MarkedString MarkupContent []MarkedString]", t) 50549-} 50550- 50551-func (t *Or_Hover_contents) UnmarshalJSON(x []byte) error { 50552- if string(x) == "null" { 50553- t.Value = nil 50554- return nil 50555- } 50556- var h0 MarkedString 50557- if err := json.Unmarshal(x, &h0); err == nil { 50558- t.Value = h0 50559- return nil 50560- } 50561- var h1 MarkupContent 50562- if err := json.Unmarshal(x, &h1); err == nil { 50563- t.Value = h1 50564- return nil 50565- } 50566- var h2 []MarkedString 50567- if err := json.Unmarshal(x, &h2); err == nil { 50568- t.Value = h2 50569- return nil 50570- } 50571- return &UnmarshalError{"unmarshal failed to match one of [MarkedString MarkupContent []MarkedString]"} 50572-} 50573- 50574-// from line 3658 50575-func (t Or_InlayHint_label) MarshalJSON() ([]byte, error) { 50576- switch x := t.Value.(type) { 50577- case []InlayHintLabelPart: 50578- return json.Marshal(x) 50579- case string: 50580- return json.Marshal(x) 50581- case nil: 50582- return []byte("null"), nil 50583- } 50584- return nil, fmt.Errorf("type %T not one of [[]InlayHintLabelPart string]", t) 50585-} 50586- 50587-func (t *Or_InlayHint_label) UnmarshalJSON(x []byte) error { 50588- if string(x) == "null" { 50589- t.Value = nil 50590- return nil 50591- } 50592- var h0 []InlayHintLabelPart 50593- if err := json.Unmarshal(x, &h0); err == nil { 50594- t.Value = h0 50595- return nil 50596- } 50597- var h1 string 50598- if err := json.Unmarshal(x, &h1); err == nil { 50599- t.Value = h1 50600- return nil 50601- } 50602- return &UnmarshalError{"unmarshal failed to match one of [[]InlayHintLabelPart string]"} 50603-} 50604- 50605-// from line 13863 50606-func (t Or_InlineValue) MarshalJSON() ([]byte, error) { 50607- switch x := t.Value.(type) { 50608- case InlineValueEvaluatableExpression: 50609- return json.Marshal(x) 50610- case InlineValueText: 50611- return json.Marshal(x) 50612- case InlineValueVariableLookup: 50613- return json.Marshal(x) 50614- case nil: 50615- return []byte("null"), nil 50616- } 50617- return nil, fmt.Errorf("type %T not one of [InlineValueEvaluatableExpression InlineValueText InlineValueVariableLookup]", t) 50618-} 50619- 50620-func (t *Or_InlineValue) UnmarshalJSON(x []byte) error { 50621- if string(x) == "null" { 50622- t.Value = nil 50623- return nil 50624- } 50625- var h0 InlineValueEvaluatableExpression 50626- if err := json.Unmarshal(x, &h0); err == nil { 50627- t.Value = h0 50628- return nil 50629- } 50630- var h1 InlineValueText 50631- if err := json.Unmarshal(x, &h1); err == nil { 50632- t.Value = h1 50633- return nil 50634- } 50635- var h2 InlineValueVariableLookup 50636- if err := json.Unmarshal(x, &h2); err == nil { 50637- t.Value = h2 50638- return nil 50639- } 50640- return &UnmarshalError{"unmarshal failed to match one of [InlineValueEvaluatableExpression InlineValueText InlineValueVariableLookup]"} 50641-} 50642- 50643-// from line 14060 50644-func (t Or_MarkedString) MarshalJSON() ([]byte, error) { 50645- switch x := t.Value.(type) { 50646- case Msg_MarkedString: 50647- return json.Marshal(x) 50648- case string: 50649- return json.Marshal(x) 50650- case nil: 50651- return []byte("null"), nil 50652- } 50653- return nil, fmt.Errorf("type %T not one of [Msg_MarkedString string]", t) 50654-} 50655- 50656-func (t *Or_MarkedString) UnmarshalJSON(x []byte) error { 50657- if string(x) == "null" { 50658- t.Value = nil 50659- return nil 50660- } 50661- var h0 Msg_MarkedString 50662- if err := json.Unmarshal(x, &h0); err == nil { 50663- t.Value = h0 50664- return nil 50665- } 50666- var h1 string 50667- if err := json.Unmarshal(x, &h1); err == nil { 50668- t.Value = h1 50669- return nil 50670- } 50671- return &UnmarshalError{"unmarshal failed to match one of [Msg_MarkedString string]"} 50672-} 50673- 50674-// from line 10118 50675-func (t Or_NotebookCellTextDocumentFilter_notebook) MarshalJSON() ([]byte, error) { 50676- switch x := t.Value.(type) { 50677- case NotebookDocumentFilter: 50678- return json.Marshal(x) 50679- case string: 50680- return json.Marshal(x) 50681- case nil: 50682- return []byte("null"), nil 50683- } 50684- return nil, fmt.Errorf("type %T not one of [NotebookDocumentFilter string]", t) 50685-} 50686- 50687-func (t *Or_NotebookCellTextDocumentFilter_notebook) UnmarshalJSON(x []byte) error { 50688- if string(x) == "null" { 50689- t.Value = nil 50690- return nil 50691- } 50692- var h0 NotebookDocumentFilter 50693- if err := json.Unmarshal(x, &h0); err == nil { 50694- t.Value = h0 50695- return nil 50696- } 50697- var h1 string 50698- if err := json.Unmarshal(x, &h1); err == nil { 50699- t.Value = h1 50700- return nil 50701- } 50702- return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentFilter string]"} 50703-} 50704- 50705-// from line 9857 50706-func (t Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook) MarshalJSON() ([]byte, error) { 50707- switch x := t.Value.(type) { 50708- case NotebookDocumentFilter: 50709- return json.Marshal(x) 50710- case string: 50711- return json.Marshal(x) 50712- case nil: 50713- return []byte("null"), nil 50714- } 50715- return nil, fmt.Errorf("type %T not one of [NotebookDocumentFilter string]", t) 50716-} 50717- 50718-func (t *Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook) UnmarshalJSON(x []byte) error { 50719- if string(x) == "null" { 50720- t.Value = nil 50721- return nil 50722- } 50723- var h0 NotebookDocumentFilter 50724- if err := json.Unmarshal(x, &h0); err == nil { 50725- t.Value = h0 50726- return nil 50727- } 50728- var h1 string 50729- if err := json.Unmarshal(x, &h1); err == nil { 50730- t.Value = h1 50731- return nil 50732- } 50733- return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentFilter string]"} 50734-} 50735- 50736-// from line 7168 50737-func (t Or_RelatedFullDocumentDiagnosticReport_relatedDocuments_Value) MarshalJSON() ([]byte, error) { 50738- switch x := t.Value.(type) { 50739- case FullDocumentDiagnosticReport: 50740- return json.Marshal(x) 50741- case UnchangedDocumentDiagnosticReport: 50742- return json.Marshal(x) 50743- case nil: 50744- return []byte("null"), nil 50745- } 50746- return nil, fmt.Errorf("type %T not one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]", t) 50747-} 50748- 50749-func (t *Or_RelatedFullDocumentDiagnosticReport_relatedDocuments_Value) UnmarshalJSON(x []byte) error { 50750- if string(x) == "null" { 50751- t.Value = nil 50752- return nil 50753- } 50754- var h0 FullDocumentDiagnosticReport 50755- if err := json.Unmarshal(x, &h0); err == nil { 50756- t.Value = h0 50757- return nil 50758- } 50759- var h1 UnchangedDocumentDiagnosticReport 50760- if err := json.Unmarshal(x, &h1); err == nil { 50761- t.Value = h1 50762- return nil 50763- } 50764- return &UnmarshalError{"unmarshal failed to match one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]"} 50765-} 50766- 50767-// from line 7207 50768-func (t Or_RelatedUnchangedDocumentDiagnosticReport_relatedDocuments_Value) MarshalJSON() ([]byte, error) { 50769- switch x := t.Value.(type) { 50770- case FullDocumentDiagnosticReport: 50771- return json.Marshal(x) 50772- case UnchangedDocumentDiagnosticReport: 50773- return json.Marshal(x) 50774- case nil: 50775- return []byte("null"), nil 50776- } 50777- return nil, fmt.Errorf("type %T not one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]", t) 50778-} 50779- 50780-func (t *Or_RelatedUnchangedDocumentDiagnosticReport_relatedDocuments_Value) UnmarshalJSON(x []byte) error { 50781- if string(x) == "null" { 50782- t.Value = nil 50783- return nil 50784- } 50785- var h0 FullDocumentDiagnosticReport 50786- if err := json.Unmarshal(x, &h0); err == nil { 50787- t.Value = h0 50788- return nil 50789- } 50790- var h1 UnchangedDocumentDiagnosticReport 50791- if err := json.Unmarshal(x, &h1); err == nil { 50792- t.Value = h1 50793- return nil 50794- } 50795- return &UnmarshalError{"unmarshal failed to match one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]"} 50796-} 50797- 50798-// from line 10741 50799-func (t Or_RelativePattern_baseUri) MarshalJSON() ([]byte, error) { 50800- switch x := t.Value.(type) { 50801- case URI: 50802- return json.Marshal(x) 50803- case WorkspaceFolder: 50804- return json.Marshal(x) 50805- case nil: 50806- return []byte("null"), nil 50807- } 50808- return nil, fmt.Errorf("type %T not one of [URI WorkspaceFolder]", t) 50809-} 50810- 50811-func (t *Or_RelativePattern_baseUri) UnmarshalJSON(x []byte) error { 50812- if string(x) == "null" { 50813- t.Value = nil 50814- return nil 50815- } 50816- var h0 URI 50817- if err := json.Unmarshal(x, &h0); err == nil { 50818- t.Value = h0 50819- return nil 50820- } 50821- var h1 WorkspaceFolder 50822- if err := json.Unmarshal(x, &h1); err == nil { 50823- t.Value = h1 50824- return nil 50825- } 50826- return &UnmarshalError{"unmarshal failed to match one of [URI WorkspaceFolder]"} 50827-} 50828- 50829-// from line 1371 50830-func (t Or_Result_textDocument_codeAction_Item0_Elem) MarshalJSON() ([]byte, error) { 50831- switch x := t.Value.(type) { 50832- case CodeAction: 50833- return json.Marshal(x) 50834- case Command: 50835- return json.Marshal(x) 50836- case nil: 50837- return []byte("null"), nil 50838- } 50839- return nil, fmt.Errorf("type %T not one of [CodeAction Command]", t) 50840-} 50841- 50842-func (t *Or_Result_textDocument_codeAction_Item0_Elem) UnmarshalJSON(x []byte) error { 50843- if string(x) == "null" { 50844- t.Value = nil 50845- return nil 50846- } 50847- var h0 CodeAction 50848- if err := json.Unmarshal(x, &h0); err == nil { 50849- t.Value = h0 50850- return nil 50851- } 50852- var h1 Command 50853- if err := json.Unmarshal(x, &h1); err == nil { 50854- t.Value = h1 50855- return nil 50856- } 50857- return &UnmarshalError{"unmarshal failed to match one of [CodeAction Command]"} 50858-} 50859- 50860-// from line 12197 50861-func (t Or_SemanticTokensClientCapabilities_requests_full) MarshalJSON() ([]byte, error) { 50862- switch x := t.Value.(type) { 50863- case FFullPRequests: 50864- return json.Marshal(x) 50865- case bool: 50866- return json.Marshal(x) 50867- case nil: 50868- return []byte("null"), nil 50869- } 50870- return nil, fmt.Errorf("type %T not one of [FFullPRequests bool]", t) 50871-} 50872- 50873-func (t *Or_SemanticTokensClientCapabilities_requests_full) UnmarshalJSON(x []byte) error { 50874- if string(x) == "null" { 50875- t.Value = nil 50876- return nil 50877- } 50878- var h0 FFullPRequests 50879- if err := json.Unmarshal(x, &h0); err == nil { 50880- t.Value = h0 50881- return nil 50882- } 50883- var h1 bool 50884- if err := json.Unmarshal(x, &h1); err == nil { 50885- t.Value = h1 50886- return nil 50887- } 50888- return &UnmarshalError{"unmarshal failed to match one of [FFullPRequests bool]"} 50889-} 50890- 50891-// from line 12177 50892-func (t Or_SemanticTokensClientCapabilities_requests_range) MarshalJSON() ([]byte, error) { 50893- switch x := t.Value.(type) { 50894- case FRangePRequests: 50895- return json.Marshal(x) 50896- case bool: 50897- return json.Marshal(x) 50898- case nil: 50899- return []byte("null"), nil 50900- } 50901- return nil, fmt.Errorf("type %T not one of [FRangePRequests bool]", t) 50902-} 50903- 50904-func (t *Or_SemanticTokensClientCapabilities_requests_range) UnmarshalJSON(x []byte) error { 50905- if string(x) == "null" { 50906- t.Value = nil 50907- return nil 50908- } 50909- var h0 FRangePRequests 50910- if err := json.Unmarshal(x, &h0); err == nil { 50911- t.Value = h0 50912- return nil 50913- } 50914- var h1 bool 50915- if err := json.Unmarshal(x, &h1); err == nil { 50916- t.Value = h1 50917- return nil 50918- } 50919- return &UnmarshalError{"unmarshal failed to match one of [FRangePRequests bool]"} 50920-} 50921- 50922-// from line 6579 50923-func (t Or_SemanticTokensOptions_full) MarshalJSON() ([]byte, error) { 50924- switch x := t.Value.(type) { 50925- case PFullESemanticTokensOptions: 50926- return json.Marshal(x) 50927- case bool: 50928- return json.Marshal(x) 50929- case nil: 50930- return []byte("null"), nil 50931- } 50932- return nil, fmt.Errorf("type %T not one of [PFullESemanticTokensOptions bool]", t) 50933-} 50934- 50935-func (t *Or_SemanticTokensOptions_full) UnmarshalJSON(x []byte) error { 50936- if string(x) == "null" { 50937- t.Value = nil 50938- return nil 50939- } 50940- var h0 PFullESemanticTokensOptions 50941- if err := json.Unmarshal(x, &h0); err == nil { 50942- t.Value = h0 50943- return nil 50944- } 50945- var h1 bool 50946- if err := json.Unmarshal(x, &h1); err == nil { 50947- t.Value = h1 50948- return nil 50949- } 50950- return &UnmarshalError{"unmarshal failed to match one of [PFullESemanticTokensOptions bool]"} 50951-} 50952- 50953-// from line 6559 50954-func (t Or_SemanticTokensOptions_range) MarshalJSON() ([]byte, error) { 50955- switch x := t.Value.(type) { 50956- case PRangeESemanticTokensOptions: 50957- return json.Marshal(x) 50958- case bool: 50959- return json.Marshal(x) 50960- case nil: 50961- return []byte("null"), nil 50962- } 50963- return nil, fmt.Errorf("type %T not one of [PRangeESemanticTokensOptions bool]", t) 50964-} 50965- 50966-func (t *Or_SemanticTokensOptions_range) UnmarshalJSON(x []byte) error { 50967- if string(x) == "null" { 50968- t.Value = nil 50969- return nil 50970- } 50971- var h0 PRangeESemanticTokensOptions 50972- if err := json.Unmarshal(x, &h0); err == nil { 50973- t.Value = h0 50974- return nil 50975- } 50976- var h1 bool 50977- if err := json.Unmarshal(x, &h1); err == nil { 50978- t.Value = h1 50979- return nil 50980- } 50981- return &UnmarshalError{"unmarshal failed to match one of [PRangeESemanticTokensOptions bool]"} 50982-} 50983- 50984-// from line 8227 50985-func (t Or_ServerCapabilities_callHierarchyProvider) MarshalJSON() ([]byte, error) { 50986- switch x := t.Value.(type) { 50987- case CallHierarchyOptions: 50988- return json.Marshal(x) 50989- case CallHierarchyRegistrationOptions: 50990- return json.Marshal(x) 50991- case bool: 50992- return json.Marshal(x) 50993- case nil: 50994- return []byte("null"), nil 50995- } 50996- return nil, fmt.Errorf("type %T not one of [CallHierarchyOptions CallHierarchyRegistrationOptions bool]", t) 50997-} 50998- 50999-func (t *Or_ServerCapabilities_callHierarchyProvider) UnmarshalJSON(x []byte) error { 51000- if string(x) == "null" { 51001- t.Value = nil 51002- return nil 51003- } 51004- var h0 CallHierarchyOptions 51005- if err := json.Unmarshal(x, &h0); err == nil { 51006- t.Value = h0 51007- return nil 51008- } 51009- var h1 CallHierarchyRegistrationOptions 51010- if err := json.Unmarshal(x, &h1); err == nil { 51011- t.Value = h1 51012- return nil 51013- } 51014- var h2 bool 51015- if err := json.Unmarshal(x, &h2); err == nil { 51016- t.Value = h2 51017- return nil 51018- } 51019- return &UnmarshalError{"unmarshal failed to match one of [CallHierarchyOptions CallHierarchyRegistrationOptions bool]"} 51020-} 51021- 51022-// from line 8035 51023-func (t Or_ServerCapabilities_codeActionProvider) MarshalJSON() ([]byte, error) { 51024- switch x := t.Value.(type) { 51025- case CodeActionOptions: 51026- return json.Marshal(x) 51027- case bool: 51028- return json.Marshal(x) 51029- case nil: 51030- return []byte("null"), nil 51031- } 51032- return nil, fmt.Errorf("type %T not one of [CodeActionOptions bool]", t) 51033-} 51034- 51035-func (t *Or_ServerCapabilities_codeActionProvider) UnmarshalJSON(x []byte) error { 51036- if string(x) == "null" { 51037- t.Value = nil 51038- return nil 51039- } 51040- var h0 CodeActionOptions 51041- if err := json.Unmarshal(x, &h0); err == nil { 51042- t.Value = h0 51043- return nil 51044- } 51045- var h1 bool 51046- if err := json.Unmarshal(x, &h1); err == nil { 51047- t.Value = h1 51048- return nil 51049- } 51050- return &UnmarshalError{"unmarshal failed to match one of [CodeActionOptions bool]"} 51051-} 51052- 51053-// from line 8071 51054-func (t Or_ServerCapabilities_colorProvider) MarshalJSON() ([]byte, error) { 51055- switch x := t.Value.(type) { 51056- case DocumentColorOptions: 51057- return json.Marshal(x) 51058- case DocumentColorRegistrationOptions: 51059- return json.Marshal(x) 51060- case bool: 51061- return json.Marshal(x) 51062- case nil: 51063- return []byte("null"), nil 51064- } 51065- return nil, fmt.Errorf("type %T not one of [DocumentColorOptions DocumentColorRegistrationOptions bool]", t) 51066-} 51067- 51068-func (t *Or_ServerCapabilities_colorProvider) UnmarshalJSON(x []byte) error { 51069- if string(x) == "null" { 51070- t.Value = nil 51071- return nil 51072- } 51073- var h0 DocumentColorOptions 51074- if err := json.Unmarshal(x, &h0); err == nil { 51075- t.Value = h0 51076- return nil 51077- } 51078- var h1 DocumentColorRegistrationOptions 51079- if err := json.Unmarshal(x, &h1); err == nil { 51080- t.Value = h1 51081- return nil 51082- } 51083- var h2 bool 51084- if err := json.Unmarshal(x, &h2); err == nil { 51085- t.Value = h2 51086- return nil 51087- } 51088- return &UnmarshalError{"unmarshal failed to match one of [DocumentColorOptions DocumentColorRegistrationOptions bool]"} 51089-} 51090- 51091-// from line 7897 51092-func (t Or_ServerCapabilities_declarationProvider) MarshalJSON() ([]byte, error) { 51093- switch x := t.Value.(type) { 51094- case DeclarationOptions: 51095- return json.Marshal(x) 51096- case DeclarationRegistrationOptions: 51097- return json.Marshal(x) 51098- case bool: 51099- return json.Marshal(x) 51100- case nil: 51101- return []byte("null"), nil 51102- } 51103- return nil, fmt.Errorf("type %T not one of [DeclarationOptions DeclarationRegistrationOptions bool]", t) 51104-} 51105- 51106-func (t *Or_ServerCapabilities_declarationProvider) UnmarshalJSON(x []byte) error { 51107- if string(x) == "null" { 51108- t.Value = nil 51109- return nil 51110- } 51111- var h0 DeclarationOptions 51112- if err := json.Unmarshal(x, &h0); err == nil { 51113- t.Value = h0 51114- return nil 51115- } 51116- var h1 DeclarationRegistrationOptions 51117- if err := json.Unmarshal(x, &h1); err == nil { 51118- t.Value = h1 51119- return nil 51120- } 51121- var h2 bool 51122- if err := json.Unmarshal(x, &h2); err == nil { 51123- t.Value = h2 51124- return nil 51125- } 51126- return &UnmarshalError{"unmarshal failed to match one of [DeclarationOptions DeclarationRegistrationOptions bool]"} 51127-} 51128- 51129-// from line 7919 51130-func (t Or_ServerCapabilities_definitionProvider) MarshalJSON() ([]byte, error) { 51131- switch x := t.Value.(type) { 51132- case DefinitionOptions: 51133- return json.Marshal(x) 51134- case bool: 51135- return json.Marshal(x) 51136- case nil: 51137- return []byte("null"), nil 51138- } 51139- return nil, fmt.Errorf("type %T not one of [DefinitionOptions bool]", t) 51140-} 51141- 51142-func (t *Or_ServerCapabilities_definitionProvider) UnmarshalJSON(x []byte) error { 51143- if string(x) == "null" { 51144- t.Value = nil 51145- return nil 51146- } 51147- var h0 DefinitionOptions 51148- if err := json.Unmarshal(x, &h0); err == nil { 51149- t.Value = h0 51150- return nil 51151- } 51152- var h1 bool 51153- if err := json.Unmarshal(x, &h1); err == nil { 51154- t.Value = h1 51155- return nil 51156- } 51157- return &UnmarshalError{"unmarshal failed to match one of [DefinitionOptions bool]"} 51158-} 51159- 51160-// from line 8384 51161-func (t Or_ServerCapabilities_diagnosticProvider) MarshalJSON() ([]byte, error) { 51162- switch x := t.Value.(type) { 51163- case DiagnosticOptions: 51164- return json.Marshal(x) 51165- case DiagnosticRegistrationOptions: 51166- return json.Marshal(x) 51167- case nil: 51168- return []byte("null"), nil 51169- } 51170- return nil, fmt.Errorf("type %T not one of [DiagnosticOptions DiagnosticRegistrationOptions]", t) 51171-} 51172- 51173-func (t *Or_ServerCapabilities_diagnosticProvider) UnmarshalJSON(x []byte) error { 51174- if string(x) == "null" { 51175- t.Value = nil 51176- return nil 51177- } 51178- var h0 DiagnosticOptions 51179- if err := json.Unmarshal(x, &h0); err == nil { 51180- t.Value = h0 51181- return nil 51182- } 51183- var h1 DiagnosticRegistrationOptions 51184- if err := json.Unmarshal(x, &h1); err == nil { 51185- t.Value = h1 51186- return nil 51187- } 51188- return &UnmarshalError{"unmarshal failed to match one of [DiagnosticOptions DiagnosticRegistrationOptions]"} 51189-} 51190- 51191-// from line 8111 51192-func (t Or_ServerCapabilities_documentFormattingProvider) MarshalJSON() ([]byte, error) { 51193- switch x := t.Value.(type) { 51194- case DocumentFormattingOptions: 51195- return json.Marshal(x) 51196- case bool: 51197- return json.Marshal(x) 51198- case nil: 51199- return []byte("null"), nil 51200- } 51201- return nil, fmt.Errorf("type %T not one of [DocumentFormattingOptions bool]", t) 51202-} 51203- 51204-func (t *Or_ServerCapabilities_documentFormattingProvider) UnmarshalJSON(x []byte) error { 51205- if string(x) == "null" { 51206- t.Value = nil 51207- return nil 51208- } 51209- var h0 DocumentFormattingOptions 51210- if err := json.Unmarshal(x, &h0); err == nil { 51211- t.Value = h0 51212- return nil 51213- } 51214- var h1 bool 51215- if err := json.Unmarshal(x, &h1); err == nil { 51216- t.Value = h1 51217- return nil 51218- } 51219- return &UnmarshalError{"unmarshal failed to match one of [DocumentFormattingOptions bool]"} 51220-} 51221- 51222-// from line 7999 51223-func (t Or_ServerCapabilities_documentHighlightProvider) MarshalJSON() ([]byte, error) { 51224- switch x := t.Value.(type) { 51225- case DocumentHighlightOptions: 51226- return json.Marshal(x) 51227- case bool: 51228- return json.Marshal(x) 51229- case nil: 51230- return []byte("null"), nil 51231- } 51232- return nil, fmt.Errorf("type %T not one of [DocumentHighlightOptions bool]", t) 51233-} 51234- 51235-func (t *Or_ServerCapabilities_documentHighlightProvider) UnmarshalJSON(x []byte) error { 51236- if string(x) == "null" { 51237- t.Value = nil 51238- return nil 51239- } 51240- var h0 DocumentHighlightOptions 51241- if err := json.Unmarshal(x, &h0); err == nil { 51242- t.Value = h0 51243- return nil 51244- } 51245- var h1 bool 51246- if err := json.Unmarshal(x, &h1); err == nil { 51247- t.Value = h1 51248- return nil 51249- } 51250- return &UnmarshalError{"unmarshal failed to match one of [DocumentHighlightOptions bool]"} 51251-} 51252- 51253-// from line 8129 51254-func (t Or_ServerCapabilities_documentRangeFormattingProvider) MarshalJSON() ([]byte, error) { 51255- switch x := t.Value.(type) { 51256- case DocumentRangeFormattingOptions: 51257- return json.Marshal(x) 51258- case bool: 51259- return json.Marshal(x) 51260- case nil: 51261- return []byte("null"), nil 51262- } 51263- return nil, fmt.Errorf("type %T not one of [DocumentRangeFormattingOptions bool]", t) 51264-} 51265- 51266-func (t *Or_ServerCapabilities_documentRangeFormattingProvider) UnmarshalJSON(x []byte) error { 51267- if string(x) == "null" { 51268- t.Value = nil 51269- return nil 51270- } 51271- var h0 DocumentRangeFormattingOptions 51272- if err := json.Unmarshal(x, &h0); err == nil { 51273- t.Value = h0 51274- return nil 51275- } 51276- var h1 bool 51277- if err := json.Unmarshal(x, &h1); err == nil { 51278- t.Value = h1 51279- return nil 51280- } 51281- return &UnmarshalError{"unmarshal failed to match one of [DocumentRangeFormattingOptions bool]"} 51282-} 51283- 51284-// from line 8017 51285-func (t Or_ServerCapabilities_documentSymbolProvider) MarshalJSON() ([]byte, error) { 51286- switch x := t.Value.(type) { 51287- case DocumentSymbolOptions: 51288- return json.Marshal(x) 51289- case bool: 51290- return json.Marshal(x) 51291- case nil: 51292- return []byte("null"), nil 51293- } 51294- return nil, fmt.Errorf("type %T not one of [DocumentSymbolOptions bool]", t) 51295-} 51296- 51297-func (t *Or_ServerCapabilities_documentSymbolProvider) UnmarshalJSON(x []byte) error { 51298- if string(x) == "null" { 51299- t.Value = nil 51300- return nil 51301- } 51302- var h0 DocumentSymbolOptions 51303- if err := json.Unmarshal(x, &h0); err == nil { 51304- t.Value = h0 51305- return nil 51306- } 51307- var h1 bool 51308- if err := json.Unmarshal(x, &h1); err == nil { 51309- t.Value = h1 51310- return nil 51311- } 51312- return &UnmarshalError{"unmarshal failed to match one of [DocumentSymbolOptions bool]"} 51313-} 51314- 51315-// from line 8174 51316-func (t Or_ServerCapabilities_foldingRangeProvider) MarshalJSON() ([]byte, error) { 51317- switch x := t.Value.(type) { 51318- case FoldingRangeOptions: 51319- return json.Marshal(x) 51320- case FoldingRangeRegistrationOptions: 51321- return json.Marshal(x) 51322- case bool: 51323- return json.Marshal(x) 51324- case nil: 51325- return []byte("null"), nil 51326- } 51327- return nil, fmt.Errorf("type %T not one of [FoldingRangeOptions FoldingRangeRegistrationOptions bool]", t) 51328-} 51329- 51330-func (t *Or_ServerCapabilities_foldingRangeProvider) UnmarshalJSON(x []byte) error { 51331- if string(x) == "null" { 51332- t.Value = nil 51333- return nil 51334- } 51335- var h0 FoldingRangeOptions 51336- if err := json.Unmarshal(x, &h0); err == nil { 51337- t.Value = h0 51338- return nil 51339- } 51340- var h1 FoldingRangeRegistrationOptions 51341- if err := json.Unmarshal(x, &h1); err == nil { 51342- t.Value = h1 51343- return nil 51344- } 51345- var h2 bool 51346- if err := json.Unmarshal(x, &h2); err == nil { 51347- t.Value = h2 51348- return nil 51349- } 51350- return &UnmarshalError{"unmarshal failed to match one of [FoldingRangeOptions FoldingRangeRegistrationOptions bool]"} 51351-} 51352- 51353-// from line 7870 51354-func (t Or_ServerCapabilities_hoverProvider) MarshalJSON() ([]byte, error) { 51355- switch x := t.Value.(type) { 51356- case HoverOptions: 51357- return json.Marshal(x) 51358- case bool: 51359- return json.Marshal(x) 51360- case nil: 51361- return []byte("null"), nil 51362- } 51363- return nil, fmt.Errorf("type %T not one of [HoverOptions bool]", t) 51364-} 51365- 51366-func (t *Or_ServerCapabilities_hoverProvider) UnmarshalJSON(x []byte) error { 51367- if string(x) == "null" { 51368- t.Value = nil 51369- return nil 51370- } 51371- var h0 HoverOptions 51372- if err := json.Unmarshal(x, &h0); err == nil { 51373- t.Value = h0 51374- return nil 51375- } 51376- var h1 bool 51377- if err := json.Unmarshal(x, &h1); err == nil { 51378- t.Value = h1 51379- return nil 51380- } 51381- return &UnmarshalError{"unmarshal failed to match one of [HoverOptions bool]"} 51382-} 51383- 51384-// from line 7959 51385-func (t Or_ServerCapabilities_implementationProvider) MarshalJSON() ([]byte, error) { 51386- switch x := t.Value.(type) { 51387- case ImplementationOptions: 51388- return json.Marshal(x) 51389- case ImplementationRegistrationOptions: 51390- return json.Marshal(x) 51391- case bool: 51392- return json.Marshal(x) 51393- case nil: 51394- return []byte("null"), nil 51395- } 51396- return nil, fmt.Errorf("type %T not one of [ImplementationOptions ImplementationRegistrationOptions bool]", t) 51397-} 51398- 51399-func (t *Or_ServerCapabilities_implementationProvider) UnmarshalJSON(x []byte) error { 51400- if string(x) == "null" { 51401- t.Value = nil 51402- return nil 51403- } 51404- var h0 ImplementationOptions 51405- if err := json.Unmarshal(x, &h0); err == nil { 51406- t.Value = h0 51407- return nil 51408- } 51409- var h1 ImplementationRegistrationOptions 51410- if err := json.Unmarshal(x, &h1); err == nil { 51411- t.Value = h1 51412- return nil 51413- } 51414- var h2 bool 51415- if err := json.Unmarshal(x, &h2); err == nil { 51416- t.Value = h2 51417- return nil 51418- } 51419- return &UnmarshalError{"unmarshal failed to match one of [ImplementationOptions ImplementationRegistrationOptions bool]"} 51420-} 51421- 51422-// from line 8361 51423-func (t Or_ServerCapabilities_inlayHintProvider) MarshalJSON() ([]byte, error) { 51424- switch x := t.Value.(type) { 51425- case InlayHintOptions: 51426- return json.Marshal(x) 51427- case InlayHintRegistrationOptions: 51428- return json.Marshal(x) 51429- case bool: 51430- return json.Marshal(x) 51431- case nil: 51432- return []byte("null"), nil 51433- } 51434- return nil, fmt.Errorf("type %T not one of [InlayHintOptions InlayHintRegistrationOptions bool]", t) 51435-} 51436- 51437-func (t *Or_ServerCapabilities_inlayHintProvider) UnmarshalJSON(x []byte) error { 51438- if string(x) == "null" { 51439- t.Value = nil 51440- return nil 51441- } 51442- var h0 InlayHintOptions 51443- if err := json.Unmarshal(x, &h0); err == nil { 51444- t.Value = h0 51445- return nil 51446- } 51447- var h1 InlayHintRegistrationOptions 51448- if err := json.Unmarshal(x, &h1); err == nil { 51449- t.Value = h1 51450- return nil 51451- } 51452- var h2 bool 51453- if err := json.Unmarshal(x, &h2); err == nil { 51454- t.Value = h2 51455- return nil 51456- } 51457- return &UnmarshalError{"unmarshal failed to match one of [InlayHintOptions InlayHintRegistrationOptions bool]"} 51458-} 51459- 51460-// from line 8338 51461-func (t Or_ServerCapabilities_inlineValueProvider) MarshalJSON() ([]byte, error) { 51462- switch x := t.Value.(type) { 51463- case InlineValueOptions: 51464- return json.Marshal(x) 51465- case InlineValueRegistrationOptions: 51466- return json.Marshal(x) 51467- case bool: 51468- return json.Marshal(x) 51469- case nil: 51470- return []byte("null"), nil 51471- } 51472- return nil, fmt.Errorf("type %T not one of [InlineValueOptions InlineValueRegistrationOptions bool]", t) 51473-} 51474- 51475-func (t *Or_ServerCapabilities_inlineValueProvider) UnmarshalJSON(x []byte) error { 51476- if string(x) == "null" { 51477- t.Value = nil 51478- return nil 51479- } 51480- var h0 InlineValueOptions 51481- if err := json.Unmarshal(x, &h0); err == nil { 51482- t.Value = h0 51483- return nil 51484- } 51485- var h1 InlineValueRegistrationOptions 51486- if err := json.Unmarshal(x, &h1); err == nil { 51487- t.Value = h1 51488- return nil 51489- } 51490- var h2 bool 51491- if err := json.Unmarshal(x, &h2); err == nil { 51492- t.Value = h2 51493- return nil 51494- } 51495- return &UnmarshalError{"unmarshal failed to match one of [InlineValueOptions InlineValueRegistrationOptions bool]"} 51496-} 51497- 51498-// from line 8250 51499-func (t Or_ServerCapabilities_linkedEditingRangeProvider) MarshalJSON() ([]byte, error) { 51500- switch x := t.Value.(type) { 51501- case LinkedEditingRangeOptions: 51502- return json.Marshal(x) 51503- case LinkedEditingRangeRegistrationOptions: 51504- return json.Marshal(x) 51505- case bool: 51506- return json.Marshal(x) 51507- case nil: 51508- return []byte("null"), nil 51509- } 51510- return nil, fmt.Errorf("type %T not one of [LinkedEditingRangeOptions LinkedEditingRangeRegistrationOptions bool]", t) 51511-} 51512- 51513-func (t *Or_ServerCapabilities_linkedEditingRangeProvider) UnmarshalJSON(x []byte) error { 51514- if string(x) == "null" { 51515- t.Value = nil 51516- return nil 51517- } 51518- var h0 LinkedEditingRangeOptions 51519- if err := json.Unmarshal(x, &h0); err == nil { 51520- t.Value = h0 51521- return nil 51522- } 51523- var h1 LinkedEditingRangeRegistrationOptions 51524- if err := json.Unmarshal(x, &h1); err == nil { 51525- t.Value = h1 51526- return nil 51527- } 51528- var h2 bool 51529- if err := json.Unmarshal(x, &h2); err == nil { 51530- t.Value = h2 51531- return nil 51532- } 51533- return &UnmarshalError{"unmarshal failed to match one of [LinkedEditingRangeOptions LinkedEditingRangeRegistrationOptions bool]"} 51534-} 51535- 51536-// from line 8292 51537-func (t Or_ServerCapabilities_monikerProvider) MarshalJSON() ([]byte, error) { 51538- switch x := t.Value.(type) { 51539- case MonikerOptions: 51540- return json.Marshal(x) 51541- case MonikerRegistrationOptions: 51542- return json.Marshal(x) 51543- case bool: 51544- return json.Marshal(x) 51545- case nil: 51546- return []byte("null"), nil 51547- } 51548- return nil, fmt.Errorf("type %T not one of [MonikerOptions MonikerRegistrationOptions bool]", t) 51549-} 51550- 51551-func (t *Or_ServerCapabilities_monikerProvider) UnmarshalJSON(x []byte) error { 51552- if string(x) == "null" { 51553- t.Value = nil 51554- return nil 51555- } 51556- var h0 MonikerOptions 51557- if err := json.Unmarshal(x, &h0); err == nil { 51558- t.Value = h0 51559- return nil 51560- } 51561- var h1 MonikerRegistrationOptions 51562- if err := json.Unmarshal(x, &h1); err == nil { 51563- t.Value = h1 51564- return nil 51565- } 51566- var h2 bool 51567- if err := json.Unmarshal(x, &h2); err == nil { 51568- t.Value = h2 51569- return nil 51570- } 51571- return &UnmarshalError{"unmarshal failed to match one of [MonikerOptions MonikerRegistrationOptions bool]"} 51572-} 51573- 51574-// from line 7842 51575-func (t Or_ServerCapabilities_notebookDocumentSync) MarshalJSON() ([]byte, error) { 51576- switch x := t.Value.(type) { 51577- case NotebookDocumentSyncOptions: 51578- return json.Marshal(x) 51579- case NotebookDocumentSyncRegistrationOptions: 51580- return json.Marshal(x) 51581- case nil: 51582- return []byte("null"), nil 51583- } 51584- return nil, fmt.Errorf("type %T not one of [NotebookDocumentSyncOptions NotebookDocumentSyncRegistrationOptions]", t) 51585-} 51586- 51587-func (t *Or_ServerCapabilities_notebookDocumentSync) UnmarshalJSON(x []byte) error { 51588- if string(x) == "null" { 51589- t.Value = nil 51590- return nil 51591- } 51592- var h0 NotebookDocumentSyncOptions 51593- if err := json.Unmarshal(x, &h0); err == nil { 51594- t.Value = h0 51595- return nil 51596- } 51597- var h1 NotebookDocumentSyncRegistrationOptions 51598- if err := json.Unmarshal(x, &h1); err == nil { 51599- t.Value = h1 51600- return nil 51601- } 51602- return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentSyncOptions NotebookDocumentSyncRegistrationOptions]"} 51603-} 51604- 51605-// from line 7981 51606-func (t Or_ServerCapabilities_referencesProvider) MarshalJSON() ([]byte, error) { 51607- switch x := t.Value.(type) { 51608- case ReferenceOptions: 51609- return json.Marshal(x) 51610- case bool: 51611- return json.Marshal(x) 51612- case nil: 51613- return []byte("null"), nil 51614- } 51615- return nil, fmt.Errorf("type %T not one of [ReferenceOptions bool]", t) 51616-} 51617- 51618-func (t *Or_ServerCapabilities_referencesProvider) UnmarshalJSON(x []byte) error { 51619- if string(x) == "null" { 51620- t.Value = nil 51621- return nil 51622- } 51623- var h0 ReferenceOptions 51624- if err := json.Unmarshal(x, &h0); err == nil { 51625- t.Value = h0 51626- return nil 51627- } 51628- var h1 bool 51629- if err := json.Unmarshal(x, &h1); err == nil { 51630- t.Value = h1 51631- return nil 51632- } 51633- return &UnmarshalError{"unmarshal failed to match one of [ReferenceOptions bool]"} 51634-} 51635- 51636-// from line 8156 51637-func (t Or_ServerCapabilities_renameProvider) MarshalJSON() ([]byte, error) { 51638- switch x := t.Value.(type) { 51639- case RenameOptions: 51640- return json.Marshal(x) 51641- case bool: 51642- return json.Marshal(x) 51643- case nil: 51644- return []byte("null"), nil 51645- } 51646- return nil, fmt.Errorf("type %T not one of [RenameOptions bool]", t) 51647-} 51648- 51649-func (t *Or_ServerCapabilities_renameProvider) UnmarshalJSON(x []byte) error { 51650- if string(x) == "null" { 51651- t.Value = nil 51652- return nil 51653- } 51654- var h0 RenameOptions 51655- if err := json.Unmarshal(x, &h0); err == nil { 51656- t.Value = h0 51657- return nil 51658- } 51659- var h1 bool 51660- if err := json.Unmarshal(x, &h1); err == nil { 51661- t.Value = h1 51662- return nil 51663- } 51664- return &UnmarshalError{"unmarshal failed to match one of [RenameOptions bool]"} 51665-} 51666- 51667-// from line 8196 51668-func (t Or_ServerCapabilities_selectionRangeProvider) MarshalJSON() ([]byte, error) { 51669- switch x := t.Value.(type) { 51670- case SelectionRangeOptions: 51671- return json.Marshal(x) 51672- case SelectionRangeRegistrationOptions: 51673- return json.Marshal(x) 51674- case bool: 51675- return json.Marshal(x) 51676- case nil: 51677- return []byte("null"), nil 51678- } 51679- return nil, fmt.Errorf("type %T not one of [SelectionRangeOptions SelectionRangeRegistrationOptions bool]", t) 51680-} 51681- 51682-func (t *Or_ServerCapabilities_selectionRangeProvider) UnmarshalJSON(x []byte) error { 51683- if string(x) == "null" { 51684- t.Value = nil 51685- return nil 51686- } 51687- var h0 SelectionRangeOptions 51688- if err := json.Unmarshal(x, &h0); err == nil { 51689- t.Value = h0 51690- return nil 51691- } 51692- var h1 SelectionRangeRegistrationOptions 51693- if err := json.Unmarshal(x, &h1); err == nil { 51694- t.Value = h1 51695- return nil 51696- } 51697- var h2 bool 51698- if err := json.Unmarshal(x, &h2); err == nil { 51699- t.Value = h2 51700- return nil 51701- } 51702- return &UnmarshalError{"unmarshal failed to match one of [SelectionRangeOptions SelectionRangeRegistrationOptions bool]"} 51703-} 51704- 51705-// from line 8273 51706-func (t Or_ServerCapabilities_semanticTokensProvider) MarshalJSON() ([]byte, error) { 51707- switch x := t.Value.(type) { 51708- case SemanticTokensOptions: 51709- return json.Marshal(x) 51710- case SemanticTokensRegistrationOptions: 51711- return json.Marshal(x) 51712- case nil: 51713- return []byte("null"), nil 51714- } 51715- return nil, fmt.Errorf("type %T not one of [SemanticTokensOptions SemanticTokensRegistrationOptions]", t) 51716-} 51717- 51718-func (t *Or_ServerCapabilities_semanticTokensProvider) UnmarshalJSON(x []byte) error { 51719- if string(x) == "null" { 51720- t.Value = nil 51721- return nil 51722- } 51723- var h0 SemanticTokensOptions 51724- if err := json.Unmarshal(x, &h0); err == nil { 51725- t.Value = h0 51726- return nil 51727- } 51728- var h1 SemanticTokensRegistrationOptions 51729- if err := json.Unmarshal(x, &h1); err == nil { 51730- t.Value = h1 51731- return nil 51732- } 51733- return &UnmarshalError{"unmarshal failed to match one of [SemanticTokensOptions SemanticTokensRegistrationOptions]"} 51734-} 51735- 51736-// from line 7824 51737-func (t Or_ServerCapabilities_textDocumentSync) MarshalJSON() ([]byte, error) { 51738- switch x := t.Value.(type) { 51739- case TextDocumentSyncKind: 51740- return json.Marshal(x) 51741- case TextDocumentSyncOptions: 51742- return json.Marshal(x) 51743- case nil: 51744- return []byte("null"), nil 51745- } 51746- return nil, fmt.Errorf("type %T not one of [TextDocumentSyncKind TextDocumentSyncOptions]", t) 51747-} 51748- 51749-func (t *Or_ServerCapabilities_textDocumentSync) UnmarshalJSON(x []byte) error { 51750- if string(x) == "null" { 51751- t.Value = nil 51752- return nil 51753- } 51754- var h0 TextDocumentSyncKind 51755- if err := json.Unmarshal(x, &h0); err == nil { 51756- t.Value = h0 51757- return nil 51758- } 51759- var h1 TextDocumentSyncOptions 51760- if err := json.Unmarshal(x, &h1); err == nil { 51761- t.Value = h1 51762- return nil 51763- } 51764- return &UnmarshalError{"unmarshal failed to match one of [TextDocumentSyncKind TextDocumentSyncOptions]"} 51765-} 51766- 51767-// from line 7937 51768-func (t Or_ServerCapabilities_typeDefinitionProvider) MarshalJSON() ([]byte, error) { 51769- switch x := t.Value.(type) { 51770- case TypeDefinitionOptions: 51771- return json.Marshal(x) 51772- case TypeDefinitionRegistrationOptions: 51773- return json.Marshal(x) 51774- case bool: 51775- return json.Marshal(x) 51776- case nil: 51777- return []byte("null"), nil 51778- } 51779- return nil, fmt.Errorf("type %T not one of [TypeDefinitionOptions TypeDefinitionRegistrationOptions bool]", t) 51780-} 51781- 51782-func (t *Or_ServerCapabilities_typeDefinitionProvider) UnmarshalJSON(x []byte) error { 51783- if string(x) == "null" { 51784- t.Value = nil 51785- return nil 51786- } 51787- var h0 TypeDefinitionOptions 51788- if err := json.Unmarshal(x, &h0); err == nil { 51789- t.Value = h0 51790- return nil 51791- } 51792- var h1 TypeDefinitionRegistrationOptions 51793- if err := json.Unmarshal(x, &h1); err == nil { 51794- t.Value = h1 51795- return nil 51796- } 51797- var h2 bool 51798- if err := json.Unmarshal(x, &h2); err == nil { 51799- t.Value = h2 51800- return nil 51801- } 51802- return &UnmarshalError{"unmarshal failed to match one of [TypeDefinitionOptions TypeDefinitionRegistrationOptions bool]"} 51803-} 51804- 51805-// from line 8315 51806-func (t Or_ServerCapabilities_typeHierarchyProvider) MarshalJSON() ([]byte, error) { 51807- switch x := t.Value.(type) { 51808- case TypeHierarchyOptions: 51809- return json.Marshal(x) 51810- case TypeHierarchyRegistrationOptions: 51811- return json.Marshal(x) 51812- case bool: 51813- return json.Marshal(x) 51814- case nil: 51815- return []byte("null"), nil 51816- } 51817- return nil, fmt.Errorf("type %T not one of [TypeHierarchyOptions TypeHierarchyRegistrationOptions bool]", t) 51818-} 51819- 51820-func (t *Or_ServerCapabilities_typeHierarchyProvider) UnmarshalJSON(x []byte) error { 51821- if string(x) == "null" { 51822- t.Value = nil 51823- return nil 51824- } 51825- var h0 TypeHierarchyOptions 51826- if err := json.Unmarshal(x, &h0); err == nil { 51827- t.Value = h0 51828- return nil 51829- } 51830- var h1 TypeHierarchyRegistrationOptions 51831- if err := json.Unmarshal(x, &h1); err == nil { 51832- t.Value = h1 51833- return nil 51834- } 51835- var h2 bool 51836- if err := json.Unmarshal(x, &h2); err == nil { 51837- t.Value = h2 51838- return nil 51839- } 51840- return &UnmarshalError{"unmarshal failed to match one of [TypeHierarchyOptions TypeHierarchyRegistrationOptions bool]"} 51841-} 51842- 51843-// from line 8093 51844-func (t Or_ServerCapabilities_workspaceSymbolProvider) MarshalJSON() ([]byte, error) { 51845- switch x := t.Value.(type) { 51846- case WorkspaceSymbolOptions: 51847- return json.Marshal(x) 51848- case bool: 51849- return json.Marshal(x) 51850- case nil: 51851- return []byte("null"), nil 51852- } 51853- return nil, fmt.Errorf("type %T not one of [WorkspaceSymbolOptions bool]", t) 51854-} 51855- 51856-func (t *Or_ServerCapabilities_workspaceSymbolProvider) UnmarshalJSON(x []byte) error { 51857- if string(x) == "null" { 51858- t.Value = nil 51859- return nil 51860- } 51861- var h0 WorkspaceSymbolOptions 51862- if err := json.Unmarshal(x, &h0); err == nil { 51863- t.Value = h0 51864- return nil 51865- } 51866- var h1 bool 51867- if err := json.Unmarshal(x, &h1); err == nil { 51868- t.Value = h1 51869- return nil 51870- } 51871- return &UnmarshalError{"unmarshal failed to match one of [WorkspaceSymbolOptions bool]"} 51872-} 51873- 51874-// from line 8841 51875-func (t Or_SignatureInformation_documentation) MarshalJSON() ([]byte, error) { 51876- switch x := t.Value.(type) { 51877- case MarkupContent: 51878- return json.Marshal(x) 51879- case string: 51880- return json.Marshal(x) 51881- case nil: 51882- return []byte("null"), nil 51883- } 51884- return nil, fmt.Errorf("type %T not one of [MarkupContent string]", t) 51885-} 51886- 51887-func (t *Or_SignatureInformation_documentation) UnmarshalJSON(x []byte) error { 51888- if string(x) == "null" { 51889- t.Value = nil 51890- return nil 51891- } 51892- var h0 MarkupContent 51893- if err := json.Unmarshal(x, &h0); err == nil { 51894- t.Value = h0 51895- return nil 51896- } 51897- var h1 string 51898- if err := json.Unmarshal(x, &h1); err == nil { 51899- t.Value = h1 51900- return nil 51901- } 51902- return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"} 51903-} 51904- 51905-// from line 6692 51906-func (t Or_TextDocumentEdit_edits_Elem) MarshalJSON() ([]byte, error) { 51907- switch x := t.Value.(type) { 51908- case AnnotatedTextEdit: 51909- return json.Marshal(x) 51910- case TextEdit: 51911- return json.Marshal(x) 51912- case nil: 51913- return []byte("null"), nil 51914- } 51915- return nil, fmt.Errorf("type %T not one of [AnnotatedTextEdit TextEdit]", t) 51916-} 51917- 51918-func (t *Or_TextDocumentEdit_edits_Elem) UnmarshalJSON(x []byte) error { 51919- if string(x) == "null" { 51920- t.Value = nil 51921- return nil 51922- } 51923- var h0 AnnotatedTextEdit 51924- if err := json.Unmarshal(x, &h0); err == nil { 51925- t.Value = h0 51926- return nil 51927- } 51928- var h1 TextEdit 51929- if err := json.Unmarshal(x, &h1); err == nil { 51930- t.Value = h1 51931- return nil 51932- } 51933- return &UnmarshalError{"unmarshal failed to match one of [AnnotatedTextEdit TextEdit]"} 51934-} 51935- 51936-// from line 9777 51937-func (t Or_TextDocumentSyncOptions_save) MarshalJSON() ([]byte, error) { 51938- switch x := t.Value.(type) { 51939- case SaveOptions: 51940- return json.Marshal(x) 51941- case bool: 51942- return json.Marshal(x) 51943- case nil: 51944- return []byte("null"), nil 51945- } 51946- return nil, fmt.Errorf("type %T not one of [SaveOptions bool]", t) 51947-} 51948- 51949-func (t *Or_TextDocumentSyncOptions_save) UnmarshalJSON(x []byte) error { 51950- if string(x) == "null" { 51951- t.Value = nil 51952- return nil 51953- } 51954- var h0 SaveOptions 51955- if err := json.Unmarshal(x, &h0); err == nil { 51956- t.Value = h0 51957- return nil 51958- } 51959- var h1 bool 51960- if err := json.Unmarshal(x, &h1); err == nil { 51961- t.Value = h1 51962- return nil 51963- } 51964- return &UnmarshalError{"unmarshal failed to match one of [SaveOptions bool]"} 51965-} 51966- 51967-// from line 13986 51968-func (t Or_WorkspaceDocumentDiagnosticReport) MarshalJSON() ([]byte, error) { 51969- switch x := t.Value.(type) { 51970- case WorkspaceFullDocumentDiagnosticReport: 51971- return json.Marshal(x) 51972- case WorkspaceUnchangedDocumentDiagnosticReport: 51973- return json.Marshal(x) 51974- case nil: 51975- return []byte("null"), nil 51976- } 51977- return nil, fmt.Errorf("type %T not one of [WorkspaceFullDocumentDiagnosticReport WorkspaceUnchangedDocumentDiagnosticReport]", t) 51978-} 51979- 51980-func (t *Or_WorkspaceDocumentDiagnosticReport) UnmarshalJSON(x []byte) error { 51981- if string(x) == "null" { 51982- t.Value = nil 51983- return nil 51984- } 51985- var h0 WorkspaceFullDocumentDiagnosticReport 51986- if err := json.Unmarshal(x, &h0); err == nil { 51987- t.Value = h0 51988- return nil 51989- } 51990- var h1 WorkspaceUnchangedDocumentDiagnosticReport 51991- if err := json.Unmarshal(x, &h1); err == nil { 51992- t.Value = h1 51993- return nil 51994- } 51995- return &UnmarshalError{"unmarshal failed to match one of [WorkspaceFullDocumentDiagnosticReport WorkspaceUnchangedDocumentDiagnosticReport]"} 51996-} 51997- 51998-// from line 3219 51999-func (t Or_WorkspaceEdit_documentChanges_Elem) MarshalJSON() ([]byte, error) { 52000- switch x := t.Value.(type) { 52001- case CreateFile: 52002- return json.Marshal(x) 52003- case DeleteFile: 52004- return json.Marshal(x) 52005- case RenameFile: 52006- return json.Marshal(x) 52007- case TextDocumentEdit: 52008- return json.Marshal(x) 52009- case nil: 52010- return []byte("null"), nil 52011- } 52012- return nil, fmt.Errorf("type %T not one of [CreateFile DeleteFile RenameFile TextDocumentEdit]", t) 52013-} 52014- 52015-func (t *Or_WorkspaceEdit_documentChanges_Elem) UnmarshalJSON(x []byte) error { 52016- if string(x) == "null" { 52017- t.Value = nil 52018- return nil 52019- } 52020- var h0 CreateFile 52021- if err := json.Unmarshal(x, &h0); err == nil { 52022- t.Value = h0 52023- return nil 52024- } 52025- var h1 DeleteFile 52026- if err := json.Unmarshal(x, &h1); err == nil { 52027- t.Value = h1 52028- return nil 52029- } 52030- var h2 RenameFile 52031- if err := json.Unmarshal(x, &h2); err == nil { 52032- t.Value = h2 52033- return nil 52034- } 52035- var h3 TextDocumentEdit 52036- if err := json.Unmarshal(x, &h3); err == nil { 52037- t.Value = h3 52038- return nil 52039- } 52040- return &UnmarshalError{"unmarshal failed to match one of [CreateFile DeleteFile RenameFile TextDocumentEdit]"} 52041-} 52042- 52043-// from line 248 52044-func (t Or_textDocument_declaration) MarshalJSON() ([]byte, error) { 52045- switch x := t.Value.(type) { 52046- case Declaration: 52047- return json.Marshal(x) 52048- case []DeclarationLink: 52049- return json.Marshal(x) 52050- case nil: 52051- return []byte("null"), nil 52052- } 52053- return nil, fmt.Errorf("type %T not one of [Declaration []DeclarationLink]", t) 52054-} 52055- 52056-func (t *Or_textDocument_declaration) UnmarshalJSON(x []byte) error { 52057- if string(x) == "null" { 52058- t.Value = nil 52059- return nil 52060- } 52061- var h0 Declaration 52062- if err := json.Unmarshal(x, &h0); err == nil { 52063- t.Value = h0 52064- return nil 52065- } 52066- var h1 []DeclarationLink 52067- if err := json.Unmarshal(x, &h1); err == nil { 52068- t.Value = h1 52069- return nil 52070- } 52071- return &UnmarshalError{"unmarshal failed to match one of [Declaration []DeclarationLink]"} 52072-} 52073diff -urN a/gopls/internal/lsp/protocol/tsprotocol.go b/gopls/internal/lsp/protocol/tsprotocol.go 52074--- a/gopls/internal/lsp/protocol/tsprotocol.go 2000-01-01 00:00:00.000000000 -0000 52075+++ b/gopls/internal/lsp/protocol/tsprotocol.go 1970-01-01 00:00:00.000000000 +0000 52076@@ -1,5450 +0,0 @@ 52077-// Copyright 2023 The Go Authors. All rights reserved. 52078-// Use of this source code is governed by a BSD-style 52079-// license that can be found in the LICENSE file. 52080- 52081-// Code generated for LSP. DO NOT EDIT. 52082- 52083-package protocol 52084- 52085-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f). 52086-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json 52087-// LSP metaData.version = 3.17.0. 52088- 52089-import "encoding/json" 52090- 52091-// A special text edit with an additional change annotation. 52092-// 52093-// @since 3.16.0. 52094-type AnnotatedTextEdit struct { // line 9372 52095- // The actual identifier of the change annotation 52096- AnnotationID ChangeAnnotationIdentifier `json:"annotationId"` 52097- TextEdit 52098-} 52099- 52100-// The parameters passed via a apply workspace edit request. 52101-type ApplyWorkspaceEditParams struct { // line 5984 52102- // An optional label of the workspace edit. This label is 52103- // presented in the user interface for example on an undo 52104- // stack to undo the workspace edit. 52105- Label string `json:"label,omitempty"` 52106- // The edits to apply. 52107- Edit WorkspaceEdit `json:"edit"` 52108-} 52109- 52110-// The result returned from the apply workspace edit request. 52111-// 52112-// @since 3.17 renamed from ApplyWorkspaceEditResponse 52113-type ApplyWorkspaceEditResult struct { // line 6007 52114- // Indicates whether the edit was applied or not. 52115- Applied bool `json:"applied"` 52116- // An optional textual description for why the edit was not applied. 52117- // This may be used by the server for diagnostic logging or to provide 52118- // a suitable error for a request that triggered the edit. 52119- FailureReason string `json:"failureReason,omitempty"` 52120- // Depending on the client's failure handling strategy `failedChange` might 52121- // contain the index of the change that failed. This property is only available 52122- // if the client signals a `failureHandlingStrategy` in its client capabilities. 52123- FailedChange uint32 `json:"failedChange,omitempty"` 52124-} 52125- 52126-// A base for all symbol information. 52127-type BaseSymbolInformation struct { // line 8966 52128- // The name of this symbol. 52129- Name string `json:"name"` 52130- // The kind of this symbol. 52131- Kind SymbolKind `json:"kind"` 52132- // Tags for this symbol. 52133- // 52134- // @since 3.16.0 52135- Tags []SymbolTag `json:"tags,omitempty"` 52136- // The name of the symbol containing this symbol. This information is for 52137- // user interface purposes (e.g. to render a qualifier in the user interface 52138- // if necessary). It can't be used to re-infer a hierarchy for the document 52139- // symbols. 52140- ContainerName string `json:"containerName,omitempty"` 52141-} 52142- 52143-// @since 3.16.0 52144-type CallHierarchyClientCapabilities struct { // line 12141 52145- // Whether implementation supports dynamic registration. If this is set to `true` 52146- // the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` 52147- // return value for the corresponding server capability as well. 52148- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52149-} 52150- 52151-// Represents an incoming call, e.g. a caller of a method or constructor. 52152-// 52153-// @since 3.16.0 52154-type CallHierarchyIncomingCall struct { // line 2779 52155- // The item that makes the call. 52156- From CallHierarchyItem `json:"from"` 52157- // The ranges at which the calls appear. This is relative to the caller 52158- // denoted by {@link CallHierarchyIncomingCall.from `this.from`}. 52159- FromRanges []Range `json:"fromRanges"` 52160-} 52161- 52162-// The parameter of a `callHierarchy/incomingCalls` request. 52163-// 52164-// @since 3.16.0 52165-type CallHierarchyIncomingCallsParams struct { // line 2755 52166- Item CallHierarchyItem `json:"item"` 52167- WorkDoneProgressParams 52168- PartialResultParams 52169-} 52170- 52171-// Represents programming constructs like functions or constructors in the context 52172-// of call hierarchy. 52173-// 52174-// @since 3.16.0 52175-type CallHierarchyItem struct { // line 2656 52176- // The name of this item. 52177- Name string `json:"name"` 52178- // The kind of this item. 52179- Kind SymbolKind `json:"kind"` 52180- // Tags for this item. 52181- Tags []SymbolTag `json:"tags,omitempty"` 52182- // More detail for this item, e.g. the signature of a function. 52183- Detail string `json:"detail,omitempty"` 52184- // The resource identifier of this item. 52185- URI DocumentURI `json:"uri"` 52186- // The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. 52187- Range Range `json:"range"` 52188- // The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. 52189- // Must be contained by the {@link CallHierarchyItem.range `range`}. 52190- SelectionRange Range `json:"selectionRange"` 52191- // A data entry field that is preserved between a call hierarchy prepare and 52192- // incoming calls or outgoing calls requests. 52193- Data interface{} `json:"data,omitempty"` 52194-} 52195- 52196-// Call hierarchy options used during static registration. 52197-// 52198-// @since 3.16.0 52199-type CallHierarchyOptions struct { // line 6534 52200- WorkDoneProgressOptions 52201-} 52202- 52203-// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. 52204-// 52205-// @since 3.16.0 52206-type CallHierarchyOutgoingCall struct { // line 2829 52207- // The item that is called. 52208- To CallHierarchyItem `json:"to"` 52209- // The range at which this item is called. This is the range relative to the caller, e.g the item 52210- // passed to {@link CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls `provideCallHierarchyOutgoingCalls`} 52211- // and not {@link CallHierarchyOutgoingCall.to `this.to`}. 52212- FromRanges []Range `json:"fromRanges"` 52213-} 52214- 52215-// The parameter of a `callHierarchy/outgoingCalls` request. 52216-// 52217-// @since 3.16.0 52218-type CallHierarchyOutgoingCallsParams struct { // line 2805 52219- Item CallHierarchyItem `json:"item"` 52220- WorkDoneProgressParams 52221- PartialResultParams 52222-} 52223- 52224-// The parameter of a `textDocument/prepareCallHierarchy` request. 52225-// 52226-// @since 3.16.0 52227-type CallHierarchyPrepareParams struct { // line 2638 52228- TextDocumentPositionParams 52229- WorkDoneProgressParams 52230-} 52231- 52232-// Call hierarchy options used during static or dynamic registration. 52233-// 52234-// @since 3.16.0 52235-type CallHierarchyRegistrationOptions struct { // line 2733 52236- TextDocumentRegistrationOptions 52237- CallHierarchyOptions 52238- StaticRegistrationOptions 52239-} 52240-type CancelParams struct { // line 6179 52241- // The request id to cancel. 52242- ID interface{} `json:"id"` 52243-} 52244- 52245-// Additional information that describes document changes. 52246-// 52247-// @since 3.16.0 52248-type ChangeAnnotation struct { // line 6831 52249- // A human-readable string describing the actual change. The string 52250- // is rendered prominent in the user interface. 52251- Label string `json:"label"` 52252- // A flag which indicates that user confirmation is needed 52253- // before applying the change. 52254- NeedsConfirmation bool `json:"needsConfirmation,omitempty"` 52255- // A human-readable string which is rendered less prominent in 52256- // the user interface. 52257- Description string `json:"description,omitempty"` 52258-} 52259- 52260-// An identifier to refer to a change annotation stored with a workspace edit. 52261-type ChangeAnnotationIdentifier = string // (alias) line 13976 52262-// Defines the capabilities provided by the client. 52263-type ClientCapabilities struct { // line 9674 52264- // Workspace specific client capabilities. 52265- Workspace WorkspaceClientCapabilities `json:"workspace,omitempty"` 52266- // Text document specific client capabilities. 52267- TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"` 52268- // Capabilities specific to the notebook document support. 52269- // 52270- // @since 3.17.0 52271- NotebookDocument *NotebookDocumentClientCapabilities `json:"notebookDocument,omitempty"` 52272- // Window specific client capabilities. 52273- Window WindowClientCapabilities `json:"window,omitempty"` 52274- // General client capabilities. 52275- // 52276- // @since 3.16.0 52277- General *GeneralClientCapabilities `json:"general,omitempty"` 52278- // Experimental client capabilities. 52279- Experimental interface{} `json:"experimental,omitempty"` 52280-} 52281- 52282-// A code action represents a change that can be performed in code, e.g. to fix a problem or 52283-// to refactor code. 52284-// 52285-// A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed. 52286-type CodeAction struct { // line 5382 52287- // A short, human-readable, title for this code action. 52288- Title string `json:"title"` 52289- // The kind of the code action. 52290- // 52291- // Used to filter code actions. 52292- Kind CodeActionKind `json:"kind,omitempty"` 52293- // The diagnostics that this code action resolves. 52294- Diagnostics []Diagnostic `json:"diagnostics,omitempty"` 52295- // Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted 52296- // by keybindings. 52297- // 52298- // A quick fix should be marked preferred if it properly addresses the underlying error. 52299- // A refactoring should be marked preferred if it is the most reasonable choice of actions to take. 52300- // 52301- // @since 3.15.0 52302- IsPreferred bool `json:"isPreferred,omitempty"` 52303- // Marks that the code action cannot currently be applied. 52304- // 52305- // Clients should follow the following guidelines regarding disabled code actions: 52306- // 52307- // - Disabled code actions are not shown in automatic [lightbulbs](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) 52308- // code action menus. 52309- // 52310- // - Disabled actions are shown as faded out in the code action menu when the user requests a more specific type 52311- // of code action, such as refactorings. 52312- // 52313- // - If the user has a [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) 52314- // that auto applies a code action and only disabled code actions are returned, the client should show the user an 52315- // error message with `reason` in the editor. 52316- // 52317- // @since 3.16.0 52318- Disabled *PDisabledMsg_textDocument_codeAction `json:"disabled,omitempty"` 52319- // The workspace edit this code action performs. 52320- Edit *WorkspaceEdit `json:"edit,omitempty"` 52321- // A command this code action executes. If a code action 52322- // provides an edit and a command, first the edit is 52323- // executed and then the command. 52324- Command *Command `json:"command,omitempty"` 52325- // A data entry field that is preserved on a code action between 52326- // a `textDocument/codeAction` and a `codeAction/resolve` request. 52327- // 52328- // @since 3.16.0 52329- Data interface{} `json:"data,omitempty"` 52330-} 52331- 52332-// The Client Capabilities of a {@link CodeActionRequest}. 52333-type CodeActionClientCapabilities struct { // line 11721 52334- // Whether code action supports dynamic registration. 52335- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52336- // The client support code action literals of type `CodeAction` as a valid 52337- // response of the `textDocument/codeAction` request. If the property is not 52338- // set the request can only return `Command` literals. 52339- // 52340- // @since 3.8.0 52341- CodeActionLiteralSupport PCodeActionLiteralSupportPCodeAction `json:"codeActionLiteralSupport,omitempty"` 52342- // Whether code action supports the `isPreferred` property. 52343- // 52344- // @since 3.15.0 52345- IsPreferredSupport bool `json:"isPreferredSupport,omitempty"` 52346- // Whether code action supports the `disabled` property. 52347- // 52348- // @since 3.16.0 52349- DisabledSupport bool `json:"disabledSupport,omitempty"` 52350- // Whether code action supports the `data` property which is 52351- // preserved between a `textDocument/codeAction` and a 52352- // `codeAction/resolve` request. 52353- // 52354- // @since 3.16.0 52355- DataSupport bool `json:"dataSupport,omitempty"` 52356- // Whether the client supports resolving additional code action 52357- // properties via a separate `codeAction/resolve` request. 52358- // 52359- // @since 3.16.0 52360- ResolveSupport *PResolveSupportPCodeAction `json:"resolveSupport,omitempty"` 52361- // Whether the client honors the change annotations in 52362- // text edits and resource operations returned via the 52363- // `CodeAction#edit` property by for example presenting 52364- // the workspace edit in the user interface and asking 52365- // for confirmation. 52366- // 52367- // @since 3.16.0 52368- HonorsChangeAnnotations bool `json:"honorsChangeAnnotations,omitempty"` 52369-} 52370- 52371-// Contains additional diagnostic information about the context in which 52372-// a {@link CodeActionProvider.provideCodeActions code action} is run. 52373-type CodeActionContext struct { // line 9032 52374- // An array of diagnostics known on the client side overlapping the range provided to the 52375- // `textDocument/codeAction` request. They are provided so that the server knows which 52376- // errors are currently presented to the user for the given range. There is no guarantee 52377- // that these accurately reflect the error state of the resource. The primary parameter 52378- // to compute code actions is the provided range. 52379- Diagnostics []Diagnostic `json:"diagnostics"` 52380- // Requested kind of actions to return. 52381- // 52382- // Actions not of this kind are filtered out by the client before being shown. So servers 52383- // can omit computing them. 52384- Only []CodeActionKind `json:"only,omitempty"` 52385- // The reason why code actions were requested. 52386- // 52387- // @since 3.17.0 52388- TriggerKind *CodeActionTriggerKind `json:"triggerKind,omitempty"` 52389-} 52390- 52391-// A set of predefined code action kinds 52392-type CodeActionKind string // line 13326 52393-// Provider options for a {@link CodeActionRequest}. 52394-type CodeActionOptions struct { // line 9071 52395- // CodeActionKinds that this server may return. 52396- // 52397- // The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server 52398- // may list out every specific kind they provide. 52399- CodeActionKinds []CodeActionKind `json:"codeActionKinds,omitempty"` 52400- // The server provides support to resolve additional 52401- // information for a code action. 52402- // 52403- // @since 3.16.0 52404- ResolveProvider bool `json:"resolveProvider,omitempty"` 52405- WorkDoneProgressOptions 52406-} 52407- 52408-// The parameters of a {@link CodeActionRequest}. 52409-type CodeActionParams struct { // line 5308 52410- // The document in which the command was invoked. 52411- TextDocument TextDocumentIdentifier `json:"textDocument"` 52412- // The range for which the command was invoked. 52413- Range Range `json:"range"` 52414- // Context carrying additional information. 52415- Context CodeActionContext `json:"context"` 52416- WorkDoneProgressParams 52417- PartialResultParams 52418-} 52419- 52420-// Registration options for a {@link CodeActionRequest}. 52421-type CodeActionRegistrationOptions struct { // line 5476 52422- TextDocumentRegistrationOptions 52423- CodeActionOptions 52424-} 52425- 52426-// The reason why code actions were requested. 52427-// 52428-// @since 3.17.0 52429-type CodeActionTriggerKind uint32 // line 13606 52430-// Structure to capture a description for an error code. 52431-// 52432-// @since 3.16.0 52433-type CodeDescription struct { // line 10026 52434- // An URI to open with more information about the diagnostic error. 52435- Href URI `json:"href"` 52436-} 52437- 52438-// A code lens represents a {@link Command command} that should be shown along with 52439-// source text, like the number of references, a way to run tests, etc. 52440-// 52441-// A code lens is _unresolved_ when no command is associated to it. For performance 52442-// reasons the creation of a code lens and resolving should be done in two stages. 52443-type CodeLens struct { // line 5599 52444- // The range in which this code lens is valid. Should only span a single line. 52445- Range Range `json:"range"` 52446- // The command this code lens represents. 52447- Command *Command `json:"command,omitempty"` 52448- // A data entry field that is preserved on a code lens item between 52449- // a {@link CodeLensRequest} and a [CodeLensResolveRequest] 52450- // (#CodeLensResolveRequest) 52451- Data interface{} `json:"data,omitempty"` 52452-} 52453- 52454-// The client capabilities of a {@link CodeLensRequest}. 52455-type CodeLensClientCapabilities struct { // line 11835 52456- // Whether code lens supports dynamic registration. 52457- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52458-} 52459- 52460-// Code Lens provider options of a {@link CodeLensRequest}. 52461-type CodeLensOptions struct { // line 9127 52462- // Code lens has a resolve provider as well. 52463- ResolveProvider bool `json:"resolveProvider,omitempty"` 52464- WorkDoneProgressOptions 52465-} 52466- 52467-// The parameters of a {@link CodeLensRequest}. 52468-type CodeLensParams struct { // line 5575 52469- // The document to request code lens for. 52470- TextDocument TextDocumentIdentifier `json:"textDocument"` 52471- WorkDoneProgressParams 52472- PartialResultParams 52473-} 52474- 52475-// Registration options for a {@link CodeLensRequest}. 52476-type CodeLensRegistrationOptions struct { // line 5631 52477- TextDocumentRegistrationOptions 52478- CodeLensOptions 52479-} 52480- 52481-// @since 3.16.0 52482-type CodeLensWorkspaceClientCapabilities struct { // line 10993 52483- // Whether the client implementation supports a refresh request sent from the 52484- // server to the client. 52485- // 52486- // Note that this event is global and will force the client to refresh all 52487- // code lenses currently shown. It should be used with absolute care and is 52488- // useful for situation where a server for example detect a project wide 52489- // change that requires such a calculation. 52490- RefreshSupport bool `json:"refreshSupport,omitempty"` 52491-} 52492- 52493-// Represents a color in RGBA space. 52494-type Color struct { // line 6433 52495- // The red component of this color in the range [0-1]. 52496- Red float64 `json:"red"` 52497- // The green component of this color in the range [0-1]. 52498- Green float64 `json:"green"` 52499- // The blue component of this color in the range [0-1]. 52500- Blue float64 `json:"blue"` 52501- // The alpha component of this color in the range [0-1]. 52502- Alpha float64 `json:"alpha"` 52503-} 52504- 52505-// Represents a color range from a document. 52506-type ColorInformation struct { // line 2239 52507- // The range in the document where this color appears. 52508- Range Range `json:"range"` 52509- // The actual color value for this color range. 52510- Color Color `json:"color"` 52511-} 52512-type ColorPresentation struct { // line 2321 52513- // The label of this color presentation. It will be shown on the color 52514- // picker header. By default this is also the text that is inserted when selecting 52515- // this color presentation. 52516- Label string `json:"label"` 52517- // An {@link TextEdit edit} which is applied to a document when selecting 52518- // this presentation for the color. When `falsy` the {@link ColorPresentation.label label} 52519- // is used. 52520- TextEdit *TextEdit `json:"textEdit,omitempty"` 52521- // An optional array of additional {@link TextEdit text edits} that are applied when 52522- // selecting this color presentation. Edits must not overlap with the main {@link ColorPresentation.textEdit edit} nor with themselves. 52523- AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` 52524-} 52525- 52526-// Parameters for a {@link ColorPresentationRequest}. 52527-type ColorPresentationParams struct { // line 2281 52528- // The text document. 52529- TextDocument TextDocumentIdentifier `json:"textDocument"` 52530- // The color to request presentations for. 52531- Color Color `json:"color"` 52532- // The range where the color would be inserted. Serves as a context. 52533- Range Range `json:"range"` 52534- WorkDoneProgressParams 52535- PartialResultParams 52536-} 52537- 52538-// Represents a reference to a command. Provides a title which 52539-// will be used to represent a command in the UI and, optionally, 52540-// an array of arguments which will be passed to the command handler 52541-// function when invoked. 52542-type Command struct { // line 5348 52543- // Title of the command, like `save`. 52544- Title string `json:"title"` 52545- // The identifier of the actual command handler. 52546- Command string `json:"command"` 52547- // Arguments that the command handler should be 52548- // invoked with. 52549- Arguments []json.RawMessage `json:"arguments,omitempty"` 52550-} 52551- 52552-// Completion client capabilities 52553-type CompletionClientCapabilities struct { // line 11168 52554- // Whether completion supports dynamic registration. 52555- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52556- // The client supports the following `CompletionItem` specific 52557- // capabilities. 52558- CompletionItem PCompletionItemPCompletion `json:"completionItem,omitempty"` 52559- CompletionItemKind *PCompletionItemKindPCompletion `json:"completionItemKind,omitempty"` 52560- // Defines how the client handles whitespace and indentation 52561- // when accepting a completion item that uses multi line 52562- // text in either `insertText` or `textEdit`. 52563- // 52564- // @since 3.17.0 52565- InsertTextMode InsertTextMode `json:"insertTextMode,omitempty"` 52566- // The client supports to send additional context information for a 52567- // `textDocument/completion` request. 52568- ContextSupport bool `json:"contextSupport,omitempty"` 52569- // The client supports the following `CompletionList` specific 52570- // capabilities. 52571- // 52572- // @since 3.17.0 52573- CompletionList *PCompletionListPCompletion `json:"completionList,omitempty"` 52574-} 52575- 52576-// Contains additional information about the context in which a completion request is triggered. 52577-type CompletionContext struct { // line 8628 52578- // How the completion was triggered. 52579- TriggerKind CompletionTriggerKind `json:"triggerKind"` 52580- // The trigger character (a single character) that has trigger code complete. 52581- // Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` 52582- TriggerCharacter string `json:"triggerCharacter,omitempty"` 52583-} 52584- 52585-// A completion item represents a text snippet that is 52586-// proposed to complete text that is being typed. 52587-type CompletionItem struct { // line 4528 52588- // The label of this completion item. 52589- // 52590- // The label property is also by default the text that 52591- // is inserted when selecting this completion. 52592- // 52593- // If label details are provided the label itself should 52594- // be an unqualified name of the completion item. 52595- Label string `json:"label"` 52596- // Additional details for the label 52597- // 52598- // @since 3.17.0 52599- LabelDetails *CompletionItemLabelDetails `json:"labelDetails,omitempty"` 52600- // The kind of this completion item. Based of the kind 52601- // an icon is chosen by the editor. 52602- Kind CompletionItemKind `json:"kind,omitempty"` 52603- // Tags for this completion item. 52604- // 52605- // @since 3.15.0 52606- Tags []CompletionItemTag `json:"tags,omitempty"` 52607- // A human-readable string with additional information 52608- // about this item, like type or symbol information. 52609- Detail string `json:"detail,omitempty"` 52610- // A human-readable string that represents a doc-comment. 52611- Documentation *Or_CompletionItem_documentation `json:"documentation,omitempty"` 52612- // Indicates if this item is deprecated. 52613- // @deprecated Use `tags` instead. 52614- Deprecated bool `json:"deprecated,omitempty"` 52615- // Select this item when showing. 52616- // 52617- // *Note* that only one completion item can be selected and that the 52618- // tool / client decides which item that is. The rule is that the *first* 52619- // item of those that match best is selected. 52620- Preselect bool `json:"preselect,omitempty"` 52621- // A string that should be used when comparing this item 52622- // with other items. When `falsy` the {@link CompletionItem.label label} 52623- // is used. 52624- SortText string `json:"sortText,omitempty"` 52625- // A string that should be used when filtering a set of 52626- // completion items. When `falsy` the {@link CompletionItem.label label} 52627- // is used. 52628- FilterText string `json:"filterText,omitempty"` 52629- // A string that should be inserted into a document when selecting 52630- // this completion. When `falsy` the {@link CompletionItem.label label} 52631- // is used. 52632- // 52633- // The `insertText` is subject to interpretation by the client side. 52634- // Some tools might not take the string literally. For example 52635- // VS Code when code complete is requested in this example 52636- // `con<cursor position>` and a completion item with an `insertText` of 52637- // `console` is provided it will only insert `sole`. Therefore it is 52638- // recommended to use `textEdit` instead since it avoids additional client 52639- // side interpretation. 52640- InsertText string `json:"insertText,omitempty"` 52641- // The format of the insert text. The format applies to both the 52642- // `insertText` property and the `newText` property of a provided 52643- // `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`. 52644- // 52645- // Please note that the insertTextFormat doesn't apply to 52646- // `additionalTextEdits`. 52647- InsertTextFormat *InsertTextFormat `json:"insertTextFormat,omitempty"` 52648- // How whitespace and indentation is handled during completion 52649- // item insertion. If not provided the clients default value depends on 52650- // the `textDocument.completion.insertTextMode` client capability. 52651- // 52652- // @since 3.16.0 52653- InsertTextMode *InsertTextMode `json:"insertTextMode,omitempty"` 52654- // An {@link TextEdit edit} which is applied to a document when selecting 52655- // this completion. When an edit is provided the value of 52656- // {@link CompletionItem.insertText insertText} is ignored. 52657- // 52658- // Most editors support two different operations when accepting a completion 52659- // item. One is to insert a completion text and the other is to replace an 52660- // existing text with a completion text. Since this can usually not be 52661- // predetermined by a server it can report both ranges. Clients need to 52662- // signal support for `InsertReplaceEdits` via the 52663- // `textDocument.completion.insertReplaceSupport` client capability 52664- // property. 52665- // 52666- // *Note 1:* The text edit's range as well as both ranges from an insert 52667- // replace edit must be a [single line] and they must contain the position 52668- // at which completion has been requested. 52669- // *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range 52670- // must be a prefix of the edit's replace range, that means it must be 52671- // contained and starting at the same position. 52672- // 52673- // @since 3.16.0 additional type `InsertReplaceEdit` 52674- TextEdit *TextEdit `json:"textEdit,omitempty"` 52675- // The edit text used if the completion item is part of a CompletionList and 52676- // CompletionList defines an item default for the text edit range. 52677- // 52678- // Clients will only honor this property if they opt into completion list 52679- // item defaults using the capability `completionList.itemDefaults`. 52680- // 52681- // If not provided and a list's default range is provided the label 52682- // property is used as a text. 52683- // 52684- // @since 3.17.0 52685- TextEditText string `json:"textEditText,omitempty"` 52686- // An optional array of additional {@link TextEdit text edits} that are applied when 52687- // selecting this completion. Edits must not overlap (including the same insert position) 52688- // with the main {@link CompletionItem.textEdit edit} nor with themselves. 52689- // 52690- // Additional text edits should be used to change text unrelated to the current cursor position 52691- // (for example adding an import statement at the top of the file if the completion item will 52692- // insert an unqualified type). 52693- AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` 52694- // An optional set of characters that when pressed while this completion is active will accept it first and 52695- // then type that character. *Note* that all commit characters should have `length=1` and that superfluous 52696- // characters will be ignored. 52697- CommitCharacters []string `json:"commitCharacters,omitempty"` 52698- // An optional {@link Command command} that is executed *after* inserting this completion. *Note* that 52699- // additional modifications to the current document should be described with the 52700- // {@link CompletionItem.additionalTextEdits additionalTextEdits}-property. 52701- Command *Command `json:"command,omitempty"` 52702- // A data entry field that is preserved on a completion item between a 52703- // {@link CompletionRequest} and a {@link CompletionResolveRequest}. 52704- Data interface{} `json:"data,omitempty"` 52705-} 52706- 52707-// The kind of a completion entry. 52708-type CompletionItemKind uint32 // line 13134 52709-// Additional details for a completion item label. 52710-// 52711-// @since 3.17.0 52712-type CompletionItemLabelDetails struct { // line 8651 52713- // An optional string which is rendered less prominently directly after {@link CompletionItem.label label}, 52714- // without any spacing. Should be used for function signatures and type annotations. 52715- Detail string `json:"detail,omitempty"` 52716- // An optional string which is rendered less prominently after {@link CompletionItem.detail}. Should be used 52717- // for fully qualified names and file paths. 52718- Description string `json:"description,omitempty"` 52719-} 52720- 52721-// Completion item tags are extra annotations that tweak the rendering of a completion 52722-// item. 52723-// 52724-// @since 3.15.0 52725-type CompletionItemTag uint32 // line 13244 52726-// Represents a collection of {@link CompletionItem completion items} to be presented 52727-// in the editor. 52728-type CompletionList struct { // line 4737 52729- // This list it not complete. Further typing results in recomputing this list. 52730- // 52731- // Recomputed lists have all their items replaced (not appended) in the 52732- // incomplete completion sessions. 52733- IsIncomplete bool `json:"isIncomplete"` 52734- // In many cases the items of an actual completion result share the same 52735- // value for properties like `commitCharacters` or the range of a text 52736- // edit. A completion list can therefore define item defaults which will 52737- // be used if a completion item itself doesn't specify the value. 52738- // 52739- // If a completion list specifies a default value and a completion item 52740- // also specifies a corresponding value the one from the item is used. 52741- // 52742- // Servers are only allowed to return default values if the client 52743- // signals support for this via the `completionList.itemDefaults` 52744- // capability. 52745- // 52746- // @since 3.17.0 52747- ItemDefaults *PItemDefaultsMsg_textDocument_completion `json:"itemDefaults,omitempty"` 52748- // The completion items. 52749- Items []CompletionItem `json:"items"` 52750-} 52751- 52752-// Completion options. 52753-type CompletionOptions struct { // line 8707 52754- // Most tools trigger completion request automatically without explicitly requesting 52755- // it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user 52756- // starts to type an identifier. For example if the user types `c` in a JavaScript file 52757- // code complete will automatically pop up present `console` besides others as a 52758- // completion item. Characters that make up identifiers don't need to be listed here. 52759- // 52760- // If code complete should automatically be trigger on characters not being valid inside 52761- // an identifier (for example `.` in JavaScript) list them in `triggerCharacters`. 52762- TriggerCharacters []string `json:"triggerCharacters,omitempty"` 52763- // The list of all possible characters that commit a completion. This field can be used 52764- // if clients don't support individual commit characters per completion item. See 52765- // `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport` 52766- // 52767- // If a server provides both `allCommitCharacters` and commit characters on an individual 52768- // completion item the ones on the completion item win. 52769- // 52770- // @since 3.2.0 52771- AllCommitCharacters []string `json:"allCommitCharacters,omitempty"` 52772- // The server provides support to resolve additional 52773- // information for a completion item. 52774- ResolveProvider bool `json:"resolveProvider,omitempty"` 52775- // The server supports the following `CompletionItem` specific 52776- // capabilities. 52777- // 52778- // @since 3.17.0 52779- CompletionItem *PCompletionItemPCompletionProvider `json:"completionItem,omitempty"` 52780- WorkDoneProgressOptions 52781-} 52782- 52783-// Completion parameters 52784-type CompletionParams struct { // line 4497 52785- // The completion context. This is only available it the client specifies 52786- // to send this using the client capability `textDocument.completion.contextSupport === true` 52787- Context CompletionContext `json:"context,omitempty"` 52788- TextDocumentPositionParams 52789- WorkDoneProgressParams 52790- PartialResultParams 52791-} 52792- 52793-// Registration options for a {@link CompletionRequest}. 52794-type CompletionRegistrationOptions struct { // line 4854 52795- TextDocumentRegistrationOptions 52796- CompletionOptions 52797-} 52798- 52799-// How a completion was triggered 52800-type CompletionTriggerKind uint32 // line 13555 52801-type ConfigurationItem struct { // line 6396 52802- // The scope to get the configuration section for. 52803- ScopeURI string `json:"scopeUri,omitempty"` 52804- // The configuration section asked for. 52805- Section string `json:"section,omitempty"` 52806-} 52807- 52808-// The parameters of a configuration request. 52809-type ConfigurationParams struct { // line 2199 52810- Items []ConfigurationItem `json:"items"` 52811-} 52812- 52813-// Create file operation. 52814-type CreateFile struct { // line 6712 52815- // A create 52816- Kind string `json:"kind"` 52817- // The resource to create. 52818- URI DocumentURI `json:"uri"` 52819- // Additional options 52820- Options *CreateFileOptions `json:"options,omitempty"` 52821- ResourceOperation 52822-} 52823- 52824-// Options to create a file. 52825-type CreateFileOptions struct { // line 9417 52826- // Overwrite existing file. Overwrite wins over `ignoreIfExists` 52827- Overwrite bool `json:"overwrite,omitempty"` 52828- // Ignore if exists. 52829- IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` 52830-} 52831- 52832-// The parameters sent in notifications/requests for user-initiated creation of 52833-// files. 52834-// 52835-// @since 3.16.0 52836-type CreateFilesParams struct { // line 3175 52837- // An array of all files/folders created in this operation. 52838- Files []FileCreate `json:"files"` 52839-} 52840- 52841-// The declaration of a symbol representation as one or many {@link Location locations}. 52842-type Declaration = []Location // (alias) line 13833 52843-// @since 3.14.0 52844-type DeclarationClientCapabilities struct { // line 11509 52845- // Whether declaration supports dynamic registration. If this is set to `true` 52846- // the client supports the new `DeclarationRegistrationOptions` return value 52847- // for the corresponding server capability as well. 52848- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52849- // The client supports additional metadata in the form of declaration links. 52850- LinkSupport bool `json:"linkSupport,omitempty"` 52851-} 52852- 52853-// Information about where a symbol is declared. 52854-// 52855-// Provides additional metadata over normal {@link Location location} declarations, including the range of 52856-// the declaring symbol. 52857-// 52858-// Servers should prefer returning `DeclarationLink` over `Declaration` if supported 52859-// by the client. 52860-type DeclarationLink = LocationLink // (alias) line 13853 52861-type DeclarationOptions struct { // line 6491 52862- WorkDoneProgressOptions 52863-} 52864-type DeclarationParams struct { // line 2494 52865- TextDocumentPositionParams 52866- WorkDoneProgressParams 52867- PartialResultParams 52868-} 52869-type DeclarationRegistrationOptions struct { // line 2514 52870- DeclarationOptions 52871- TextDocumentRegistrationOptions 52872- StaticRegistrationOptions 52873-} 52874- 52875-// The definition of a symbol represented as one or many {@link Location locations}. 52876-// For most programming languages there is only one location at which a symbol is 52877-// defined. 52878-// 52879-// Servers should prefer returning `DefinitionLink` over `Definition` if supported 52880-// by the client. 52881-type Definition = Or_Definition // (alias) line 13751 52882-// Client Capabilities for a {@link DefinitionRequest}. 52883-type DefinitionClientCapabilities struct { // line 11534 52884- // Whether definition supports dynamic registration. 52885- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52886- // The client supports additional metadata in the form of definition links. 52887- // 52888- // @since 3.14.0 52889- LinkSupport bool `json:"linkSupport,omitempty"` 52890-} 52891- 52892-// Information about where a symbol is defined. 52893-// 52894-// Provides additional metadata over normal {@link Location location} definitions, including the range of 52895-// the defining symbol 52896-type DefinitionLink = LocationLink // (alias) line 13771 52897-// Server Capabilities for a {@link DefinitionRequest}. 52898-type DefinitionOptions struct { // line 8919 52899- WorkDoneProgressOptions 52900-} 52901- 52902-// Parameters for a {@link DefinitionRequest}. 52903-type DefinitionParams struct { // line 5018 52904- TextDocumentPositionParams 52905- WorkDoneProgressParams 52906- PartialResultParams 52907-} 52908- 52909-// Registration options for a {@link DefinitionRequest}. 52910-type DefinitionRegistrationOptions struct { // line 5039 52911- TextDocumentRegistrationOptions 52912- DefinitionOptions 52913-} 52914- 52915-// Delete file operation 52916-type DeleteFile struct { // line 6794 52917- // A delete 52918- Kind string `json:"kind"` 52919- // The file to delete. 52920- URI DocumentURI `json:"uri"` 52921- // Delete options. 52922- Options *DeleteFileOptions `json:"options,omitempty"` 52923- ResourceOperation 52924-} 52925- 52926-// Delete file options 52927-type DeleteFileOptions struct { // line 9465 52928- // Delete the content recursively if a folder is denoted. 52929- Recursive bool `json:"recursive,omitempty"` 52930- // Ignore the operation if the file doesn't exist. 52931- IgnoreIfNotExists bool `json:"ignoreIfNotExists,omitempty"` 52932-} 52933- 52934-// The parameters sent in notifications/requests for user-initiated deletes of 52935-// files. 52936-// 52937-// @since 3.16.0 52938-type DeleteFilesParams struct { // line 3300 52939- // An array of all files/folders deleted in this operation. 52940- Files []FileDelete `json:"files"` 52941-} 52942- 52943-// Represents a diagnostic, such as a compiler error or warning. Diagnostic objects 52944-// are only valid in the scope of a resource. 52945-type Diagnostic struct { // line 8525 52946- // The range at which the message applies 52947- Range Range `json:"range"` 52948- // The diagnostic's severity. Can be omitted. If omitted it is up to the 52949- // client to interpret diagnostics as error, warning, info or hint. 52950- Severity DiagnosticSeverity `json:"severity,omitempty"` 52951- // The diagnostic's code, which usually appear in the user interface. 52952- Code interface{} `json:"code,omitempty"` 52953- // An optional property to describe the error code. 52954- // Requires the code field (above) to be present/not null. 52955- // 52956- // @since 3.16.0 52957- CodeDescription *CodeDescription `json:"codeDescription,omitempty"` 52958- // A human-readable string describing the source of this 52959- // diagnostic, e.g. 'typescript' or 'super lint'. It usually 52960- // appears in the user interface. 52961- Source string `json:"source,omitempty"` 52962- // The diagnostic's message. It usually appears in the user interface 52963- Message string `json:"message"` 52964- // Additional metadata about the diagnostic. 52965- // 52966- // @since 3.15.0 52967- Tags []DiagnosticTag `json:"tags,omitempty"` 52968- // An array of related diagnostic information, e.g. when symbol-names within 52969- // a scope collide all definitions can be marked via this property. 52970- RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"` 52971- // A data entry field that is preserved between a `textDocument/publishDiagnostics` 52972- // notification and `textDocument/codeAction` request. 52973- // 52974- // @since 3.16.0 52975- Data interface{} `json:"data,omitempty"` 52976-} 52977- 52978-// Client capabilities specific to diagnostic pull requests. 52979-// 52980-// @since 3.17.0 52981-type DiagnosticClientCapabilities struct { // line 12408 52982- // Whether implementation supports dynamic registration. If this is set to `true` 52983- // the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` 52984- // return value for the corresponding server capability as well. 52985- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 52986- // Whether the clients supports related documents for document diagnostic pulls. 52987- RelatedDocumentSupport bool `json:"relatedDocumentSupport,omitempty"` 52988-} 52989- 52990-// Diagnostic options. 52991-// 52992-// @since 3.17.0 52993-type DiagnosticOptions struct { // line 7293 52994- // An optional identifier under which the diagnostics are 52995- // managed by the client. 52996- Identifier string `json:"identifier,omitempty"` 52997- // Whether the language has inter file dependencies meaning that 52998- // editing code in one file can result in a different diagnostic 52999- // set in another file. Inter file dependencies are common for 53000- // most programming languages and typically uncommon for linters. 53001- InterFileDependencies bool `json:"interFileDependencies"` 53002- // The server provides support for workspace diagnostics as well. 53003- WorkspaceDiagnostics bool `json:"workspaceDiagnostics"` 53004- WorkDoneProgressOptions 53005-} 53006- 53007-// Diagnostic registration options. 53008-// 53009-// @since 3.17.0 53010-type DiagnosticRegistrationOptions struct { // line 3855 53011- TextDocumentRegistrationOptions 53012- DiagnosticOptions 53013- StaticRegistrationOptions 53014-} 53015- 53016-// Represents a related message and source code location for a diagnostic. This should be 53017-// used to point to code locations that cause or related to a diagnostics, e.g when duplicating 53018-// a symbol in a scope. 53019-type DiagnosticRelatedInformation struct { // line 10041 53020- // The location of this related diagnostic information. 53021- Location Location `json:"location"` 53022- // The message of this related diagnostic information. 53023- Message string `json:"message"` 53024-} 53025- 53026-// Cancellation data returned from a diagnostic request. 53027-// 53028-// @since 3.17.0 53029-type DiagnosticServerCancellationData struct { // line 3841 53030- RetriggerRequest bool `json:"retriggerRequest"` 53031-} 53032- 53033-// The diagnostic's severity. 53034-type DiagnosticSeverity uint32 // line 13504 53035-// The diagnostic tags. 53036-// 53037-// @since 3.15.0 53038-type DiagnosticTag uint32 // line 13534 53039-// Workspace client capabilities specific to diagnostic pull requests. 53040-// 53041-// @since 3.17.0 53042-type DiagnosticWorkspaceClientCapabilities struct { // line 11111 53043- // Whether the client implementation supports a refresh request sent from 53044- // the server to the client. 53045- // 53046- // Note that this event is global and will force the client to refresh all 53047- // pulled diagnostics currently shown. It should be used with absolute care and 53048- // is useful for situation where a server for example detects a project wide 53049- // change that requires such a calculation. 53050- RefreshSupport bool `json:"refreshSupport,omitempty"` 53051-} 53052-type DidChangeConfigurationClientCapabilities struct { // line 10837 53053- // Did change configuration notification supports dynamic registration. 53054- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53055-} 53056- 53057-// The parameters of a change configuration notification. 53058-type DidChangeConfigurationParams struct { // line 4144 53059- // The actual changed settings 53060- Settings interface{} `json:"settings"` 53061-} 53062-type DidChangeConfigurationRegistrationOptions struct { // line 4158 53063- Section *OrPSection_workspace_didChangeConfiguration `json:"section,omitempty"` 53064-} 53065- 53066-// The params sent in a change notebook document notification. 53067-// 53068-// @since 3.17.0 53069-type DidChangeNotebookDocumentParams struct { // line 3974 53070- // The notebook document that did change. The version number points 53071- // to the version after all provided changes have been applied. If 53072- // only the text document content of a cell changes the notebook version 53073- // doesn't necessarily have to change. 53074- NotebookDocument VersionedNotebookDocumentIdentifier `json:"notebookDocument"` 53075- // The actual changes to the notebook document. 53076- // 53077- // The changes describe single state changes to the notebook document. 53078- // So if there are two changes c1 (at array index 0) and c2 (at array 53079- // index 1) for a notebook in state S then c1 moves the notebook from 53080- // S to S' and c2 from S' to S''. So c1 is computed on the state S and 53081- // c2 is computed on the state S'. 53082- // 53083- // To mirror the content of a notebook using change events use the following approach: 53084- // 53085- // - start with the same initial content 53086- // - apply the 'notebookDocument/didChange' notifications in the order you receive them. 53087- // - apply the `NotebookChangeEvent`s in a single notification in the order 53088- // you receive them. 53089- Change NotebookDocumentChangeEvent `json:"change"` 53090-} 53091- 53092-// The change text document notification's parameters. 53093-type DidChangeTextDocumentParams struct { // line 4287 53094- // The document that did change. The version number points 53095- // to the version after all provided content changes have 53096- // been applied. 53097- TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` 53098- // The actual content changes. The content changes describe single state changes 53099- // to the document. So if there are two content changes c1 (at array index 0) and 53100- // c2 (at array index 1) for a document in state S then c1 moves the document from 53101- // S to S' and c2 from S' to S''. So c1 is computed on the state S and c2 is computed 53102- // on the state S'. 53103- // 53104- // To mirror the content of a document using change events use the following approach: 53105- // 53106- // - start with the same initial content 53107- // - apply the 'textDocument/didChange' notifications in the order you receive them. 53108- // - apply the `TextDocumentContentChangeEvent`s in a single notification in the order 53109- // you receive them. 53110- ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` 53111-} 53112-type DidChangeWatchedFilesClientCapabilities struct { // line 10851 53113- // Did change watched files notification supports dynamic registration. Please note 53114- // that the current protocol doesn't support static configuration for file changes 53115- // from the server side. 53116- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53117- // Whether the client has support for {@link RelativePattern relative pattern} 53118- // or not. 53119- // 53120- // @since 3.17.0 53121- RelativePatternSupport bool `json:"relativePatternSupport,omitempty"` 53122-} 53123- 53124-// The watched files change notification's parameters. 53125-type DidChangeWatchedFilesParams struct { // line 4428 53126- // The actual file events. 53127- Changes []FileEvent `json:"changes"` 53128-} 53129- 53130-// Describe options to be used when registered for text document change events. 53131-type DidChangeWatchedFilesRegistrationOptions struct { // line 4445 53132- // The watchers to register. 53133- Watchers []FileSystemWatcher `json:"watchers"` 53134-} 53135- 53136-// The parameters of a `workspace/didChangeWorkspaceFolders` notification. 53137-type DidChangeWorkspaceFoldersParams struct { // line 2185 53138- // The actual workspace folder change event. 53139- Event WorkspaceFoldersChangeEvent `json:"event"` 53140-} 53141- 53142-// The params sent in a close notebook document notification. 53143-// 53144-// @since 3.17.0 53145-type DidCloseNotebookDocumentParams struct { // line 4012 53146- // The notebook document that got closed. 53147- NotebookDocument NotebookDocumentIdentifier `json:"notebookDocument"` 53148- // The text documents that represent the content 53149- // of a notebook cell that got closed. 53150- CellTextDocuments []TextDocumentIdentifier `json:"cellTextDocuments"` 53151-} 53152- 53153-// The parameters sent in a close text document notification 53154-type DidCloseTextDocumentParams struct { // line 4332 53155- // The document that was closed. 53156- TextDocument TextDocumentIdentifier `json:"textDocument"` 53157-} 53158- 53159-// The params sent in an open notebook document notification. 53160-// 53161-// @since 3.17.0 53162-type DidOpenNotebookDocumentParams struct { // line 3948 53163- // The notebook document that got opened. 53164- NotebookDocument NotebookDocument `json:"notebookDocument"` 53165- // The text documents that represent the content 53166- // of a notebook cell. 53167- CellTextDocuments []TextDocumentItem `json:"cellTextDocuments"` 53168-} 53169- 53170-// The parameters sent in an open text document notification 53171-type DidOpenTextDocumentParams struct { // line 4273 53172- // The document that was opened. 53173- TextDocument TextDocumentItem `json:"textDocument"` 53174-} 53175- 53176-// The params sent in a save notebook document notification. 53177-// 53178-// @since 3.17.0 53179-type DidSaveNotebookDocumentParams struct { // line 3997 53180- // The notebook document that got saved. 53181- NotebookDocument NotebookDocumentIdentifier `json:"notebookDocument"` 53182-} 53183- 53184-// The parameters sent in a save text document notification 53185-type DidSaveTextDocumentParams struct { // line 4346 53186- // The document that was saved. 53187- TextDocument TextDocumentIdentifier `json:"textDocument"` 53188- // Optional the content when saved. Depends on the includeText value 53189- // when the save notification was requested. 53190- Text *string `json:"text,omitempty"` 53191-} 53192-type DocumentColorClientCapabilities struct { // line 11875 53193- // Whether implementation supports dynamic registration. If this is set to `true` 53194- // the client supports the new `DocumentColorRegistrationOptions` return value 53195- // for the corresponding server capability as well. 53196- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53197-} 53198-type DocumentColorOptions struct { // line 6471 53199- WorkDoneProgressOptions 53200-} 53201- 53202-// Parameters for a {@link DocumentColorRequest}. 53203-type DocumentColorParams struct { // line 2215 53204- // The text document. 53205- TextDocument TextDocumentIdentifier `json:"textDocument"` 53206- WorkDoneProgressParams 53207- PartialResultParams 53208-} 53209-type DocumentColorRegistrationOptions struct { // line 2261 53210- TextDocumentRegistrationOptions 53211- DocumentColorOptions 53212- StaticRegistrationOptions 53213-} 53214- 53215-// Parameters of the document diagnostic request. 53216-// 53217-// @since 3.17.0 53218-type DocumentDiagnosticParams struct { // line 3768 53219- // The text document. 53220- TextDocument TextDocumentIdentifier `json:"textDocument"` 53221- // The additional identifier provided during registration. 53222- Identifier string `json:"identifier,omitempty"` 53223- // The result id of a previous response if provided. 53224- PreviousResultID string `json:"previousResultId,omitempty"` 53225- WorkDoneProgressParams 53226- PartialResultParams 53227-} 53228-type DocumentDiagnosticReport = Or_DocumentDiagnosticReport // (alias) line 13909 53229-// The document diagnostic report kinds. 53230-// 53231-// @since 3.17.0 53232-type DocumentDiagnosticReportKind string // line 12722 53233-// A partial result for a document diagnostic report. 53234-// 53235-// @since 3.17.0 53236-type DocumentDiagnosticReportPartialResult struct { // line 3811 53237- RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments"` 53238-} 53239- 53240-// A document filter describes a top level text document or 53241-// a notebook cell document. 53242-// 53243-// @since 3.17.0 - proposed support for NotebookCellTextDocumentFilter. 53244-type DocumentFilter = Or_DocumentFilter // (alias) line 14093 53245-// Client capabilities of a {@link DocumentFormattingRequest}. 53246-type DocumentFormattingClientCapabilities struct { // line 11889 53247- // Whether formatting supports dynamic registration. 53248- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53249-} 53250- 53251-// Provider options for a {@link DocumentFormattingRequest}. 53252-type DocumentFormattingOptions struct { // line 9221 53253- WorkDoneProgressOptions 53254-} 53255- 53256-// The parameters of a {@link DocumentFormattingRequest}. 53257-type DocumentFormattingParams struct { // line 5727 53258- // The document to format. 53259- TextDocument TextDocumentIdentifier `json:"textDocument"` 53260- // The format options. 53261- Options FormattingOptions `json:"options"` 53262- WorkDoneProgressParams 53263-} 53264- 53265-// Registration options for a {@link DocumentFormattingRequest}. 53266-type DocumentFormattingRegistrationOptions struct { // line 5755 53267- TextDocumentRegistrationOptions 53268- DocumentFormattingOptions 53269-} 53270- 53271-// A document highlight is a range inside a text document which deserves 53272-// special attention. Usually a document highlight is visualized by changing 53273-// the background color of its range. 53274-type DocumentHighlight struct { // line 5119 53275- // The range this highlight applies to. 53276- Range Range `json:"range"` 53277- // The highlight kind, default is {@link DocumentHighlightKind.Text text}. 53278- Kind DocumentHighlightKind `json:"kind,omitempty"` 53279-} 53280- 53281-// Client Capabilities for a {@link DocumentHighlightRequest}. 53282-type DocumentHighlightClientCapabilities struct { // line 11624 53283- // Whether document highlight supports dynamic registration. 53284- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53285-} 53286- 53287-// A document highlight kind. 53288-type DocumentHighlightKind uint32 // line 13301 53289-// Provider options for a {@link DocumentHighlightRequest}. 53290-type DocumentHighlightOptions struct { // line 8955 53291- WorkDoneProgressOptions 53292-} 53293- 53294-// Parameters for a {@link DocumentHighlightRequest}. 53295-type DocumentHighlightParams struct { // line 5098 53296- TextDocumentPositionParams 53297- WorkDoneProgressParams 53298- PartialResultParams 53299-} 53300- 53301-// Registration options for a {@link DocumentHighlightRequest}. 53302-type DocumentHighlightRegistrationOptions struct { // line 5142 53303- TextDocumentRegistrationOptions 53304- DocumentHighlightOptions 53305-} 53306- 53307-// A document link is a range in a text document that links to an internal or external resource, like another 53308-// text document or a web site. 53309-type DocumentLink struct { // line 5670 53310- // The range this link applies to. 53311- Range Range `json:"range"` 53312- // The uri this link points to. If missing a resolve request is sent later. 53313- Target string `json:"target,omitempty"` 53314- // The tooltip text when you hover over this link. 53315- // 53316- // If a tooltip is provided, is will be displayed in a string that includes instructions on how to 53317- // trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, 53318- // user settings, and localization. 53319- // 53320- // @since 3.15.0 53321- Tooltip string `json:"tooltip,omitempty"` 53322- // A data entry field that is preserved on a document link between a 53323- // DocumentLinkRequest and a DocumentLinkResolveRequest. 53324- Data interface{} `json:"data,omitempty"` 53325-} 53326- 53327-// The client capabilities of a {@link DocumentLinkRequest}. 53328-type DocumentLinkClientCapabilities struct { // line 11850 53329- // Whether document link supports dynamic registration. 53330- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53331- // Whether the client supports the `tooltip` property on `DocumentLink`. 53332- // 53333- // @since 3.15.0 53334- TooltipSupport bool `json:"tooltipSupport,omitempty"` 53335-} 53336- 53337-// Provider options for a {@link DocumentLinkRequest}. 53338-type DocumentLinkOptions struct { // line 9148 53339- // Document links have a resolve provider as well. 53340- ResolveProvider bool `json:"resolveProvider,omitempty"` 53341- WorkDoneProgressOptions 53342-} 53343- 53344-// The parameters of a {@link DocumentLinkRequest}. 53345-type DocumentLinkParams struct { // line 5646 53346- // The document to provide document links for. 53347- TextDocument TextDocumentIdentifier `json:"textDocument"` 53348- WorkDoneProgressParams 53349- PartialResultParams 53350-} 53351- 53352-// Registration options for a {@link DocumentLinkRequest}. 53353-type DocumentLinkRegistrationOptions struct { // line 5712 53354- TextDocumentRegistrationOptions 53355- DocumentLinkOptions 53356-} 53357- 53358-// Client capabilities of a {@link DocumentOnTypeFormattingRequest}. 53359-type DocumentOnTypeFormattingClientCapabilities struct { // line 11919 53360- // Whether on type formatting supports dynamic registration. 53361- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53362-} 53363- 53364-// Provider options for a {@link DocumentOnTypeFormattingRequest}. 53365-type DocumentOnTypeFormattingOptions struct { // line 9243 53366- // A character on which formatting should be triggered, like `{`. 53367- FirstTriggerCharacter string `json:"firstTriggerCharacter"` 53368- // More trigger characters. 53369- MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"` 53370-} 53371- 53372-// The parameters of a {@link DocumentOnTypeFormattingRequest}. 53373-type DocumentOnTypeFormattingParams struct { // line 5821 53374- // The document to format. 53375- TextDocument TextDocumentIdentifier `json:"textDocument"` 53376- // The position around which the on type formatting should happen. 53377- // This is not necessarily the exact position where the character denoted 53378- // by the property `ch` got typed. 53379- Position Position `json:"position"` 53380- // The character that has been typed that triggered the formatting 53381- // on type request. That is not necessarily the last character that 53382- // got inserted into the document since the client could auto insert 53383- // characters as well (e.g. like automatic brace completion). 53384- Ch string `json:"ch"` 53385- // The formatting options. 53386- Options FormattingOptions `json:"options"` 53387-} 53388- 53389-// Registration options for a {@link DocumentOnTypeFormattingRequest}. 53390-type DocumentOnTypeFormattingRegistrationOptions struct { // line 5859 53391- TextDocumentRegistrationOptions 53392- DocumentOnTypeFormattingOptions 53393-} 53394- 53395-// Client capabilities of a {@link DocumentRangeFormattingRequest}. 53396-type DocumentRangeFormattingClientCapabilities struct { // line 11904 53397- // Whether range formatting supports dynamic registration. 53398- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53399-} 53400- 53401-// Provider options for a {@link DocumentRangeFormattingRequest}. 53402-type DocumentRangeFormattingOptions struct { // line 9232 53403- WorkDoneProgressOptions 53404-} 53405- 53406-// The parameters of a {@link DocumentRangeFormattingRequest}. 53407-type DocumentRangeFormattingParams struct { // line 5770 53408- // The document to format. 53409- TextDocument TextDocumentIdentifier `json:"textDocument"` 53410- // The range to format 53411- Range Range `json:"range"` 53412- // The format options 53413- Options FormattingOptions `json:"options"` 53414- WorkDoneProgressParams 53415-} 53416- 53417-// Registration options for a {@link DocumentRangeFormattingRequest}. 53418-type DocumentRangeFormattingRegistrationOptions struct { // line 5806 53419- TextDocumentRegistrationOptions 53420- DocumentRangeFormattingOptions 53421-} 53422- 53423-// A document selector is the combination of one or many document filters. 53424-// 53425-// @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; 53426-// 53427-// The use of a string as a document filter is deprecated @since 3.16.0. 53428-type DocumentSelector = []DocumentFilter // (alias) line 13948 53429-// Represents programming constructs like variables, classes, interfaces etc. 53430-// that appear in a document. Document symbols can be hierarchical and they 53431-// have two ranges: one that encloses its definition and one that points to 53432-// its most interesting range, e.g. the range of an identifier. 53433-type DocumentSymbol struct { // line 5211 53434- // The name of this symbol. Will be displayed in the user interface and therefore must not be 53435- // an empty string or a string only consisting of white spaces. 53436- Name string `json:"name"` 53437- // More detail for this symbol, e.g the signature of a function. 53438- Detail string `json:"detail,omitempty"` 53439- // The kind of this symbol. 53440- Kind SymbolKind `json:"kind"` 53441- // Tags for this document symbol. 53442- // 53443- // @since 3.16.0 53444- Tags []SymbolTag `json:"tags,omitempty"` 53445- // Indicates if this symbol is deprecated. 53446- // 53447- // @deprecated Use tags instead 53448- Deprecated bool `json:"deprecated,omitempty"` 53449- // The range enclosing this symbol not including leading/trailing whitespace but everything else 53450- // like comments. This information is typically used to determine if the clients cursor is 53451- // inside the symbol to reveal in the symbol in the UI. 53452- Range Range `json:"range"` 53453- // The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. 53454- // Must be contained by the `range`. 53455- SelectionRange Range `json:"selectionRange"` 53456- // Children of this symbol, e.g. properties of a class. 53457- Children []DocumentSymbol `json:"children,omitempty"` 53458-} 53459- 53460-// Client Capabilities for a {@link DocumentSymbolRequest}. 53461-type DocumentSymbolClientCapabilities struct { // line 11639 53462- // Whether document symbol supports dynamic registration. 53463- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53464- // Specific capabilities for the `SymbolKind` in the 53465- // `textDocument/documentSymbol` request. 53466- SymbolKind *PSymbolKindPDocumentSymbol `json:"symbolKind,omitempty"` 53467- // The client supports hierarchical document symbols. 53468- HierarchicalDocumentSymbolSupport bool `json:"hierarchicalDocumentSymbolSupport,omitempty"` 53469- // The client supports tags on `SymbolInformation`. Tags are supported on 53470- // `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. 53471- // Clients supporting tags have to handle unknown tags gracefully. 53472- // 53473- // @since 3.16.0 53474- TagSupport *PTagSupportPDocumentSymbol `json:"tagSupport,omitempty"` 53475- // The client supports an additional label presented in the UI when 53476- // registering a document symbol provider. 53477- // 53478- // @since 3.16.0 53479- LabelSupport bool `json:"labelSupport,omitempty"` 53480-} 53481- 53482-// Provider options for a {@link DocumentSymbolRequest}. 53483-type DocumentSymbolOptions struct { // line 9010 53484- // A human-readable string that is shown when multiple outlines trees 53485- // are shown for the same document. 53486- // 53487- // @since 3.16.0 53488- Label string `json:"label,omitempty"` 53489- WorkDoneProgressOptions 53490-} 53491- 53492-// Parameters for a {@link DocumentSymbolRequest}. 53493-type DocumentSymbolParams struct { // line 5157 53494- // The text document. 53495- TextDocument TextDocumentIdentifier `json:"textDocument"` 53496- WorkDoneProgressParams 53497- PartialResultParams 53498-} 53499- 53500-// Registration options for a {@link DocumentSymbolRequest}. 53501-type DocumentSymbolRegistrationOptions struct { // line 5293 53502- TextDocumentRegistrationOptions 53503- DocumentSymbolOptions 53504-} 53505-type DocumentURI string 53506- 53507-// Predefined error codes. 53508-type ErrorCodes int32 // line 12743 53509-// The client capabilities of a {@link ExecuteCommandRequest}. 53510-type ExecuteCommandClientCapabilities struct { // line 10962 53511- // Execute command supports dynamic registration. 53512- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53513-} 53514- 53515-// The server capabilities of a {@link ExecuteCommandRequest}. 53516-type ExecuteCommandOptions struct { // line 9291 53517- // The commands to be executed on the server 53518- Commands []string `json:"commands"` 53519- WorkDoneProgressOptions 53520-} 53521- 53522-// The parameters of a {@link ExecuteCommandRequest}. 53523-type ExecuteCommandParams struct { // line 5941 53524- // The identifier of the actual command handler. 53525- Command string `json:"command"` 53526- // Arguments that the command should be invoked with. 53527- Arguments []json.RawMessage `json:"arguments,omitempty"` 53528- WorkDoneProgressParams 53529-} 53530- 53531-// Registration options for a {@link ExecuteCommandRequest}. 53532-type ExecuteCommandRegistrationOptions struct { // line 5973 53533- ExecuteCommandOptions 53534-} 53535-type ExecutionSummary struct { // line 10162 53536- // A strict monotonically increasing value 53537- // indicating the execution order of a cell 53538- // inside a notebook. 53539- ExecutionOrder uint32 `json:"executionOrder"` 53540- // Whether the execution was successful or 53541- // not if known by the client. 53542- Success bool `json:"success,omitempty"` 53543-} 53544- 53545-// created for Literal (Lit_CodeActionClientCapabilities_codeActionLiteralSupport_codeActionKind) 53546-type FCodeActionKindPCodeActionLiteralSupport struct { // line 11742 53547- // The code action kind values the client supports. When this 53548- // property exists the client also guarantees that it will 53549- // handle values outside its set gracefully and falls back 53550- // to a default value when unknown. 53551- ValueSet []CodeActionKind `json:"valueSet"` 53552-} 53553- 53554-// created for Literal (Lit_CompletionList_itemDefaults_editRange_Item1) 53555-type FEditRangePItemDefaults struct { // line 4777 53556- Insert Range `json:"insert"` 53557- Replace Range `json:"replace"` 53558-} 53559- 53560-// created for Literal (Lit_SemanticTokensClientCapabilities_requests_full_Item1) 53561-type FFullPRequests struct { // line 12205 53562- // The client will send the `textDocument/semanticTokens/full/delta` request if 53563- // the server provides a corresponding handler. 53564- Delta bool `json:"delta"` 53565-} 53566- 53567-// created for Literal (Lit_CompletionClientCapabilities_completionItem_insertTextModeSupport) 53568-type FInsertTextModeSupportPCompletionItem struct { // line 11295 53569- ValueSet []InsertTextMode `json:"valueSet"` 53570-} 53571- 53572-// created for Literal (Lit_SignatureHelpClientCapabilities_signatureInformation_parameterInformation) 53573-type FParameterInformationPSignatureInformation struct { // line 11461 53574- // The client supports processing label offsets instead of a 53575- // simple label string. 53576- // 53577- // @since 3.14.0 53578- LabelOffsetSupport bool `json:"labelOffsetSupport,omitempty"` 53579-} 53580- 53581-// created for Literal (Lit_SemanticTokensClientCapabilities_requests_range_Item1) 53582-type FRangePRequests struct { // line 12185 53583-} 53584- 53585-// created for Literal (Lit_CompletionClientCapabilities_completionItem_resolveSupport) 53586-type FResolveSupportPCompletionItem struct { // line 11271 53587- // The properties that a client can resolve lazily. 53588- Properties []string `json:"properties"` 53589-} 53590- 53591-// created for Literal (Lit_NotebookDocumentChangeEvent_cells_structure) 53592-type FStructurePCells struct { // line 7487 53593- // The change to the cell array. 53594- Array NotebookCellArrayChange `json:"array"` 53595- // Additional opened cell text documents. 53596- DidOpen []TextDocumentItem `json:"didOpen,omitempty"` 53597- // Additional closed cell text documents. 53598- DidClose []TextDocumentIdentifier `json:"didClose,omitempty"` 53599-} 53600- 53601-// created for Literal (Lit_CompletionClientCapabilities_completionItem_tagSupport) 53602-type FTagSupportPCompletionItem struct { // line 11237 53603- // The tags supported by the client. 53604- ValueSet []CompletionItemTag `json:"valueSet"` 53605-} 53606-type FailureHandlingKind string // line 13693 53607-// The file event type 53608-type FileChangeType uint32 // line 13454 53609-// Represents information on a file/folder create. 53610-// 53611-// @since 3.16.0 53612-type FileCreate struct { // line 6662 53613- // A file:// URI for the location of the file/folder being created. 53614- URI string `json:"uri"` 53615-} 53616- 53617-// Represents information on a file/folder delete. 53618-// 53619-// @since 3.16.0 53620-type FileDelete struct { // line 6911 53621- // A file:// URI for the location of the file/folder being deleted. 53622- URI string `json:"uri"` 53623-} 53624- 53625-// An event describing a file change. 53626-type FileEvent struct { // line 8480 53627- // The file's uri. 53628- URI DocumentURI `json:"uri"` 53629- // The change type. 53630- Type FileChangeType `json:"type"` 53631-} 53632- 53633-// Capabilities relating to events from file operations by the user in the client. 53634-// 53635-// These events do not come from the file system, they come from user operations 53636-// like renaming a file in the UI. 53637-// 53638-// @since 3.16.0 53639-type FileOperationClientCapabilities struct { // line 11009 53640- // Whether the client supports dynamic registration for file requests/notifications. 53641- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53642- // The client has support for sending didCreateFiles notifications. 53643- DidCreate bool `json:"didCreate,omitempty"` 53644- // The client has support for sending willCreateFiles requests. 53645- WillCreate bool `json:"willCreate,omitempty"` 53646- // The client has support for sending didRenameFiles notifications. 53647- DidRename bool `json:"didRename,omitempty"` 53648- // The client has support for sending willRenameFiles requests. 53649- WillRename bool `json:"willRename,omitempty"` 53650- // The client has support for sending didDeleteFiles notifications. 53651- DidDelete bool `json:"didDelete,omitempty"` 53652- // The client has support for sending willDeleteFiles requests. 53653- WillDelete bool `json:"willDelete,omitempty"` 53654-} 53655- 53656-// A filter to describe in which file operation requests or notifications 53657-// the server is interested in receiving. 53658-// 53659-// @since 3.16.0 53660-type FileOperationFilter struct { // line 6864 53661- // A Uri scheme like `file` or `untitled`. 53662- Scheme string `json:"scheme,omitempty"` 53663- // The actual file operation pattern. 53664- Pattern FileOperationPattern `json:"pattern"` 53665-} 53666- 53667-// Options for notifications/requests for user operations on files. 53668-// 53669-// @since 3.16.0 53670-type FileOperationOptions struct { // line 9965 53671- // The server is interested in receiving didCreateFiles notifications. 53672- DidCreate *FileOperationRegistrationOptions `json:"didCreate,omitempty"` 53673- // The server is interested in receiving willCreateFiles requests. 53674- WillCreate *FileOperationRegistrationOptions `json:"willCreate,omitempty"` 53675- // The server is interested in receiving didRenameFiles notifications. 53676- DidRename *FileOperationRegistrationOptions `json:"didRename,omitempty"` 53677- // The server is interested in receiving willRenameFiles requests. 53678- WillRename *FileOperationRegistrationOptions `json:"willRename,omitempty"` 53679- // The server is interested in receiving didDeleteFiles file notifications. 53680- DidDelete *FileOperationRegistrationOptions `json:"didDelete,omitempty"` 53681- // The server is interested in receiving willDeleteFiles file requests. 53682- WillDelete *FileOperationRegistrationOptions `json:"willDelete,omitempty"` 53683-} 53684- 53685-// A pattern to describe in which file operation requests or notifications 53686-// the server is interested in receiving. 53687-// 53688-// @since 3.16.0 53689-type FileOperationPattern struct { // line 9489 53690- // The glob pattern to match. Glob patterns can have the following syntax: 53691- // 53692- // - `*` to match one or more characters in a path segment 53693- // - `?` to match on one character in a path segment 53694- // - `**` to match any number of path segments, including none 53695- // - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) 53696- // - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) 53697- // - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) 53698- Glob string `json:"glob"` 53699- // Whether to match files or folders with this pattern. 53700- // 53701- // Matches both if undefined. 53702- Matches *FileOperationPatternKind `json:"matches,omitempty"` 53703- // Additional options used during matching. 53704- Options *FileOperationPatternOptions `json:"options,omitempty"` 53705-} 53706- 53707-// A pattern kind describing if a glob pattern matches a file a folder or 53708-// both. 53709-// 53710-// @since 3.16.0 53711-type FileOperationPatternKind string // line 13627 53712-// Matching options for the file operation pattern. 53713-// 53714-// @since 3.16.0 53715-type FileOperationPatternOptions struct { // line 10146 53716- // The pattern should be matched ignoring casing. 53717- IgnoreCase bool `json:"ignoreCase,omitempty"` 53718-} 53719- 53720-// The options to register for file operations. 53721-// 53722-// @since 3.16.0 53723-type FileOperationRegistrationOptions struct { // line 3264 53724- // The actual filters. 53725- Filters []FileOperationFilter `json:"filters"` 53726-} 53727- 53728-// Represents information on a file/folder rename. 53729-// 53730-// @since 3.16.0 53731-type FileRename struct { // line 6888 53732- // A file:// URI for the original location of the file/folder being renamed. 53733- OldURI string `json:"oldUri"` 53734- // A file:// URI for the new location of the file/folder being renamed. 53735- NewURI string `json:"newUri"` 53736-} 53737-type FileSystemWatcher struct { // line 8502 53738- // The glob pattern to watch. See {@link GlobPattern glob pattern} for more detail. 53739- // 53740- // @since 3.17.0 support for relative patterns. 53741- GlobPattern GlobPattern `json:"globPattern"` 53742- // The kind of events of interest. If omitted it defaults 53743- // to WatchKind.Create | WatchKind.Change | WatchKind.Delete 53744- // which is 7. 53745- Kind *WatchKind `json:"kind,omitempty"` 53746-} 53747- 53748-// Represents a folding range. To be valid, start and end line must be bigger than zero and smaller 53749-// than the number of lines in the document. Clients are free to ignore invalid ranges. 53750-type FoldingRange struct { // line 2415 53751- // The zero-based start line of the range to fold. The folded area starts after the line's last character. 53752- // To be valid, the end must be zero or larger and smaller than the number of lines in the document. 53753- StartLine uint32 `json:"startLine"` 53754- // The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. 53755- StartCharacter uint32 `json:"startCharacter,omitempty"` 53756- // The zero-based end line of the range to fold. The folded area ends with the line's last character. 53757- // To be valid, the end must be zero or larger and smaller than the number of lines in the document. 53758- EndLine uint32 `json:"endLine"` 53759- // The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. 53760- EndCharacter uint32 `json:"endCharacter,omitempty"` 53761- // Describes the kind of the folding range such as `comment' or 'region'. The kind 53762- // is used to categorize folding ranges and used by commands like 'Fold all comments'. 53763- // See {@link FoldingRangeKind} for an enumeration of standardized kinds. 53764- Kind string `json:"kind,omitempty"` 53765- // The text that the client should show when the specified range is 53766- // collapsed. If not defined or not supported by the client, a default 53767- // will be chosen by the client. 53768- // 53769- // @since 3.17.0 53770- CollapsedText string `json:"collapsedText,omitempty"` 53771-} 53772-type FoldingRangeClientCapabilities struct { // line 11978 53773- // Whether implementation supports dynamic registration for folding range 53774- // providers. If this is set to `true` the client supports the new 53775- // `FoldingRangeRegistrationOptions` return value for the corresponding 53776- // server capability as well. 53777- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53778- // The maximum number of folding ranges that the client prefers to receive 53779- // per document. The value serves as a hint, servers are free to follow the 53780- // limit. 53781- RangeLimit uint32 `json:"rangeLimit,omitempty"` 53782- // If set, the client signals that it only supports folding complete lines. 53783- // If set, client will ignore specified `startCharacter` and `endCharacter` 53784- // properties in a FoldingRange. 53785- LineFoldingOnly bool `json:"lineFoldingOnly,omitempty"` 53786- // Specific options for the folding range kind. 53787- // 53788- // @since 3.17.0 53789- FoldingRangeKind *PFoldingRangeKindPFoldingRange `json:"foldingRangeKind,omitempty"` 53790- // Specific options for the folding range. 53791- // 53792- // @since 3.17.0 53793- FoldingRange *PFoldingRangePFoldingRange `json:"foldingRange,omitempty"` 53794-} 53795- 53796-// A set of predefined range kinds. 53797-type FoldingRangeKind string // line 12815 53798-type FoldingRangeOptions struct { // line 6481 53799- WorkDoneProgressOptions 53800-} 53801- 53802-// Parameters for a {@link FoldingRangeRequest}. 53803-type FoldingRangeParams struct { // line 2391 53804- // The text document. 53805- TextDocument TextDocumentIdentifier `json:"textDocument"` 53806- WorkDoneProgressParams 53807- PartialResultParams 53808-} 53809-type FoldingRangeRegistrationOptions struct { // line 2474 53810- TextDocumentRegistrationOptions 53811- FoldingRangeOptions 53812- StaticRegistrationOptions 53813-} 53814- 53815-// Value-object describing what options formatting should use. 53816-type FormattingOptions struct { // line 9169 53817- // Size of a tab in spaces. 53818- TabSize uint32 `json:"tabSize"` 53819- // Prefer spaces over tabs. 53820- InsertSpaces bool `json:"insertSpaces"` 53821- // Trim trailing whitespace on a line. 53822- // 53823- // @since 3.15.0 53824- TrimTrailingWhitespace bool `json:"trimTrailingWhitespace,omitempty"` 53825- // Insert a newline character at the end of the file if one does not exist. 53826- // 53827- // @since 3.15.0 53828- InsertFinalNewline bool `json:"insertFinalNewline,omitempty"` 53829- // Trim all newlines after the final newline at the end of the file. 53830- // 53831- // @since 3.15.0 53832- TrimFinalNewlines bool `json:"trimFinalNewlines,omitempty"` 53833-} 53834- 53835-// A diagnostic report with a full set of problems. 53836-// 53837-// @since 3.17.0 53838-type FullDocumentDiagnosticReport struct { // line 7235 53839- // A full document diagnostic report. 53840- Kind string `json:"kind"` 53841- // An optional result id. If provided it will 53842- // be sent on the next diagnostic request for the 53843- // same document. 53844- ResultID string `json:"resultId,omitempty"` 53845- // The actual items. 53846- Items []Diagnostic `json:"items"` 53847-} 53848- 53849-// General client capabilities. 53850-// 53851-// @since 3.16.0 53852-type GeneralClientCapabilities struct { // line 10664 53853- // Client capability that signals how the client 53854- // handles stale requests (e.g. a request 53855- // for which the client will not process the response 53856- // anymore since the information is outdated). 53857- // 53858- // @since 3.17.0 53859- StaleRequestSupport *PStaleRequestSupportPGeneral `json:"staleRequestSupport,omitempty"` 53860- // Client capabilities specific to regular expressions. 53861- // 53862- // @since 3.16.0 53863- RegularExpressions *RegularExpressionsClientCapabilities `json:"regularExpressions,omitempty"` 53864- // Client capabilities specific to the client's markdown parser. 53865- // 53866- // @since 3.16.0 53867- Markdown *MarkdownClientCapabilities `json:"markdown,omitempty"` 53868- // The position encodings supported by the client. Client and server 53869- // have to agree on the same position encoding to ensure that offsets 53870- // (e.g. character position in a line) are interpreted the same on both 53871- // sides. 53872- // 53873- // To keep the protocol backwards compatible the following applies: if 53874- // the value 'utf-16' is missing from the array of position encodings 53875- // servers can assume that the client supports UTF-16. UTF-16 is 53876- // therefore a mandatory encoding. 53877- // 53878- // If omitted it defaults to ['utf-16']. 53879- // 53880- // Implementation considerations: since the conversion from one encoding 53881- // into another requires the content of the file / line the conversion 53882- // is best done where the file is read which is usually on the server 53883- // side. 53884- // 53885- // @since 3.17.0 53886- PositionEncodings []PositionEncodingKind `json:"positionEncodings,omitempty"` 53887-} 53888- 53889-// The glob pattern. Either a string pattern or a relative pattern. 53890-// 53891-// @since 3.17.0 53892-type GlobPattern = string // (alias) line 14127 53893-// The result of a hover request. 53894-type Hover struct { // line 4886 53895- // The hover's content 53896- Contents MarkupContent `json:"contents"` 53897- // An optional range inside the text document that is used to 53898- // visualize the hover, e.g. by changing the background color. 53899- Range Range `json:"range,omitempty"` 53900-} 53901-type HoverClientCapabilities struct { // line 11402 53902- // Whether hover supports dynamic registration. 53903- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53904- // Client supports the following content formats for the content 53905- // property. The order describes the preferred format of the client. 53906- ContentFormat []MarkupKind `json:"contentFormat,omitempty"` 53907-} 53908- 53909-// Hover options. 53910-type HoverOptions struct { // line 8776 53911- WorkDoneProgressOptions 53912-} 53913- 53914-// Parameters for a {@link HoverRequest}. 53915-type HoverParams struct { // line 4869 53916- TextDocumentPositionParams 53917- WorkDoneProgressParams 53918-} 53919- 53920-// Registration options for a {@link HoverRequest}. 53921-type HoverRegistrationOptions struct { // line 4925 53922- TextDocumentRegistrationOptions 53923- HoverOptions 53924-} 53925- 53926-// @since 3.6.0 53927-type ImplementationClientCapabilities struct { // line 11583 53928- // Whether implementation supports dynamic registration. If this is set to `true` 53929- // the client supports the new `ImplementationRegistrationOptions` return value 53930- // for the corresponding server capability as well. 53931- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 53932- // The client supports additional metadata in the form of definition links. 53933- // 53934- // @since 3.14.0 53935- LinkSupport bool `json:"linkSupport,omitempty"` 53936-} 53937-type ImplementationOptions struct { // line 6333 53938- WorkDoneProgressOptions 53939-} 53940-type ImplementationParams struct { // line 2063 53941- TextDocumentPositionParams 53942- WorkDoneProgressParams 53943- PartialResultParams 53944-} 53945-type ImplementationRegistrationOptions struct { // line 2103 53946- TextDocumentRegistrationOptions 53947- ImplementationOptions 53948- StaticRegistrationOptions 53949-} 53950- 53951-// The data type of the ResponseError if the 53952-// initialize request fails. 53953-type InitializeError struct { // line 4126 53954- // Indicates whether the client execute the following retry logic: 53955- // (1) show the message provided by the ResponseError to the user 53956- // (2) user selects retry or cancel 53957- // (3) if user selected retry the initialize method is sent again. 53958- Retry bool `json:"retry"` 53959-} 53960-type InitializeParams struct { // line 4068 53961- XInitializeParams 53962- WorkspaceFoldersInitializeParams 53963-} 53964- 53965-// The result returned from an initialize request. 53966-type InitializeResult struct { // line 4082 53967- // The capabilities the language server provides. 53968- Capabilities ServerCapabilities `json:"capabilities"` 53969- // Information about the server. 53970- // 53971- // @since 3.15.0 53972- ServerInfo *PServerInfoMsg_initialize `json:"serverInfo,omitempty"` 53973-} 53974-type InitializedParams struct { // line 4140 53975-} 53976- 53977-// Inlay hint information. 53978-// 53979-// @since 3.17.0 53980-type InlayHint struct { // line 3645 53981- // The position of this hint. 53982- Position Position `json:"position"` 53983- // The label of this hint. A human readable string or an array of 53984- // InlayHintLabelPart label parts. 53985- // 53986- // *Note* that neither the string nor the label part can be empty. 53987- Label []InlayHintLabelPart `json:"label"` 53988- // The kind of this hint. Can be omitted in which case the client 53989- // should fall back to a reasonable default. 53990- Kind InlayHintKind `json:"kind,omitempty"` 53991- // Optional text edits that are performed when accepting this inlay hint. 53992- // 53993- // *Note* that edits are expected to change the document so that the inlay 53994- // hint (or its nearest variant) is now part of the document and the inlay 53995- // hint itself is now obsolete. 53996- TextEdits []TextEdit `json:"textEdits,omitempty"` 53997- // The tooltip text when you hover over this item. 53998- Tooltip *OrPTooltip_textDocument_inlayHint `json:"tooltip,omitempty"` 53999- // Render padding before the hint. 54000- // 54001- // Note: Padding should use the editor's background color, not the 54002- // background color of the hint itself. That means padding can be used 54003- // to visually align/separate an inlay hint. 54004- PaddingLeft bool `json:"paddingLeft,omitempty"` 54005- // Render padding after the hint. 54006- // 54007- // Note: Padding should use the editor's background color, not the 54008- // background color of the hint itself. That means padding can be used 54009- // to visually align/separate an inlay hint. 54010- PaddingRight bool `json:"paddingRight,omitempty"` 54011- // A data entry field that is preserved on an inlay hint between 54012- // a `textDocument/inlayHint` and a `inlayHint/resolve` request. 54013- Data interface{} `json:"data,omitempty"` 54014-} 54015- 54016-// Inlay hint client capabilities. 54017-// 54018-// @since 3.17.0 54019-type InlayHintClientCapabilities struct { // line 12369 54020- // Whether inlay hints support dynamic registration. 54021- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 54022- // Indicates which properties a client can resolve lazily on an inlay 54023- // hint. 54024- ResolveSupport *PResolveSupportPInlayHint `json:"resolveSupport,omitempty"` 54025-} 54026- 54027-// Inlay hint kinds. 54028-// 54029-// @since 3.17.0 54030-type InlayHintKind uint32 // line 13033 54031-// An inlay hint label part allows for interactive and composite labels 54032-// of inlay hints. 54033-// 54034-// @since 3.17.0 54035-type InlayHintLabelPart struct { // line 7062 54036- // The value of this label part. 54037- Value string `json:"value"` 54038- // The tooltip text when you hover over this label part. Depending on 54039- // the client capability `inlayHint.resolveSupport` clients might resolve 54040- // this property late using the resolve request. 54041- Tooltip *OrPTooltipPLabel `json:"tooltip,omitempty"` 54042- // An optional source code location that represents this 54043- // label part. 54044- // 54045- // The editor will use this location for the hover and for code navigation 54046- // features: This part will become a clickable link that resolves to the 54047- // definition of the symbol at the given location (not necessarily the 54048- // location itself), it shows the hover that shows at the given location, 54049- // and it shows a context menu with further code navigation commands. 54050- // 54051- // Depending on the client capability `inlayHint.resolveSupport` clients 54052- // might resolve this property late using the resolve request. 54053- Location *Location `json:"location,omitempty"` 54054- // An optional command for this label part. 54055- // 54056- // Depending on the client capability `inlayHint.resolveSupport` clients 54057- // might resolve this property late using the resolve request. 54058- Command *Command `json:"command,omitempty"` 54059-} 54060- 54061-// Inlay hint options used during static registration. 54062-// 54063-// @since 3.17.0 54064-type InlayHintOptions struct { // line 7135 54065- // The server provides support to resolve additional 54066- // information for an inlay hint item. 54067- ResolveProvider bool `json:"resolveProvider,omitempty"` 54068- WorkDoneProgressOptions 54069-} 54070- 54071-// A parameter literal used in inlay hint requests. 54072-// 54073-// @since 3.17.0 54074-type InlayHintParams struct { // line 3616 54075- // The text document. 54076- TextDocument TextDocumentIdentifier `json:"textDocument"` 54077- // The document range for which inlay hints should be computed. 54078- Range Range `json:"range"` 54079- WorkDoneProgressParams 54080-} 54081- 54082-// Inlay hint options used during static or dynamic registration. 54083-// 54084-// @since 3.17.0 54085-type InlayHintRegistrationOptions struct { // line 3746 54086- InlayHintOptions 54087- TextDocumentRegistrationOptions 54088- StaticRegistrationOptions 54089-} 54090- 54091-// Client workspace capabilities specific to inlay hints. 54092-// 54093-// @since 3.17.0 54094-type InlayHintWorkspaceClientCapabilities struct { // line 11095 54095- // Whether the client implementation supports a refresh request sent from 54096- // the server to the client. 54097- // 54098- // Note that this event is global and will force the client to refresh all 54099- // inlay hints currently shown. It should be used with absolute care and 54100- // is useful for situation where a server for example detects a project wide 54101- // change that requires such a calculation. 54102- RefreshSupport bool `json:"refreshSupport,omitempty"` 54103-} 54104- 54105-// Inline value information can be provided by different means: 54106-// 54107-// - directly as a text value (class InlineValueText). 54108-// - as a name to use for a variable lookup (class InlineValueVariableLookup) 54109-// - as an evaluatable expression (class InlineValueEvaluatableExpression) 54110-// 54111-// The InlineValue types combines all inline value types into one type. 54112-// 54113-// @since 3.17.0 54114-type InlineValue = Or_InlineValue // (alias) line 13861 54115-// Client capabilities specific to inline values. 54116-// 54117-// @since 3.17.0 54118-type InlineValueClientCapabilities struct { // line 12353 54119- // Whether implementation supports dynamic registration for inline value providers. 54120- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 54121-} 54122- 54123-// @since 3.17.0 54124-type InlineValueContext struct { // line 6948 54125- // The stack frame (as a DAP Id) where the execution has stopped. 54126- FrameID int32 `json:"frameId"` 54127- // The document range where execution has stopped. 54128- // Typically the end position of the range denotes the line where the inline values are shown. 54129- StoppedLocation Range `json:"stoppedLocation"` 54130-} 54131- 54132-// Provide an inline value through an expression evaluation. 54133-// If only a range is specified, the expression will be extracted from the underlying document. 54134-// An optional expression can be used to override the extracted expression. 54135-// 54136-// @since 3.17.0 54137-type InlineValueEvaluatableExpression struct { // line 7026 54138- // The document range for which the inline value applies. 54139- // The range is used to extract the evaluatable expression from the underlying document. 54140- Range Range `json:"range"` 54141- // If specified the expression overrides the extracted expression. 54142- Expression string `json:"expression,omitempty"` 54143-} 54144- 54145-// Inline value options used during static registration. 54146-// 54147-// @since 3.17.0 54148-type InlineValueOptions struct { // line 7050 54149- WorkDoneProgressOptions 54150-} 54151- 54152-// A parameter literal used in inline value requests. 54153-// 54154-// @since 3.17.0 54155-type InlineValueParams struct { // line 3557 54156- // The text document. 54157- TextDocument TextDocumentIdentifier `json:"textDocument"` 54158- // The document range for which inline values should be computed. 54159- Range Range `json:"range"` 54160- // Additional information about the context in which inline values were 54161- // requested. 54162- Context InlineValueContext `json:"context"` 54163- WorkDoneProgressParams 54164-} 54165- 54166-// Inline value options used during static or dynamic registration. 54167-// 54168-// @since 3.17.0 54169-type InlineValueRegistrationOptions struct { // line 3594 54170- InlineValueOptions 54171- TextDocumentRegistrationOptions 54172- StaticRegistrationOptions 54173-} 54174- 54175-// Provide inline value as text. 54176-// 54177-// @since 3.17.0 54178-type InlineValueText struct { // line 6971 54179- // The document range for which the inline value applies. 54180- Range Range `json:"range"` 54181- // The text of the inline value. 54182- Text string `json:"text"` 54183-} 54184- 54185-// Provide inline value through a variable lookup. 54186-// If only a range is specified, the variable name will be extracted from the underlying document. 54187-// An optional variable name can be used to override the extracted name. 54188-// 54189-// @since 3.17.0 54190-type InlineValueVariableLookup struct { // line 6994 54191- // The document range for which the inline value applies. 54192- // The range is used to extract the variable name from the underlying document. 54193- Range Range `json:"range"` 54194- // If specified the name of the variable to look up. 54195- VariableName string `json:"variableName,omitempty"` 54196- // How to perform the lookup. 54197- CaseSensitiveLookup bool `json:"caseSensitiveLookup"` 54198-} 54199- 54200-// Client workspace capabilities specific to inline values. 54201-// 54202-// @since 3.17.0 54203-type InlineValueWorkspaceClientCapabilities struct { // line 11079 54204- // Whether the client implementation supports a refresh request sent from the 54205- // server to the client. 54206- // 54207- // Note that this event is global and will force the client to refresh all 54208- // inline values currently shown. It should be used with absolute care and is 54209- // useful for situation where a server for example detects a project wide 54210- // change that requires such a calculation. 54211- RefreshSupport bool `json:"refreshSupport,omitempty"` 54212-} 54213- 54214-// A special text edit to provide an insert and a replace operation. 54215-// 54216-// @since 3.16.0 54217-type InsertReplaceEdit struct { // line 8676 54218- // The string to be inserted. 54219- NewText string `json:"newText"` 54220- // The range if the insert is requested 54221- Insert Range `json:"insert"` 54222- // The range if the replace is requested. 54223- Replace Range `json:"replace"` 54224-} 54225- 54226-// Defines whether the insert text in a completion item should be interpreted as 54227-// plain text or a snippet. 54228-type InsertTextFormat uint32 // line 13260 54229-// How whitespace and indentation is handled during completion 54230-// item insertion. 54231-// 54232-// @since 3.16.0 54233-type InsertTextMode uint32 // line 13280 54234-type LSPAny = interface{} 54235- 54236-// LSP arrays. 54237-// @since 3.17.0 54238-type LSPArray = []interface{} // (alias) line 13779 54239-type LSPErrorCodes int32 // line 12783 54240-// LSP object definition. 54241-// @since 3.17.0 54242-type LSPObject = map[string]LSPAny // (alias) line 14111 54243-// Client capabilities for the linked editing range request. 54244-// 54245-// @since 3.16.0 54246-type LinkedEditingRangeClientCapabilities struct { // line 12305 54247- // Whether implementation supports dynamic registration. If this is set to `true` 54248- // the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` 54249- // return value for the corresponding server capability as well. 54250- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 54251-} 54252-type LinkedEditingRangeOptions struct { // line 6652 54253- WorkDoneProgressOptions 54254-} 54255-type LinkedEditingRangeParams struct { // line 3112 54256- TextDocumentPositionParams 54257- WorkDoneProgressParams 54258-} 54259-type LinkedEditingRangeRegistrationOptions struct { // line 3155 54260- TextDocumentRegistrationOptions 54261- LinkedEditingRangeOptions 54262- StaticRegistrationOptions 54263-} 54264- 54265-// The result of a linked editing range request. 54266-// 54267-// @since 3.16.0 54268-type LinkedEditingRanges struct { // line 3128 54269- // A list of ranges that can be edited together. The ranges must have 54270- // identical length and contain identical text content. The ranges cannot overlap. 54271- Ranges []Range `json:"ranges"` 54272- // An optional word pattern (regular expression) that describes valid contents for 54273- // the given ranges. If no pattern is provided, the client configuration's word 54274- // pattern will be used. 54275- WordPattern string `json:"wordPattern,omitempty"` 54276-} 54277- 54278-// created for Literal (Lit_NotebookDocumentChangeEvent_cells_textContent_Elem) 54279-type Lit_NotebookDocumentChangeEvent_cells_textContent_Elem struct { // line 7545 54280- Document VersionedTextDocumentIdentifier `json:"document"` 54281- Changes []TextDocumentContentChangeEvent `json:"changes"` 54282-} 54283- 54284-// created for Literal (Lit_NotebookDocumentFilter_Item1) 54285-type Lit_NotebookDocumentFilter_Item1 struct { // line 14293 54286- // The type of the enclosing notebook. 54287- NotebookType string `json:"notebookType,omitempty"` 54288- // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. 54289- Scheme string `json:"scheme"` 54290- // A glob pattern. 54291- Pattern string `json:"pattern,omitempty"` 54292-} 54293- 54294-// created for Literal (Lit_NotebookDocumentFilter_Item2) 54295-type Lit_NotebookDocumentFilter_Item2 struct { // line 14326 54296- // The type of the enclosing notebook. 54297- NotebookType string `json:"notebookType,omitempty"` 54298- // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. 54299- Scheme string `json:"scheme,omitempty"` 54300- // A glob pattern. 54301- Pattern string `json:"pattern"` 54302-} 54303- 54304-// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_cells_Elem) 54305-type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_cells_Elem struct { // line 9831 54306- Language string `json:"language"` 54307-} 54308- 54309-// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1) 54310-type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1 struct { // line 9852 54311- // The notebook to be synced If a string 54312- // value is provided it matches against the 54313- // notebook type. '*' matches every notebook. 54314- Notebook *Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook `json:"notebook,omitempty"` 54315- // The cells of the matching notebook to be synced. 54316- Cells []Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_cells_Elem `json:"cells"` 54317-} 54318- 54319-// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_cells_Elem) 54320-type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_cells_Elem struct { // line 9878 54321- Language string `json:"language"` 54322-} 54323- 54324-// created for Literal (Lit_PrepareRenameResult_Item2) 54325-type Lit_PrepareRenameResult_Item2 struct { // line 13932 54326- DefaultBehavior bool `json:"defaultBehavior"` 54327-} 54328- 54329-// created for Literal (Lit_TextDocumentContentChangeEvent_Item1) 54330-type Lit_TextDocumentContentChangeEvent_Item1 struct { // line 14040 54331- // The new text of the whole document. 54332- Text string `json:"text"` 54333-} 54334- 54335-// created for Literal (Lit_TextDocumentFilter_Item2) 54336-type Lit_TextDocumentFilter_Item2 struct { // line 14217 54337- // A language id, like `typescript`. 54338- Language string `json:"language,omitempty"` 54339- // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. 54340- Scheme string `json:"scheme,omitempty"` 54341- // A glob pattern, like `*.{ts,js}`. 54342- Pattern string `json:"pattern"` 54343-} 54344- 54345-// Represents a location inside a resource, such as a line 54346-// inside a text file. 54347-type Location struct { // line 2083 54348- URI DocumentURI `json:"uri"` 54349- Range Range `json:"range"` 54350-} 54351- 54352-// Represents the connection of two locations. Provides additional metadata over normal {@link Location locations}, 54353-// including an origin range. 54354-type LocationLink struct { // line 6272 54355- // Span of the origin of this link. 54356- // 54357- // Used as the underlined span for mouse interaction. Defaults to the word range at 54358- // the definition position. 54359- OriginSelectionRange *Range `json:"originSelectionRange,omitempty"` 54360- // The target resource identifier of this link. 54361- TargetURI DocumentURI `json:"targetUri"` 54362- // The full target range of this link. If the target for example is a symbol then target range is the 54363- // range enclosing this symbol not including leading/trailing whitespace but everything else 54364- // like comments. This information is typically used to highlight the range in the editor. 54365- TargetRange Range `json:"targetRange"` 54366- // The range that should be selected and revealed when this link is being followed, e.g the name of a function. 54367- // Must be contained by the `targetRange`. See also `DocumentSymbol#range` 54368- TargetSelectionRange Range `json:"targetSelectionRange"` 54369-} 54370- 54371-// The log message parameters. 54372-type LogMessageParams struct { // line 4251 54373- // The message type. See {@link MessageType} 54374- Type MessageType `json:"type"` 54375- // The actual message. 54376- Message string `json:"message"` 54377-} 54378-type LogTraceParams struct { // line 6159 54379- Message string `json:"message"` 54380- Verbose string `json:"verbose,omitempty"` 54381-} 54382- 54383-// Client capabilities specific to the used markdown parser. 54384-// 54385-// @since 3.16.0 54386-type MarkdownClientCapabilities struct { // line 12524 54387- // The name of the parser. 54388- Parser string `json:"parser"` 54389- // The version of the parser. 54390- Version string `json:"version,omitempty"` 54391- // A list of HTML tags that the client allows / supports in 54392- // Markdown. 54393- // 54394- // @since 3.17.0 54395- AllowedTags []string `json:"allowedTags,omitempty"` 54396-} 54397- 54398-// MarkedString can be used to render human readable text. It is either a markdown string 54399-// or a code-block that provides a language and a code snippet. The language identifier 54400-// is semantically equal to the optional language identifier in fenced code blocks in GitHub 54401-// issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting 54402-// 54403-// The pair of a language and a value is an equivalent to markdown: 54404-// ```${language} 54405-// ${value} 54406-// ``` 54407-// 54408-// Note that markdown strings will be sanitized - that means html will be escaped. 54409-// @deprecated use MarkupContent instead. 54410-type MarkedString = Or_MarkedString // (alias) line 14058 54411-// A `MarkupContent` literal represents a string value which content is interpreted base on its 54412-// kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. 54413-// 54414-// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. 54415-// See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting 54416-// 54417-// Here is an example how such a string can be constructed using JavaScript / TypeScript: 54418-// ```ts 54419-// 54420-// let markdown: MarkdownContent = { 54421-// kind: MarkupKind.Markdown, 54422-// value: [ 54423-// '# Header', 54424-// 'Some text', 54425-// '```typescript', 54426-// 'someCode();', 54427-// '```' 54428-// ].join('\n') 54429-// }; 54430-// 54431-// ``` 54432-// 54433-// *Please Note* that clients might sanitize the return markdown. A client could decide to 54434-// remove HTML from the markdown to avoid script execution. 54435-type MarkupContent struct { // line 7113 54436- // The type of the Markup 54437- Kind MarkupKind `json:"kind"` 54438- // The content itself 54439- Value string `json:"value"` 54440-} 54441- 54442-// Describes the content type that a client supports in various 54443-// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. 54444-// 54445-// Please note that `MarkupKinds` must not start with a `$`. This kinds 54446-// are reserved for internal usage. 54447-type MarkupKind string // line 13407 54448-type MessageActionItem struct { // line 4238 54449- // A short title like 'Retry', 'Open Log' etc. 54450- Title string `json:"title"` 54451-} 54452- 54453-// The message type 54454-type MessageType uint32 // line 13054 54455-// Moniker definition to match LSIF 0.5 moniker definition. 54456-// 54457-// @since 3.16.0 54458-type Moniker struct { // line 3338 54459- // The scheme of the moniker. For example tsc or .Net 54460- Scheme string `json:"scheme"` 54461- // The identifier of the moniker. The value is opaque in LSIF however 54462- // schema owners are allowed to define the structure if they want. 54463- Identifier string `json:"identifier"` 54464- // The scope in which the moniker is unique 54465- Unique UniquenessLevel `json:"unique"` 54466- // The moniker kind if known. 54467- Kind *MonikerKind `json:"kind,omitempty"` 54468-} 54469- 54470-// Client capabilities specific to the moniker request. 54471-// 54472-// @since 3.16.0 54473-type MonikerClientCapabilities struct { // line 12321 54474- // Whether moniker supports dynamic registration. If this is set to `true` 54475- // the client supports the new `MonikerRegistrationOptions` return value 54476- // for the corresponding server capability as well. 54477- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 54478-} 54479- 54480-// The moniker kind. 54481-// 54482-// @since 3.16.0 54483-type MonikerKind string // line 13007 54484-type MonikerOptions struct { // line 6926 54485- WorkDoneProgressOptions 54486-} 54487-type MonikerParams struct { // line 3318 54488- TextDocumentPositionParams 54489- WorkDoneProgressParams 54490- PartialResultParams 54491-} 54492-type MonikerRegistrationOptions struct { // line 3378 54493- TextDocumentRegistrationOptions 54494- MonikerOptions 54495-} 54496- 54497-// created for Literal (Lit_MarkedString_Item1) 54498-type Msg_MarkedString struct { // line 14068 54499- Language string `json:"language"` 54500- Value string `json:"value"` 54501-} 54502- 54503-// created for Literal (Lit_NotebookDocumentFilter_Item0) 54504-type Msg_NotebookDocumentFilter struct { // line 14260 54505- // The type of the enclosing notebook. 54506- NotebookType string `json:"notebookType"` 54507- // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. 54508- Scheme string `json:"scheme,omitempty"` 54509- // A glob pattern. 54510- Pattern string `json:"pattern,omitempty"` 54511-} 54512- 54513-// created for Literal (Lit_PrepareRenameResult_Item1) 54514-type Msg_PrepareRename2Gn struct { // line 13911 54515- Range Range `json:"range"` 54516- Placeholder string `json:"placeholder"` 54517-} 54518- 54519-// created for Literal (Lit_TextDocumentContentChangeEvent_Item0) 54520-type Msg_TextDocumentContentChangeEvent struct { // line 14008 54521- // The range of the document that changed. 54522- Range *Range `json:"range"` 54523- // The optional length of the range that got replaced. 54524- // 54525- // @deprecated use range instead. 54526- RangeLength uint32 `json:"rangeLength,omitempty"` 54527- // The new text for the provided range. 54528- Text string `json:"text"` 54529-} 54530- 54531-// created for Literal (Lit_TextDocumentFilter_Item1) 54532-type Msg_TextDocumentFilter struct { // line 14184 54533- // A language id, like `typescript`. 54534- Language string `json:"language,omitempty"` 54535- // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. 54536- Scheme string `json:"scheme"` 54537- // A glob pattern, like `*.{ts,js}`. 54538- Pattern string `json:"pattern,omitempty"` 54539-} 54540- 54541-// created for Literal (Lit__InitializeParams_clientInfo) 54542-type Msg_XInitializeParams_clientInfo struct { // line 7673 54543- // The name of the client as defined by the client. 54544- Name string `json:"name"` 54545- // The client's version as defined by the client. 54546- Version string `json:"version,omitempty"` 54547-} 54548- 54549-// A notebook cell. 54550-// 54551-// A cell's document URI must be unique across ALL notebook 54552-// cells and can therefore be used to uniquely identify a 54553-// notebook cell or the cell's text document. 54554-// 54555-// @since 3.17.0 54556-type NotebookCell struct { // line 9598 54557- // The cell's kind 54558- Kind NotebookCellKind `json:"kind"` 54559- // The URI of the cell's text document 54560- // content. 54561- Document DocumentURI `json:"document"` 54562- // Additional metadata stored with the cell. 54563- // 54564- // Note: should always be an object literal (e.g. LSPObject) 54565- Metadata *LSPObject `json:"metadata,omitempty"` 54566- // Additional execution summary information 54567- // if supported by the client. 54568- ExecutionSummary *ExecutionSummary `json:"executionSummary,omitempty"` 54569-} 54570- 54571-// A change describing how to move a `NotebookCell` 54572-// array from state S to S'. 54573-// 54574-// @since 3.17.0 54575-type NotebookCellArrayChange struct { // line 9639 54576- // The start oftest of the cell that changed. 54577- Start uint32 `json:"start"` 54578- // The deleted cells 54579- DeleteCount uint32 `json:"deleteCount"` 54580- // The new cells, if any 54581- Cells []NotebookCell `json:"cells,omitempty"` 54582-} 54583- 54584-// A notebook cell kind. 54585-// 54586-// @since 3.17.0 54587-type NotebookCellKind uint32 // line 13648 54588-// A notebook cell text document filter denotes a cell text 54589-// document by different properties. 54590-// 54591-// @since 3.17.0 54592-type NotebookCellTextDocumentFilter struct { // line 10113 54593- // A filter that matches against the notebook 54594- // containing the notebook cell. If a string 54595- // value is provided it matches against the 54596- // notebook type. '*' matches every notebook. 54597- Notebook Or_NotebookCellTextDocumentFilter_notebook `json:"notebook"` 54598- // A language id like `python`. 54599- // 54600- // Will be matched against the language id of the 54601- // notebook cell document. '*' matches every language. 54602- Language string `json:"language,omitempty"` 54603-} 54604- 54605-// A notebook document. 54606-// 54607-// @since 3.17.0 54608-type NotebookDocument struct { // line 7354 54609- // The notebook document's uri. 54610- URI URI `json:"uri"` 54611- // The type of the notebook. 54612- NotebookType string `json:"notebookType"` 54613- // The version number of this document (it will increase after each 54614- // change, including undo/redo). 54615- Version int32 `json:"version"` 54616- // Additional metadata stored with the notebook 54617- // document. 54618- // 54619- // Note: should always be an object literal (e.g. LSPObject) 54620- Metadata *LSPObject `json:"metadata,omitempty"` 54621- // The cells of a notebook. 54622- Cells []NotebookCell `json:"cells"` 54623-} 54624- 54625-// A change event for a notebook document. 54626-// 54627-// @since 3.17.0 54628-type NotebookDocumentChangeEvent struct { // line 7466 54629- // The changed meta data if any. 54630- // 54631- // Note: should always be an object literal (e.g. LSPObject) 54632- Metadata *LSPObject `json:"metadata,omitempty"` 54633- // Changes to cells 54634- Cells *PCellsPChange `json:"cells,omitempty"` 54635-} 54636- 54637-// Capabilities specific to the notebook document support. 54638-// 54639-// @since 3.17.0 54640-type NotebookDocumentClientCapabilities struct { // line 10613 54641- // Capabilities specific to notebook document synchronization 54642- // 54643- // @since 3.17.0 54644- Synchronization NotebookDocumentSyncClientCapabilities `json:"synchronization"` 54645-} 54646- 54647-// A notebook document filter denotes a notebook document by 54648-// different properties. The properties will be match 54649-// against the notebook's URI (same as with documents) 54650-// 54651-// @since 3.17.0 54652-type NotebookDocumentFilter = Msg_NotebookDocumentFilter // (alias) line 14254 54653-// A literal to identify a notebook document in the client. 54654-// 54655-// @since 3.17.0 54656-type NotebookDocumentIdentifier struct { // line 7582 54657- // The notebook document's uri. 54658- URI URI `json:"uri"` 54659-} 54660- 54661-// Notebook specific client capabilities. 54662-// 54663-// @since 3.17.0 54664-type NotebookDocumentSyncClientCapabilities struct { // line 12433 54665- // Whether implementation supports dynamic registration. If this is 54666- // set to `true` the client supports the new 54667- // `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` 54668- // return value for the corresponding server capability as well. 54669- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 54670- // The client supports sending execution summary data per cell. 54671- ExecutionSummarySupport bool `json:"executionSummarySupport,omitempty"` 54672-} 54673- 54674-// Options specific to a notebook plus its cells 54675-// to be synced to the server. 54676-// 54677-// If a selector provides a notebook document 54678-// filter but no cell selector all cells of a 54679-// matching notebook document will be synced. 54680-// 54681-// If a selector provides no notebook document 54682-// filter but only a cell selector all notebook 54683-// document that contain at least one matching 54684-// cell will be synced. 54685-// 54686-// @since 3.17.0 54687-type NotebookDocumentSyncOptions struct { // line 9795 54688- // The notebooks to be synced 54689- NotebookSelector []PNotebookSelectorPNotebookDocumentSync `json:"notebookSelector"` 54690- // Whether save notification should be forwarded to 54691- // the server. Will only be honored if mode === `notebook`. 54692- Save bool `json:"save,omitempty"` 54693-} 54694- 54695-// Registration options specific to a notebook. 54696-// 54697-// @since 3.17.0 54698-type NotebookDocumentSyncRegistrationOptions struct { // line 9915 54699- NotebookDocumentSyncOptions 54700- StaticRegistrationOptions 54701-} 54702- 54703-// A text document identifier to optionally denote a specific version of a text document. 54704-type OptionalVersionedTextDocumentIdentifier struct { // line 9343 54705- // The version number of this document. If a versioned text document identifier 54706- // is sent from the server to the client and the file is not open in the editor 54707- // (the server has not received an open notification before) the server can send 54708- // `null` to indicate that the version is unknown and the content on disk is the 54709- // truth (as specified with document content ownership). 54710- Version int32 `json:"version"` 54711- TextDocumentIdentifier 54712-} 54713- 54714-// created for Or [FEditRangePItemDefaults Range] 54715-type OrFEditRangePItemDefaults struct { // line 4770 54716- Value interface{} `json:"value"` 54717-} 54718- 54719-// created for Or [NotebookDocumentFilter string] 54720-type OrFNotebookPNotebookSelector struct { // line 9812 54721- Value interface{} `json:"value"` 54722-} 54723- 54724-// created for Or [Location PLocationMsg_workspace_symbol] 54725-type OrPLocation_workspace_symbol struct { // line 5521 54726- Value interface{} `json:"value"` 54727-} 54728- 54729-// created for Or [[]string string] 54730-type OrPSection_workspace_didChangeConfiguration struct { // line 4164 54731- Value interface{} `json:"value"` 54732-} 54733- 54734-// created for Or [MarkupContent string] 54735-type OrPTooltipPLabel struct { // line 7076 54736- Value interface{} `json:"value"` 54737-} 54738- 54739-// created for Or [MarkupContent string] 54740-type OrPTooltip_textDocument_inlayHint struct { // line 3700 54741- Value interface{} `json:"value"` 54742-} 54743- 54744-// created for Or [int32 string] 54745-type Or_CancelParams_id struct { // line 6185 54746- Value interface{} `json:"value"` 54747-} 54748- 54749-// created for Or [MarkupContent string] 54750-type Or_CompletionItem_documentation struct { // line 4583 54751- Value interface{} `json:"value"` 54752-} 54753- 54754-// created for Or [InsertReplaceEdit TextEdit] 54755-type Or_CompletionItem_textEdit struct { // line 4666 54756- Value interface{} `json:"value"` 54757-} 54758- 54759-// created for Or [Location []Location] 54760-type Or_Definition struct { // line 13754 54761- Value interface{} `json:"value"` 54762-} 54763- 54764-// created for Or [int32 string] 54765-type Or_Diagnostic_code struct { // line 8548 54766- Value interface{} `json:"value"` 54767-} 54768- 54769-// created for Or [RelatedFullDocumentDiagnosticReport RelatedUnchangedDocumentDiagnosticReport] 54770-type Or_DocumentDiagnosticReport struct { // line 13886 54771- Value interface{} `json:"value"` 54772-} 54773- 54774-// created for Or [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport] 54775-type Or_DocumentDiagnosticReportPartialResult_relatedDocuments_Value struct { // line 3823 54776- Value interface{} `json:"value"` 54777-} 54778- 54779-// created for Or [NotebookCellTextDocumentFilter TextDocumentFilter] 54780-type Or_DocumentFilter struct { // line 14096 54781- Value interface{} `json:"value"` 54782-} 54783- 54784-// created for Or [MarkedString MarkupContent []MarkedString] 54785-type Or_Hover_contents struct { // line 4892 54786- Value interface{} `json:"value"` 54787-} 54788- 54789-// created for Or [[]InlayHintLabelPart string] 54790-type Or_InlayHint_label struct { // line 3659 54791- Value interface{} `json:"value"` 54792-} 54793- 54794-// created for Or [InlineValueEvaluatableExpression InlineValueText InlineValueVariableLookup] 54795-type Or_InlineValue struct { // line 13864 54796- Value interface{} `json:"value"` 54797-} 54798- 54799-// created for Or [Msg_MarkedString string] 54800-type Or_MarkedString struct { // line 14061 54801- Value interface{} `json:"value"` 54802-} 54803- 54804-// created for Or [NotebookDocumentFilter string] 54805-type Or_NotebookCellTextDocumentFilter_notebook struct { // line 10119 54806- Value interface{} `json:"value"` 54807-} 54808- 54809-// created for Or [NotebookDocumentFilter string] 54810-type Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook struct { // line 9858 54811- Value interface{} `json:"value"` 54812-} 54813- 54814-// created for Or [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport] 54815-type Or_RelatedFullDocumentDiagnosticReport_relatedDocuments_Value struct { // line 7169 54816- Value interface{} `json:"value"` 54817-} 54818- 54819-// created for Or [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport] 54820-type Or_RelatedUnchangedDocumentDiagnosticReport_relatedDocuments_Value struct { // line 7208 54821- Value interface{} `json:"value"` 54822-} 54823- 54824-// created for Or [URI WorkspaceFolder] 54825-type Or_RelativePattern_baseUri struct { // line 10742 54826- Value interface{} `json:"value"` 54827-} 54828- 54829-// created for Or [CodeAction Command] 54830-type Or_Result_textDocument_codeAction_Item0_Elem struct { // line 1372 54831- Value interface{} `json:"value"` 54832-} 54833- 54834-// created for Or [FFullPRequests bool] 54835-type Or_SemanticTokensClientCapabilities_requests_full struct { // line 12198 54836- Value interface{} `json:"value"` 54837-} 54838- 54839-// created for Or [FRangePRequests bool] 54840-type Or_SemanticTokensClientCapabilities_requests_range struct { // line 12178 54841- Value interface{} `json:"value"` 54842-} 54843- 54844-// created for Or [PFullESemanticTokensOptions bool] 54845-type Or_SemanticTokensOptions_full struct { // line 6580 54846- Value interface{} `json:"value"` 54847-} 54848- 54849-// created for Or [PRangeESemanticTokensOptions bool] 54850-type Or_SemanticTokensOptions_range struct { // line 6560 54851- Value interface{} `json:"value"` 54852-} 54853- 54854-// created for Or [CallHierarchyOptions CallHierarchyRegistrationOptions bool] 54855-type Or_ServerCapabilities_callHierarchyProvider struct { // line 8228 54856- Value interface{} `json:"value"` 54857-} 54858- 54859-// created for Or [CodeActionOptions bool] 54860-type Or_ServerCapabilities_codeActionProvider struct { // line 8036 54861- Value interface{} `json:"value"` 54862-} 54863- 54864-// created for Or [DocumentColorOptions DocumentColorRegistrationOptions bool] 54865-type Or_ServerCapabilities_colorProvider struct { // line 8072 54866- Value interface{} `json:"value"` 54867-} 54868- 54869-// created for Or [DeclarationOptions DeclarationRegistrationOptions bool] 54870-type Or_ServerCapabilities_declarationProvider struct { // line 7898 54871- Value interface{} `json:"value"` 54872-} 54873- 54874-// created for Or [DefinitionOptions bool] 54875-type Or_ServerCapabilities_definitionProvider struct { // line 7920 54876- Value interface{} `json:"value"` 54877-} 54878- 54879-// created for Or [DiagnosticOptions DiagnosticRegistrationOptions] 54880-type Or_ServerCapabilities_diagnosticProvider struct { // line 8385 54881- Value interface{} `json:"value"` 54882-} 54883- 54884-// created for Or [DocumentFormattingOptions bool] 54885-type Or_ServerCapabilities_documentFormattingProvider struct { // line 8112 54886- Value interface{} `json:"value"` 54887-} 54888- 54889-// created for Or [DocumentHighlightOptions bool] 54890-type Or_ServerCapabilities_documentHighlightProvider struct { // line 8000 54891- Value interface{} `json:"value"` 54892-} 54893- 54894-// created for Or [DocumentRangeFormattingOptions bool] 54895-type Or_ServerCapabilities_documentRangeFormattingProvider struct { // line 8130 54896- Value interface{} `json:"value"` 54897-} 54898- 54899-// created for Or [DocumentSymbolOptions bool] 54900-type Or_ServerCapabilities_documentSymbolProvider struct { // line 8018 54901- Value interface{} `json:"value"` 54902-} 54903- 54904-// created for Or [FoldingRangeOptions FoldingRangeRegistrationOptions bool] 54905-type Or_ServerCapabilities_foldingRangeProvider struct { // line 8175 54906- Value interface{} `json:"value"` 54907-} 54908- 54909-// created for Or [HoverOptions bool] 54910-type Or_ServerCapabilities_hoverProvider struct { // line 7871 54911- Value interface{} `json:"value"` 54912-} 54913- 54914-// created for Or [ImplementationOptions ImplementationRegistrationOptions bool] 54915-type Or_ServerCapabilities_implementationProvider struct { // line 7960 54916- Value interface{} `json:"value"` 54917-} 54918- 54919-// created for Or [InlayHintOptions InlayHintRegistrationOptions bool] 54920-type Or_ServerCapabilities_inlayHintProvider struct { // line 8362 54921- Value interface{} `json:"value"` 54922-} 54923- 54924-// created for Or [InlineValueOptions InlineValueRegistrationOptions bool] 54925-type Or_ServerCapabilities_inlineValueProvider struct { // line 8339 54926- Value interface{} `json:"value"` 54927-} 54928- 54929-// created for Or [LinkedEditingRangeOptions LinkedEditingRangeRegistrationOptions bool] 54930-type Or_ServerCapabilities_linkedEditingRangeProvider struct { // line 8251 54931- Value interface{} `json:"value"` 54932-} 54933- 54934-// created for Or [MonikerOptions MonikerRegistrationOptions bool] 54935-type Or_ServerCapabilities_monikerProvider struct { // line 8293 54936- Value interface{} `json:"value"` 54937-} 54938- 54939-// created for Or [NotebookDocumentSyncOptions NotebookDocumentSyncRegistrationOptions] 54940-type Or_ServerCapabilities_notebookDocumentSync struct { // line 7843 54941- Value interface{} `json:"value"` 54942-} 54943- 54944-// created for Or [ReferenceOptions bool] 54945-type Or_ServerCapabilities_referencesProvider struct { // line 7982 54946- Value interface{} `json:"value"` 54947-} 54948- 54949-// created for Or [RenameOptions bool] 54950-type Or_ServerCapabilities_renameProvider struct { // line 8157 54951- Value interface{} `json:"value"` 54952-} 54953- 54954-// created for Or [SelectionRangeOptions SelectionRangeRegistrationOptions bool] 54955-type Or_ServerCapabilities_selectionRangeProvider struct { // line 8197 54956- Value interface{} `json:"value"` 54957-} 54958- 54959-// created for Or [SemanticTokensOptions SemanticTokensRegistrationOptions] 54960-type Or_ServerCapabilities_semanticTokensProvider struct { // line 8274 54961- Value interface{} `json:"value"` 54962-} 54963- 54964-// created for Or [TextDocumentSyncKind TextDocumentSyncOptions] 54965-type Or_ServerCapabilities_textDocumentSync struct { // line 7825 54966- Value interface{} `json:"value"` 54967-} 54968- 54969-// created for Or [TypeDefinitionOptions TypeDefinitionRegistrationOptions bool] 54970-type Or_ServerCapabilities_typeDefinitionProvider struct { // line 7938 54971- Value interface{} `json:"value"` 54972-} 54973- 54974-// created for Or [TypeHierarchyOptions TypeHierarchyRegistrationOptions bool] 54975-type Or_ServerCapabilities_typeHierarchyProvider struct { // line 8316 54976- Value interface{} `json:"value"` 54977-} 54978- 54979-// created for Or [WorkspaceSymbolOptions bool] 54980-type Or_ServerCapabilities_workspaceSymbolProvider struct { // line 8094 54981- Value interface{} `json:"value"` 54982-} 54983- 54984-// created for Or [MarkupContent string] 54985-type Or_SignatureInformation_documentation struct { // line 8842 54986- Value interface{} `json:"value"` 54987-} 54988- 54989-// created for Or [AnnotatedTextEdit TextEdit] 54990-type Or_TextDocumentEdit_edits_Elem struct { // line 6693 54991- Value interface{} `json:"value"` 54992-} 54993- 54994-// created for Or [SaveOptions bool] 54995-type Or_TextDocumentSyncOptions_save struct { // line 9778 54996- Value interface{} `json:"value"` 54997-} 54998- 54999-// created for Or [WorkspaceFullDocumentDiagnosticReport WorkspaceUnchangedDocumentDiagnosticReport] 55000-type Or_WorkspaceDocumentDiagnosticReport struct { // line 13987 55001- Value interface{} `json:"value"` 55002-} 55003- 55004-// created for Or [CreateFile DeleteFile RenameFile TextDocumentEdit] 55005-type Or_WorkspaceEdit_documentChanges_Elem struct { // line 3220 55006- Value interface{} `json:"value"` 55007-} 55008- 55009-// created for Or [Declaration []DeclarationLink] 55010-type Or_textDocument_declaration struct { // line 249 55011- Value interface{} `json:"value"` 55012-} 55013- 55014-// created for Literal (Lit_NotebookDocumentChangeEvent_cells) 55015-type PCellsPChange struct { // line 7481 55016- // Changes to the cell structure to add or 55017- // remove cells. 55018- Structure *FStructurePCells `json:"structure,omitempty"` 55019- // Changes to notebook cells properties like its 55020- // kind, execution summary or metadata. 55021- Data []NotebookCell `json:"data,omitempty"` 55022- // Changes to the text content of notebook cells. 55023- TextContent []Lit_NotebookDocumentChangeEvent_cells_textContent_Elem `json:"textContent,omitempty"` 55024-} 55025- 55026-// created for Literal (Lit_WorkspaceEditClientCapabilities_changeAnnotationSupport) 55027-type PChangeAnnotationSupportPWorkspaceEdit struct { // line 10816 55028- // Whether the client groups edits with equal labels into tree nodes, 55029- // for instance all edits labelled with "Changes in Strings" would 55030- // be a tree node. 55031- GroupsOnLabel bool `json:"groupsOnLabel,omitempty"` 55032-} 55033- 55034-// created for Literal (Lit_CodeActionClientCapabilities_codeActionLiteralSupport) 55035-type PCodeActionLiteralSupportPCodeAction struct { // line 11736 55036- // The code action kind is support with the following value 55037- // set. 55038- CodeActionKind FCodeActionKindPCodeActionLiteralSupport `json:"codeActionKind"` 55039-} 55040- 55041-// created for Literal (Lit_CompletionClientCapabilities_completionItemKind) 55042-type PCompletionItemKindPCompletion struct { // line 11334 55043- // The completion item kind values the client supports. When this 55044- // property exists the client also guarantees that it will 55045- // handle values outside its set gracefully and falls back 55046- // to a default value when unknown. 55047- // 55048- // If this property is not present the client only supports 55049- // the completion items kinds from `Text` to `Reference` as defined in 55050- // the initial version of the protocol. 55051- ValueSet []CompletionItemKind `json:"valueSet,omitempty"` 55052-} 55053- 55054-// created for Literal (Lit_CompletionClientCapabilities_completionItem) 55055-type PCompletionItemPCompletion struct { // line 11183 55056- // Client supports snippets as insert text. 55057- // 55058- // A snippet can define tab stops and placeholders with `$1`, `$2` 55059- // and `${3:foo}`. `$0` defines the final tab stop, it defaults to 55060- // the end of the snippet. Placeholders with equal identifiers are linked, 55061- // that is typing in one will update others too. 55062- SnippetSupport bool `json:"snippetSupport,omitempty"` 55063- // Client supports commit characters on a completion item. 55064- CommitCharactersSupport bool `json:"commitCharactersSupport,omitempty"` 55065- // Client supports the following content formats for the documentation 55066- // property. The order describes the preferred format of the client. 55067- DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` 55068- // Client supports the deprecated property on a completion item. 55069- DeprecatedSupport bool `json:"deprecatedSupport,omitempty"` 55070- // Client supports the preselect property on a completion item. 55071- PreselectSupport bool `json:"preselectSupport,omitempty"` 55072- // Client supports the tag property on a completion item. Clients supporting 55073- // tags have to handle unknown tags gracefully. Clients especially need to 55074- // preserve unknown tags when sending a completion item back to the server in 55075- // a resolve call. 55076- // 55077- // @since 3.15.0 55078- TagSupport FTagSupportPCompletionItem `json:"tagSupport"` 55079- // Client support insert replace edit to control different behavior if a 55080- // completion item is inserted in the text or should replace text. 55081- // 55082- // @since 3.16.0 55083- InsertReplaceSupport bool `json:"insertReplaceSupport,omitempty"` 55084- // Indicates which properties a client can resolve lazily on a completion 55085- // item. Before version 3.16.0 only the predefined properties `documentation` 55086- // and `details` could be resolved lazily. 55087- // 55088- // @since 3.16.0 55089- ResolveSupport *FResolveSupportPCompletionItem `json:"resolveSupport,omitempty"` 55090- // The client supports the `insertTextMode` property on 55091- // a completion item to override the whitespace handling mode 55092- // as defined by the client (see `insertTextMode`). 55093- // 55094- // @since 3.16.0 55095- InsertTextModeSupport *FInsertTextModeSupportPCompletionItem `json:"insertTextModeSupport,omitempty"` 55096- // The client has support for completion item label 55097- // details (see also `CompletionItemLabelDetails`). 55098- // 55099- // @since 3.17.0 55100- LabelDetailsSupport bool `json:"labelDetailsSupport,omitempty"` 55101-} 55102- 55103-// created for Literal (Lit_CompletionOptions_completionItem) 55104-type PCompletionItemPCompletionProvider struct { // line 8747 55105- // The server has support for completion item label 55106- // details (see also `CompletionItemLabelDetails`) when 55107- // receiving a completion item in a resolve call. 55108- // 55109- // @since 3.17.0 55110- LabelDetailsSupport bool `json:"labelDetailsSupport,omitempty"` 55111-} 55112- 55113-// created for Literal (Lit_CompletionClientCapabilities_completionList) 55114-type PCompletionListPCompletion struct { // line 11376 55115- // The client supports the following itemDefaults on 55116- // a completion list. 55117- // 55118- // The value lists the supported property names of the 55119- // `CompletionList.itemDefaults` object. If omitted 55120- // no properties are supported. 55121- // 55122- // @since 3.17.0 55123- ItemDefaults []string `json:"itemDefaults,omitempty"` 55124-} 55125- 55126-// created for Literal (Lit_CodeAction_disabled) 55127-type PDisabledMsg_textDocument_codeAction struct { // line 5427 55128- // Human readable description of why the code action is currently disabled. 55129- // 55130- // This is displayed in the code actions UI. 55131- Reason string `json:"reason"` 55132-} 55133- 55134-// created for Literal (Lit_FoldingRangeClientCapabilities_foldingRangeKind) 55135-type PFoldingRangeKindPFoldingRange struct { // line 12011 55136- // The folding range kind values the client supports. When this 55137- // property exists the client also guarantees that it will 55138- // handle values outside its set gracefully and falls back 55139- // to a default value when unknown. 55140- ValueSet []FoldingRangeKind `json:"valueSet,omitempty"` 55141-} 55142- 55143-// created for Literal (Lit_FoldingRangeClientCapabilities_foldingRange) 55144-type PFoldingRangePFoldingRange struct { // line 12036 55145- // If set, the client signals that it supports setting collapsedText on 55146- // folding ranges to display custom labels instead of the default text. 55147- // 55148- // @since 3.17.0 55149- CollapsedText bool `json:"collapsedText,omitempty"` 55150-} 55151- 55152-// created for Literal (Lit_SemanticTokensOptions_full_Item1) 55153-type PFullESemanticTokensOptions struct { // line 6587 55154- // The server supports deltas for full documents. 55155- Delta bool `json:"delta"` 55156-} 55157- 55158-// created for Literal (Lit_CompletionList_itemDefaults) 55159-type PItemDefaultsMsg_textDocument_completion struct { // line 4751 55160- // A default commit character set. 55161- // 55162- // @since 3.17.0 55163- CommitCharacters []string `json:"commitCharacters,omitempty"` 55164- // A default edit range. 55165- // 55166- // @since 3.17.0 55167- EditRange *OrFEditRangePItemDefaults `json:"editRange,omitempty"` 55168- // A default insert text format. 55169- // 55170- // @since 3.17.0 55171- InsertTextFormat *InsertTextFormat `json:"insertTextFormat,omitempty"` 55172- // A default insert text mode. 55173- // 55174- // @since 3.17.0 55175- InsertTextMode *InsertTextMode `json:"insertTextMode,omitempty"` 55176- // A default data value. 55177- // 55178- // @since 3.17.0 55179- Data interface{} `json:"data,omitempty"` 55180-} 55181- 55182-// created for Literal (Lit_WorkspaceSymbol_location_Item1) 55183-type PLocationMsg_workspace_symbol struct { // line 5528 55184- URI DocumentURI `json:"uri"` 55185-} 55186- 55187-// created for Literal (Lit_ShowMessageRequestClientCapabilities_messageActionItem) 55188-type PMessageActionItemPShowMessage struct { // line 12464 55189- // Whether the client supports additional attributes which 55190- // are preserved and send back to the server in the 55191- // request's response. 55192- AdditionalPropertiesSupport bool `json:"additionalPropertiesSupport,omitempty"` 55193-} 55194- 55195-// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0) 55196-type PNotebookSelectorPNotebookDocumentSync struct { // line 9806 55197- // The notebook to be synced If a string 55198- // value is provided it matches against the 55199- // notebook type. '*' matches every notebook. 55200- Notebook OrFNotebookPNotebookSelector `json:"notebook"` 55201- // The cells of the matching notebook to be synced. 55202- Cells []Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_cells_Elem `json:"cells,omitempty"` 55203-} 55204- 55205-// created for Literal (Lit_SemanticTokensOptions_range_Item1) 55206-type PRangeESemanticTokensOptions struct { // line 6567 55207-} 55208- 55209-// created for Literal (Lit_SemanticTokensClientCapabilities_requests) 55210-type PRequestsPSemanticTokens struct { // line 12172 55211- // The client will send the `textDocument/semanticTokens/range` request if 55212- // the server provides a corresponding handler. 55213- Range Or_SemanticTokensClientCapabilities_requests_range `json:"range"` 55214- // The client will send the `textDocument/semanticTokens/full` request if 55215- // the server provides a corresponding handler. 55216- Full Or_SemanticTokensClientCapabilities_requests_full `json:"full"` 55217-} 55218- 55219-// created for Literal (Lit_CodeActionClientCapabilities_resolveSupport) 55220-type PResolveSupportPCodeAction struct { // line 11801 55221- // The properties that a client can resolve lazily. 55222- Properties []string `json:"properties"` 55223-} 55224- 55225-// created for Literal (Lit_InlayHintClientCapabilities_resolveSupport) 55226-type PResolveSupportPInlayHint struct { // line 12384 55227- // The properties that a client can resolve lazily. 55228- Properties []string `json:"properties"` 55229-} 55230- 55231-// created for Literal (Lit_WorkspaceSymbolClientCapabilities_resolveSupport) 55232-type PResolveSupportPSymbol struct { // line 10938 55233- // The properties that a client can resolve lazily. Usually 55234- // `location.range` 55235- Properties []string `json:"properties"` 55236-} 55237- 55238-// created for Literal (Lit_InitializeResult_serverInfo) 55239-type PServerInfoMsg_initialize struct { // line 4096 55240- // The name of the server as defined by the server. 55241- Name string `json:"name"` 55242- // The server's version as defined by the server. 55243- Version string `json:"version,omitempty"` 55244-} 55245- 55246-// created for Literal (Lit_SignatureHelpClientCapabilities_signatureInformation) 55247-type PSignatureInformationPSignatureHelp struct { // line 11443 55248- // Client supports the following content formats for the documentation 55249- // property. The order describes the preferred format of the client. 55250- DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` 55251- // Client capabilities specific to parameter information. 55252- ParameterInformation *FParameterInformationPSignatureInformation `json:"parameterInformation,omitempty"` 55253- // The client supports the `activeParameter` property on `SignatureInformation` 55254- // literal. 55255- // 55256- // @since 3.16.0 55257- ActiveParameterSupport bool `json:"activeParameterSupport,omitempty"` 55258-} 55259- 55260-// created for Literal (Lit_GeneralClientCapabilities_staleRequestSupport) 55261-type PStaleRequestSupportPGeneral struct { // line 10670 55262- // The client will actively cancel the request. 55263- Cancel bool `json:"cancel"` 55264- // The list of requests for which the client 55265- // will retry the request if it receives a 55266- // response with error code `ContentModified` 55267- RetryOnContentModified []string `json:"retryOnContentModified"` 55268-} 55269- 55270-// created for Literal (Lit_DocumentSymbolClientCapabilities_symbolKind) 55271-type PSymbolKindPDocumentSymbol struct { // line 11654 55272- // The symbol kind values the client supports. When this 55273- // property exists the client also guarantees that it will 55274- // handle values outside its set gracefully and falls back 55275- // to a default value when unknown. 55276- // 55277- // If this property is not present the client only supports 55278- // the symbol kinds from `File` to `Array` as defined in 55279- // the initial version of the protocol. 55280- ValueSet []SymbolKind `json:"valueSet,omitempty"` 55281-} 55282- 55283-// created for Literal (Lit_WorkspaceSymbolClientCapabilities_symbolKind) 55284-type PSymbolKindPSymbol struct { // line 10890 55285- // The symbol kind values the client supports. When this 55286- // property exists the client also guarantees that it will 55287- // handle values outside its set gracefully and falls back 55288- // to a default value when unknown. 55289- // 55290- // If this property is not present the client only supports 55291- // the symbol kinds from `File` to `Array` as defined in 55292- // the initial version of the protocol. 55293- ValueSet []SymbolKind `json:"valueSet,omitempty"` 55294-} 55295- 55296-// created for Literal (Lit_DocumentSymbolClientCapabilities_tagSupport) 55297-type PTagSupportPDocumentSymbol struct { // line 11687 55298- // The tags supported by the client. 55299- ValueSet []SymbolTag `json:"valueSet"` 55300-} 55301- 55302-// created for Literal (Lit_PublishDiagnosticsClientCapabilities_tagSupport) 55303-type PTagSupportPPublishDiagnostics struct { // line 12087 55304- // The tags supported by the client. 55305- ValueSet []DiagnosticTag `json:"valueSet"` 55306-} 55307- 55308-// created for Literal (Lit_WorkspaceSymbolClientCapabilities_tagSupport) 55309-type PTagSupportPSymbol struct { // line 10914 55310- // The tags supported by the client. 55311- ValueSet []SymbolTag `json:"valueSet"` 55312-} 55313- 55314-// The parameters of a configuration request. 55315-type ParamConfiguration struct { // line 2199 55316- Items []ConfigurationItem `json:"items"` 55317-} 55318-type ParamInitialize struct { // line 4068 55319- XInitializeParams 55320- WorkspaceFoldersInitializeParams 55321-} 55322- 55323-// Represents a parameter of a callable-signature. A parameter can 55324-// have a label and a doc-comment. 55325-type ParameterInformation struct { // line 10063 55326- // The label of this parameter information. 55327- // 55328- // Either a string or an inclusive start and exclusive end offsets within its containing 55329- // signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 55330- // string representation as `Position` and `Range` does. 55331- // 55332- // *Note*: a label of type string should be a substring of its containing signature label. 55333- // Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. 55334- Label string `json:"label"` 55335- // The human-readable doc-comment of this parameter. Will be shown 55336- // in the UI but can be omitted. 55337- Documentation string `json:"documentation,omitempty"` 55338-} 55339-type PartialResultParams struct { // line 6258 55340- // An optional token that a server can use to report partial results (e.g. streaming) to 55341- // the client. 55342- PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"` 55343-} 55344- 55345-// The glob pattern to watch relative to the base path. Glob patterns can have the following syntax: 55346-// 55347-// - `*` to match one or more characters in a path segment 55348-// - `?` to match on one character in a path segment 55349-// - `**` to match any number of path segments, including none 55350-// - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) 55351-// - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) 55352-// - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) 55353-// 55354-// @since 3.17.0 55355-type Pattern = string // (alias) line 14363 55356-// Position in a text document expressed as zero-based line and character 55357-// offset. Prior to 3.17 the offsets were always based on a UTF-16 string 55358-// representation. So a string of the form `ab` the character offset of the 55359-// character `a` is 0, the character offset of `` is 1 and the character 55360-// offset of b is 3 since `` is represented using two code units in UTF-16. 55361-// Since 3.17 clients and servers can agree on a different string encoding 55362-// representation (e.g. UTF-8). The client announces it's supported encoding 55363-// via the client capability [`general.positionEncodings`](#clientCapabilities). 55364-// The value is an array of position encodings the client supports, with 55365-// decreasing preference (e.g. the encoding at index `0` is the most preferred 55366-// one). To stay backwards compatible the only mandatory encoding is UTF-16 55367-// represented via the string `utf-16`. The server can pick one of the 55368-// encodings offered by the client and signals that encoding back to the 55369-// client via the initialize result's property 55370-// [`capabilities.positionEncoding`](#serverCapabilities). If the string value 55371-// `utf-16` is missing from the client's capability `general.positionEncodings` 55372-// servers can safely assume that the client supports UTF-16. If the server 55373-// omits the position encoding in its initialize result the encoding defaults 55374-// to the string value `utf-16`. Implementation considerations: since the 55375-// conversion from one encoding into another requires the content of the 55376-// file / line the conversion is best done where the file is read which is 55377-// usually on the server side. 55378-// 55379-// Positions are line end character agnostic. So you can not specify a position 55380-// that denotes `\r|\n` or `\n|` where `|` represents the character offset. 55381-// 55382-// @since 3.17.0 - support for negotiated position encoding. 55383-type Position struct { // line 6501 55384- // Line position in a document (zero-based). 55385- // 55386- // If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. 55387- // If a line number is negative, it defaults to 0. 55388- Line uint32 `json:"line"` 55389- // Character offset on a line in a document (zero-based). 55390- // 55391- // The meaning of this offset is determined by the negotiated 55392- // `PositionEncodingKind`. 55393- // 55394- // If the character value is greater than the line length it defaults back to the 55395- // line length. 55396- Character uint32 `json:"character"` 55397-} 55398- 55399-// A set of predefined position encoding kinds. 55400-// 55401-// @since 3.17.0 55402-type PositionEncodingKind string // line 13427 55403-type PrepareRename2Gn = Msg_PrepareRename2Gn // (alias) line 13927 55404-type PrepareRenameParams struct { // line 5925 55405- TextDocumentPositionParams 55406- WorkDoneProgressParams 55407-} 55408-type PrepareRenameResult = Msg_PrepareRename2Gn // (alias) line 13927 55409-type PrepareSupportDefaultBehavior uint32 // line 13722 55410-// A previous result id in a workspace pull request. 55411-// 55412-// @since 3.17.0 55413-type PreviousResultID struct { // line 7331 55414- // The URI for which the client knowns a 55415- // result id. 55416- URI DocumentURI `json:"uri"` 55417- // The value of the previous result id. 55418- Value string `json:"value"` 55419-} 55420- 55421-// A previous result id in a workspace pull request. 55422-// 55423-// @since 3.17.0 55424-type PreviousResultId struct { // line 7331 55425- // The URI for which the client knowns a 55426- // result id. 55427- URI DocumentURI `json:"uri"` 55428- // The value of the previous result id. 55429- Value string `json:"value"` 55430-} 55431-type ProgressParams struct { // line 6201 55432- // The progress token provided by the client or server. 55433- Token ProgressToken `json:"token"` 55434- // The progress data. 55435- Value interface{} `json:"value"` 55436-} 55437-type ProgressToken = interface{} // (alias) line 13960 55438-// The publish diagnostic client capabilities. 55439-type PublishDiagnosticsClientCapabilities struct { // line 12072 55440- // Whether the clients accepts diagnostics with related information. 55441- RelatedInformation bool `json:"relatedInformation,omitempty"` 55442- // Client supports the tag property to provide meta data about a diagnostic. 55443- // Clients supporting tags have to handle unknown tags gracefully. 55444- // 55445- // @since 3.15.0 55446- TagSupport *PTagSupportPPublishDiagnostics `json:"tagSupport,omitempty"` 55447- // Whether the client interprets the version property of the 55448- // `textDocument/publishDiagnostics` notification's parameter. 55449- // 55450- // @since 3.15.0 55451- VersionSupport bool `json:"versionSupport,omitempty"` 55452- // Client supports a codeDescription property 55453- // 55454- // @since 3.16.0 55455- CodeDescriptionSupport bool `json:"codeDescriptionSupport,omitempty"` 55456- // Whether code action supports the `data` property which is 55457- // preserved between a `textDocument/publishDiagnostics` and 55458- // `textDocument/codeAction` request. 55459- // 55460- // @since 3.16.0 55461- DataSupport bool `json:"dataSupport,omitempty"` 55462-} 55463- 55464-// The publish diagnostic notification's parameters. 55465-type PublishDiagnosticsParams struct { // line 4462 55466- // The URI for which diagnostic information is reported. 55467- URI DocumentURI `json:"uri"` 55468- // Optional the version number of the document the diagnostics are published for. 55469- // 55470- // @since 3.15.0 55471- Version int32 `json:"version,omitempty"` 55472- // An array of diagnostic information items. 55473- Diagnostics []Diagnostic `json:"diagnostics"` 55474-} 55475- 55476-// A range in a text document expressed as (zero-based) start and end positions. 55477-// 55478-// If you want to specify a range that contains a line including the line ending 55479-// character(s) then use an end position denoting the start of the next line. 55480-// For example: 55481-// ```ts 55482-// 55483-// { 55484-// start: { line: 5, character: 23 } 55485-// end : { line 6, character : 0 } 55486-// } 55487-// 55488-// ``` 55489-type Range struct { // line 6311 55490- // The range's start position. 55491- Start Position `json:"start"` 55492- // The range's end position. 55493- End Position `json:"end"` 55494-} 55495- 55496-// Client Capabilities for a {@link ReferencesRequest}. 55497-type ReferenceClientCapabilities struct { // line 11609 55498- // Whether references supports dynamic registration. 55499- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 55500-} 55501- 55502-// Value-object that contains additional information when 55503-// requesting references. 55504-type ReferenceContext struct { // line 8930 55505- // Include the declaration of the current symbol. 55506- IncludeDeclaration bool `json:"includeDeclaration"` 55507-} 55508- 55509-// Reference options. 55510-type ReferenceOptions struct { // line 8944 55511- WorkDoneProgressOptions 55512-} 55513- 55514-// Parameters for a {@link ReferencesRequest}. 55515-type ReferenceParams struct { // line 5054 55516- Context ReferenceContext `json:"context"` 55517- TextDocumentPositionParams 55518- WorkDoneProgressParams 55519- PartialResultParams 55520-} 55521- 55522-// Registration options for a {@link ReferencesRequest}. 55523-type ReferenceRegistrationOptions struct { // line 5083 55524- TextDocumentRegistrationOptions 55525- ReferenceOptions 55526-} 55527- 55528-// General parameters to to register for an notification or to register a provider. 55529-type Registration struct { // line 7597 55530- // The id used to register the request. The id can be used to deregister 55531- // the request again. 55532- ID string `json:"id"` 55533- // The method / capability to register for. 55534- Method string `json:"method"` 55535- // Options necessary for the registration. 55536- RegisterOptions interface{} `json:"registerOptions,omitempty"` 55537-} 55538-type RegistrationParams struct { // line 4038 55539- Registrations []Registration `json:"registrations"` 55540-} 55541- 55542-// Client capabilities specific to regular expressions. 55543-// 55544-// @since 3.16.0 55545-type RegularExpressionsClientCapabilities struct { // line 12500 55546- // The engine's name. 55547- Engine string `json:"engine"` 55548- // The engine's version. 55549- Version string `json:"version,omitempty"` 55550-} 55551- 55552-// A full diagnostic report with a set of related documents. 55553-// 55554-// @since 3.17.0 55555-type RelatedFullDocumentDiagnosticReport struct { // line 7157 55556- // Diagnostics of related documents. This information is useful 55557- // in programming languages where code in a file A can generate 55558- // diagnostics in a file B which A depends on. An example of 55559- // such a language is C/C++ where marco definitions in a file 55560- // a.cpp and result in errors in a header file b.hpp. 55561- // 55562- // @since 3.17.0 55563- RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments,omitempty"` 55564- FullDocumentDiagnosticReport 55565-} 55566- 55567-// An unchanged diagnostic report with a set of related documents. 55568-// 55569-// @since 3.17.0 55570-type RelatedUnchangedDocumentDiagnosticReport struct { // line 7196 55571- // Diagnostics of related documents. This information is useful 55572- // in programming languages where code in a file A can generate 55573- // diagnostics in a file B which A depends on. An example of 55574- // such a language is C/C++ where marco definitions in a file 55575- // a.cpp and result in errors in a header file b.hpp. 55576- // 55577- // @since 3.17.0 55578- RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments,omitempty"` 55579- UnchangedDocumentDiagnosticReport 55580-} 55581- 55582-// A relative pattern is a helper to construct glob patterns that are matched 55583-// relatively to a base URI. The common value for a `baseUri` is a workspace 55584-// folder root, but it can be another absolute URI as well. 55585-// 55586-// @since 3.17.0 55587-type RelativePattern struct { // line 10736 55588- // A workspace folder or a base URI to which this pattern will be matched 55589- // against relatively. 55590- BaseURI Or_RelativePattern_baseUri `json:"baseUri"` 55591- // The actual glob pattern; 55592- Pattern Pattern `json:"pattern"` 55593-} 55594-type RenameClientCapabilities struct { // line 11934 55595- // Whether rename supports dynamic registration. 55596- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 55597- // Client supports testing for validity of rename operations 55598- // before execution. 55599- // 55600- // @since 3.12.0 55601- PrepareSupport bool `json:"prepareSupport,omitempty"` 55602- // Client supports the default behavior result. 55603- // 55604- // The value indicates the default behavior used by the 55605- // client. 55606- // 55607- // @since 3.16.0 55608- PrepareSupportDefaultBehavior *PrepareSupportDefaultBehavior `json:"prepareSupportDefaultBehavior,omitempty"` 55609- // Whether the client honors the change annotations in 55610- // text edits and resource operations returned via the 55611- // rename request's workspace edit by for example presenting 55612- // the workspace edit in the user interface and asking 55613- // for confirmation. 55614- // 55615- // @since 3.16.0 55616- HonorsChangeAnnotations bool `json:"honorsChangeAnnotations,omitempty"` 55617-} 55618- 55619-// Rename file operation 55620-type RenameFile struct { // line 6749 55621- // A rename 55622- Kind string `json:"kind"` 55623- // The old (existing) location. 55624- OldURI DocumentURI `json:"oldUri"` 55625- // The new location. 55626- NewURI DocumentURI `json:"newUri"` 55627- // Rename options. 55628- Options *RenameFileOptions `json:"options,omitempty"` 55629- ResourceOperation 55630-} 55631- 55632-// Rename file options 55633-type RenameFileOptions struct { // line 9441 55634- // Overwrite target if existing. Overwrite wins over `ignoreIfExists` 55635- Overwrite bool `json:"overwrite,omitempty"` 55636- // Ignores if target exists. 55637- IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` 55638-} 55639- 55640-// The parameters sent in notifications/requests for user-initiated renames of 55641-// files. 55642-// 55643-// @since 3.16.0 55644-type RenameFilesParams struct { // line 3282 55645- // An array of all files/folders renamed in this operation. When a folder is renamed, only 55646- // the folder will be included, and not its children. 55647- Files []FileRename `json:"files"` 55648-} 55649- 55650-// Provider options for a {@link RenameRequest}. 55651-type RenameOptions struct { // line 9269 55652- // Renames should be checked and tested before being executed. 55653- // 55654- // @since version 3.12.0 55655- PrepareProvider bool `json:"prepareProvider,omitempty"` 55656- WorkDoneProgressOptions 55657-} 55658- 55659-// The parameters of a {@link RenameRequest}. 55660-type RenameParams struct { // line 5874 55661- // The document to rename. 55662- TextDocument TextDocumentIdentifier `json:"textDocument"` 55663- // The position at which this request was sent. 55664- Position Position `json:"position"` 55665- // The new name of the symbol. If the given name is not valid the 55666- // request must return a {@link ResponseError} with an 55667- // appropriate message set. 55668- NewName string `json:"newName"` 55669- WorkDoneProgressParams 55670-} 55671- 55672-// Registration options for a {@link RenameRequest}. 55673-type RenameRegistrationOptions struct { // line 5910 55674- TextDocumentRegistrationOptions 55675- RenameOptions 55676-} 55677- 55678-// A generic resource operation. 55679-type ResourceOperation struct { // line 9393 55680- // The resource operation kind. 55681- Kind string `json:"kind"` 55682- // An optional annotation identifier describing the operation. 55683- // 55684- // @since 3.16.0 55685- AnnotationID *ChangeAnnotationIdentifier `json:"annotationId,omitempty"` 55686-} 55687-type ResourceOperationKind string // line 13669 55688-// Save options. 55689-type SaveOptions struct { // line 8465 55690- // The client is supposed to include the content on save. 55691- IncludeText bool `json:"includeText,omitempty"` 55692-} 55693- 55694-// A selection range represents a part of a selection hierarchy. A selection range 55695-// may have a parent selection range that contains it. 55696-type SelectionRange struct { // line 2569 55697- // The {@link Range range} of this selection range. 55698- Range Range `json:"range"` 55699- // The parent selection range containing this range. Therefore `parent.range` must contain `this.range`. 55700- Parent *SelectionRange `json:"parent,omitempty"` 55701-} 55702-type SelectionRangeClientCapabilities struct { // line 12058 55703- // Whether implementation supports dynamic registration for selection range providers. If this is set to `true` 55704- // the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server 55705- // capability as well. 55706- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 55707-} 55708-type SelectionRangeOptions struct { // line 6524 55709- WorkDoneProgressOptions 55710-} 55711- 55712-// A parameter literal used in selection range requests. 55713-type SelectionRangeParams struct { // line 2534 55714- // The text document. 55715- TextDocument TextDocumentIdentifier `json:"textDocument"` 55716- // The positions inside the text document. 55717- Positions []Position `json:"positions"` 55718- WorkDoneProgressParams 55719- PartialResultParams 55720-} 55721-type SelectionRangeRegistrationOptions struct { // line 2592 55722- SelectionRangeOptions 55723- TextDocumentRegistrationOptions 55724- StaticRegistrationOptions 55725-} 55726- 55727-// A set of predefined token modifiers. This set is not fixed 55728-// an clients can specify additional token types via the 55729-// corresponding client capabilities. 55730-// 55731-// @since 3.16.0 55732-type SemanticTokenModifiers string // line 12670 55733-// A set of predefined token types. This set is not fixed 55734-// an clients can specify additional token types via the 55735-// corresponding client capabilities. 55736-// 55737-// @since 3.16.0 55738-type SemanticTokenTypes string // line 12563 55739-// @since 3.16.0 55740-type SemanticTokens struct { // line 2880 55741- // An optional result id. If provided and clients support delta updating 55742- // the client will include the result id in the next semantic token request. 55743- // A server can then instead of computing all semantic tokens again simply 55744- // send a delta. 55745- ResultID string `json:"resultId,omitempty"` 55746- // The actual tokens. 55747- Data []uint32 `json:"data"` 55748-} 55749- 55750-// @since 3.16.0 55751-type SemanticTokensClientCapabilities struct { // line 12157 55752- // Whether implementation supports dynamic registration. If this is set to `true` 55753- // the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` 55754- // return value for the corresponding server capability as well. 55755- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 55756- // Which requests the client supports and might send to the server 55757- // depending on the server's capability. Please note that clients might not 55758- // show semantic tokens or degrade some of the user experience if a range 55759- // or full request is advertised by the client but not provided by the 55760- // server. If for example the client capability `requests.full` and 55761- // `request.range` are both set to true but the server only provides a 55762- // range provider the client might not render a minimap correctly or might 55763- // even decide to not show any semantic tokens at all. 55764- Requests PRequestsPSemanticTokens `json:"requests"` 55765- // The token types that the client supports. 55766- TokenTypes []string `json:"tokenTypes"` 55767- // The token modifiers that the client supports. 55768- TokenModifiers []string `json:"tokenModifiers"` 55769- // The token formats the clients supports. 55770- Formats []TokenFormat `json:"formats"` 55771- // Whether the client supports tokens that can overlap each other. 55772- OverlappingTokenSupport bool `json:"overlappingTokenSupport,omitempty"` 55773- // Whether the client supports tokens that can span multiple lines. 55774- MultilineTokenSupport bool `json:"multilineTokenSupport,omitempty"` 55775- // Whether the client allows the server to actively cancel a 55776- // semantic token request, e.g. supports returning 55777- // LSPErrorCodes.ServerCancelled. If a server does the client 55778- // needs to retrigger the request. 55779- // 55780- // @since 3.17.0 55781- ServerCancelSupport bool `json:"serverCancelSupport,omitempty"` 55782- // Whether the client uses semantic tokens to augment existing 55783- // syntax tokens. If set to `true` client side created syntax 55784- // tokens and semantic tokens are both used for colorization. If 55785- // set to `false` the client only uses the returned semantic tokens 55786- // for colorization. 55787- // 55788- // If the value is `undefined` then the client behavior is not 55789- // specified. 55790- // 55791- // @since 3.17.0 55792- AugmentsSyntaxTokens bool `json:"augmentsSyntaxTokens,omitempty"` 55793-} 55794- 55795-// @since 3.16.0 55796-type SemanticTokensDelta struct { // line 2979 55797- ResultID string `json:"resultId,omitempty"` 55798- // The semantic token edits to transform a previous result into a new result. 55799- Edits []SemanticTokensEdit `json:"edits"` 55800-} 55801- 55802-// @since 3.16.0 55803-type SemanticTokensDeltaParams struct { // line 2946 55804- // The text document. 55805- TextDocument TextDocumentIdentifier `json:"textDocument"` 55806- // The result id of a previous response. The result Id can either point to a full response 55807- // or a delta response depending on what was received last. 55808- PreviousResultID string `json:"previousResultId"` 55809- WorkDoneProgressParams 55810- PartialResultParams 55811-} 55812- 55813-// @since 3.16.0 55814-type SemanticTokensDeltaPartialResult struct { // line 3005 55815- Edits []SemanticTokensEdit `json:"edits"` 55816-} 55817- 55818-// @since 3.16.0 55819-type SemanticTokensEdit struct { // line 6617 55820- // The start offset of the edit. 55821- Start uint32 `json:"start"` 55822- // The count of elements to remove. 55823- DeleteCount uint32 `json:"deleteCount"` 55824- // The elements to insert. 55825- Data []uint32 `json:"data,omitempty"` 55826-} 55827- 55828-// @since 3.16.0 55829-type SemanticTokensLegend struct { // line 9314 55830- // The token types a server uses. 55831- TokenTypes []string `json:"tokenTypes"` 55832- // The token modifiers a server uses. 55833- TokenModifiers []string `json:"tokenModifiers"` 55834-} 55835- 55836-// @since 3.16.0 55837-type SemanticTokensOptions struct { // line 6546 55838- // The legend used by the server 55839- Legend SemanticTokensLegend `json:"legend"` 55840- // Server supports providing semantic tokens for a specific range 55841- // of a document. 55842- Range *Or_SemanticTokensOptions_range `json:"range,omitempty"` 55843- // Server supports providing semantic tokens for a full document. 55844- Full *Or_SemanticTokensOptions_full `json:"full,omitempty"` 55845- WorkDoneProgressOptions 55846-} 55847- 55848-// @since 3.16.0 55849-type SemanticTokensParams struct { // line 2855 55850- // The text document. 55851- TextDocument TextDocumentIdentifier `json:"textDocument"` 55852- WorkDoneProgressParams 55853- PartialResultParams 55854-} 55855- 55856-// @since 3.16.0 55857-type SemanticTokensPartialResult struct { // line 2907 55858- Data []uint32 `json:"data"` 55859-} 55860- 55861-// @since 3.16.0 55862-type SemanticTokensRangeParams struct { // line 3022 55863- // The text document. 55864- TextDocument TextDocumentIdentifier `json:"textDocument"` 55865- // The range the semantic tokens are requested for. 55866- Range Range `json:"range"` 55867- WorkDoneProgressParams 55868- PartialResultParams 55869-} 55870- 55871-// @since 3.16.0 55872-type SemanticTokensRegistrationOptions struct { // line 2924 55873- TextDocumentRegistrationOptions 55874- SemanticTokensOptions 55875- StaticRegistrationOptions 55876-} 55877- 55878-// @since 3.16.0 55879-type SemanticTokensWorkspaceClientCapabilities struct { // line 10977 55880- // Whether the client implementation supports a refresh request sent from 55881- // the server to the client. 55882- // 55883- // Note that this event is global and will force the client to refresh all 55884- // semantic tokens currently shown. It should be used with absolute care 55885- // and is useful for situation where a server for example detects a project 55886- // wide change that requires such a calculation. 55887- RefreshSupport bool `json:"refreshSupport,omitempty"` 55888-} 55889- 55890-// Defines the capabilities provided by a language 55891-// server. 55892-type ServerCapabilities struct { // line 7809 55893- // The position encoding the server picked from the encodings offered 55894- // by the client via the client capability `general.positionEncodings`. 55895- // 55896- // If the client didn't provide any position encodings the only valid 55897- // value that a server can return is 'utf-16'. 55898- // 55899- // If omitted it defaults to 'utf-16'. 55900- // 55901- // @since 3.17.0 55902- PositionEncoding *PositionEncodingKind `json:"positionEncoding,omitempty"` 55903- // Defines how text documents are synced. Is either a detailed structure 55904- // defining each notification or for backwards compatibility the 55905- // TextDocumentSyncKind number. 55906- TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` 55907- // Defines how notebook documents are synced. 55908- // 55909- // @since 3.17.0 55910- NotebookDocumentSync *Or_ServerCapabilities_notebookDocumentSync `json:"notebookDocumentSync,omitempty"` 55911- // The server provides completion support. 55912- CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"` 55913- // The server provides hover support. 55914- HoverProvider *Or_ServerCapabilities_hoverProvider `json:"hoverProvider,omitempty"` 55915- // The server provides signature help support. 55916- SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"` 55917- // The server provides Goto Declaration support. 55918- DeclarationProvider *Or_ServerCapabilities_declarationProvider `json:"declarationProvider,omitempty"` 55919- // The server provides goto definition support. 55920- DefinitionProvider *Or_ServerCapabilities_definitionProvider `json:"definitionProvider,omitempty"` 55921- // The server provides Goto Type Definition support. 55922- TypeDefinitionProvider *Or_ServerCapabilities_typeDefinitionProvider `json:"typeDefinitionProvider,omitempty"` 55923- // The server provides Goto Implementation support. 55924- ImplementationProvider *Or_ServerCapabilities_implementationProvider `json:"implementationProvider,omitempty"` 55925- // The server provides find references support. 55926- ReferencesProvider *Or_ServerCapabilities_referencesProvider `json:"referencesProvider,omitempty"` 55927- // The server provides document highlight support. 55928- DocumentHighlightProvider *Or_ServerCapabilities_documentHighlightProvider `json:"documentHighlightProvider,omitempty"` 55929- // The server provides document symbol support. 55930- DocumentSymbolProvider *Or_ServerCapabilities_documentSymbolProvider `json:"documentSymbolProvider,omitempty"` 55931- // The server provides code actions. CodeActionOptions may only be 55932- // specified if the client states that it supports 55933- // `codeActionLiteralSupport` in its initial `initialize` request. 55934- CodeActionProvider interface{} `json:"codeActionProvider,omitempty"` 55935- // The server provides code lens. 55936- CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"` 55937- // The server provides document link support. 55938- DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"` 55939- // The server provides color provider support. 55940- ColorProvider *Or_ServerCapabilities_colorProvider `json:"colorProvider,omitempty"` 55941- // The server provides workspace symbol support. 55942- WorkspaceSymbolProvider *Or_ServerCapabilities_workspaceSymbolProvider `json:"workspaceSymbolProvider,omitempty"` 55943- // The server provides document formatting. 55944- DocumentFormattingProvider *Or_ServerCapabilities_documentFormattingProvider `json:"documentFormattingProvider,omitempty"` 55945- // The server provides document range formatting. 55946- DocumentRangeFormattingProvider *Or_ServerCapabilities_documentRangeFormattingProvider `json:"documentRangeFormattingProvider,omitempty"` 55947- // The server provides document formatting on typing. 55948- DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"` 55949- // The server provides rename support. RenameOptions may only be 55950- // specified if the client states that it supports 55951- // `prepareSupport` in its initial `initialize` request. 55952- RenameProvider interface{} `json:"renameProvider,omitempty"` 55953- // The server provides folding provider support. 55954- FoldingRangeProvider *Or_ServerCapabilities_foldingRangeProvider `json:"foldingRangeProvider,omitempty"` 55955- // The server provides selection range support. 55956- SelectionRangeProvider *Or_ServerCapabilities_selectionRangeProvider `json:"selectionRangeProvider,omitempty"` 55957- // The server provides execute command support. 55958- ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"` 55959- // The server provides call hierarchy support. 55960- // 55961- // @since 3.16.0 55962- CallHierarchyProvider *Or_ServerCapabilities_callHierarchyProvider `json:"callHierarchyProvider,omitempty"` 55963- // The server provides linked editing range support. 55964- // 55965- // @since 3.16.0 55966- LinkedEditingRangeProvider *Or_ServerCapabilities_linkedEditingRangeProvider `json:"linkedEditingRangeProvider,omitempty"` 55967- // The server provides semantic tokens support. 55968- // 55969- // @since 3.16.0 55970- SemanticTokensProvider interface{} `json:"semanticTokensProvider,omitempty"` 55971- // The server provides moniker support. 55972- // 55973- // @since 3.16.0 55974- MonikerProvider *Or_ServerCapabilities_monikerProvider `json:"monikerProvider,omitempty"` 55975- // The server provides type hierarchy support. 55976- // 55977- // @since 3.17.0 55978- TypeHierarchyProvider *Or_ServerCapabilities_typeHierarchyProvider `json:"typeHierarchyProvider,omitempty"` 55979- // The server provides inline values. 55980- // 55981- // @since 3.17.0 55982- InlineValueProvider *Or_ServerCapabilities_inlineValueProvider `json:"inlineValueProvider,omitempty"` 55983- // The server provides inlay hints. 55984- // 55985- // @since 3.17.0 55986- InlayHintProvider interface{} `json:"inlayHintProvider,omitempty"` 55987- // The server has support for pull model diagnostics. 55988- // 55989- // @since 3.17.0 55990- DiagnosticProvider *Or_ServerCapabilities_diagnosticProvider `json:"diagnosticProvider,omitempty"` 55991- // Workspace specific server capabilities. 55992- Workspace *Workspace6Gn `json:"workspace,omitempty"` 55993- // Experimental server capabilities. 55994- Experimental interface{} `json:"experimental,omitempty"` 55995-} 55996-type SetTraceParams struct { // line 6147 55997- Value TraceValues `json:"value"` 55998-} 55999- 56000-// Client capabilities for the showDocument request. 56001-// 56002-// @since 3.16.0 56003-type ShowDocumentClientCapabilities struct { // line 12485 56004- // The client has support for the showDocument 56005- // request. 56006- Support bool `json:"support"` 56007-} 56008- 56009-// Params to show a document. 56010-// 56011-// @since 3.16.0 56012-type ShowDocumentParams struct { // line 3055 56013- // The document uri to show. 56014- URI URI `json:"uri"` 56015- // Indicates to show the resource in an external program. 56016- // To show for example `https://code.visualstudio.com/` 56017- // in the default WEB browser set `external` to `true`. 56018- External bool `json:"external,omitempty"` 56019- // An optional property to indicate whether the editor 56020- // showing the document should take focus or not. 56021- // Clients might ignore this property if an external 56022- // program is started. 56023- TakeFocus bool `json:"takeFocus,omitempty"` 56024- // An optional selection range if the document is a text 56025- // document. Clients might ignore the property if an 56026- // external program is started or the file is not a text 56027- // file. 56028- Selection *Range `json:"selection,omitempty"` 56029-} 56030- 56031-// The result of a showDocument request. 56032-// 56033-// @since 3.16.0 56034-type ShowDocumentResult struct { // line 3097 56035- // A boolean indicating if the show was successful. 56036- Success bool `json:"success"` 56037-} 56038- 56039-// The parameters of a notification message. 56040-type ShowMessageParams struct { // line 4183 56041- // The message type. See {@link MessageType} 56042- Type MessageType `json:"type"` 56043- // The actual message. 56044- Message string `json:"message"` 56045-} 56046- 56047-// Show message request client capabilities 56048-type ShowMessageRequestClientCapabilities struct { // line 12458 56049- // Capabilities specific to the `MessageActionItem` type. 56050- MessageActionItem *PMessageActionItemPShowMessage `json:"messageActionItem,omitempty"` 56051-} 56052-type ShowMessageRequestParams struct { // line 4205 56053- // The message type. See {@link MessageType} 56054- Type MessageType `json:"type"` 56055- // The actual message. 56056- Message string `json:"message"` 56057- // The message action items to present. 56058- Actions []MessageActionItem `json:"actions,omitempty"` 56059-} 56060- 56061-// Signature help represents the signature of something 56062-// callable. There can be multiple signature but only one 56063-// active and only one active parameter. 56064-type SignatureHelp struct { // line 4968 56065- // One or more signatures. 56066- Signatures []SignatureInformation `json:"signatures"` 56067- // The active signature. If omitted or the value lies outside the 56068- // range of `signatures` the value defaults to zero or is ignored if 56069- // the `SignatureHelp` has no signatures. 56070- // 56071- // Whenever possible implementors should make an active decision about 56072- // the active signature and shouldn't rely on a default value. 56073- // 56074- // In future version of the protocol this property might become 56075- // mandatory to better express this. 56076- ActiveSignature uint32 `json:"activeSignature,omitempty"` 56077- // The active parameter of the active signature. If omitted or the value 56078- // lies outside the range of `signatures[activeSignature].parameters` 56079- // defaults to 0 if the active signature has parameters. If 56080- // the active signature has no parameters it is ignored. 56081- // In future version of the protocol this property might become 56082- // mandatory to better express the active parameter if the 56083- // active signature does have any. 56084- ActiveParameter uint32 `json:"activeParameter,omitempty"` 56085-} 56086- 56087-// Client Capabilities for a {@link SignatureHelpRequest}. 56088-type SignatureHelpClientCapabilities struct { // line 11428 56089- // Whether signature help supports dynamic registration. 56090- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 56091- // The client supports the following `SignatureInformation` 56092- // specific properties. 56093- SignatureInformation *PSignatureInformationPSignatureHelp `json:"signatureInformation,omitempty"` 56094- // The client supports to send additional context information for a 56095- // `textDocument/signatureHelp` request. A client that opts into 56096- // contextSupport will also support the `retriggerCharacters` on 56097- // `SignatureHelpOptions`. 56098- // 56099- // @since 3.15.0 56100- ContextSupport bool `json:"contextSupport,omitempty"` 56101-} 56102- 56103-// Additional information about the context in which a signature help request was triggered. 56104-// 56105-// @since 3.15.0 56106-type SignatureHelpContext struct { // line 8787 56107- // Action that caused signature help to be triggered. 56108- TriggerKind SignatureHelpTriggerKind `json:"triggerKind"` 56109- // Character that caused signature help to be triggered. 56110- // 56111- // This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` 56112- TriggerCharacter string `json:"triggerCharacter,omitempty"` 56113- // `true` if signature help was already showing when it was triggered. 56114- // 56115- // Retriggers occurs when the signature help is already active and can be caused by actions such as 56116- // typing a trigger character, a cursor move, or document content changes. 56117- IsRetrigger bool `json:"isRetrigger"` 56118- // The currently active `SignatureHelp`. 56119- // 56120- // The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on 56121- // the user navigating through available signatures. 56122- ActiveSignatureHelp *SignatureHelp `json:"activeSignatureHelp,omitempty"` 56123-} 56124- 56125-// Server Capabilities for a {@link SignatureHelpRequest}. 56126-type SignatureHelpOptions struct { // line 8882 56127- // List of characters that trigger signature help automatically. 56128- TriggerCharacters []string `json:"triggerCharacters,omitempty"` 56129- // List of characters that re-trigger signature help. 56130- // 56131- // These trigger characters are only active when signature help is already showing. All trigger characters 56132- // are also counted as re-trigger characters. 56133- // 56134- // @since 3.15.0 56135- RetriggerCharacters []string `json:"retriggerCharacters,omitempty"` 56136- WorkDoneProgressOptions 56137-} 56138- 56139-// Parameters for a {@link SignatureHelpRequest}. 56140-type SignatureHelpParams struct { // line 4940 56141- // The signature help context. This is only available if the client specifies 56142- // to send this using the client capability `textDocument.signatureHelp.contextSupport === true` 56143- // 56144- // @since 3.15.0 56145- Context *SignatureHelpContext `json:"context,omitempty"` 56146- TextDocumentPositionParams 56147- WorkDoneProgressParams 56148-} 56149- 56150-// Registration options for a {@link SignatureHelpRequest}. 56151-type SignatureHelpRegistrationOptions struct { // line 5003 56152- TextDocumentRegistrationOptions 56153- SignatureHelpOptions 56154-} 56155- 56156-// How a signature help was triggered. 56157-// 56158-// @since 3.15.0 56159-type SignatureHelpTriggerKind uint32 // line 13580 56160-// Represents the signature of something callable. A signature 56161-// can have a label, like a function-name, a doc-comment, and 56162-// a set of parameters. 56163-type SignatureInformation struct { // line 8828 56164- // The label of this signature. Will be shown in 56165- // the UI. 56166- Label string `json:"label"` 56167- // The human-readable doc-comment of this signature. Will be shown 56168- // in the UI but can be omitted. 56169- Documentation *Or_SignatureInformation_documentation `json:"documentation,omitempty"` 56170- // The parameters of this signature. 56171- Parameters []ParameterInformation `json:"parameters,omitempty"` 56172- // The index of the active parameter. 56173- // 56174- // If provided, this is used in place of `SignatureHelp.activeParameter`. 56175- // 56176- // @since 3.16.0 56177- ActiveParameter uint32 `json:"activeParameter,omitempty"` 56178-} 56179- 56180-// Static registration options to be returned in the initialize 56181-// request. 56182-type StaticRegistrationOptions struct { // line 6343 56183- // The id used to register the request. The id can be used to deregister 56184- // the request again. See also Registration#id. 56185- ID string `json:"id,omitempty"` 56186-} 56187- 56188-// Represents information about programming constructs like variables, classes, 56189-// interfaces etc. 56190-type SymbolInformation struct { // line 5181 56191- // extends BaseSymbolInformation 56192- // Indicates if this symbol is deprecated. 56193- // 56194- // @deprecated Use tags instead 56195- Deprecated bool `json:"deprecated,omitempty"` 56196- // The location of this symbol. The location's range is used by a tool 56197- // to reveal the location in the editor. If the symbol is selected in the 56198- // tool the range's start information is used to position the cursor. So 56199- // the range usually spans more than the actual symbol's name and does 56200- // normally include things like visibility modifiers. 56201- // 56202- // The range doesn't have to denote a node range in the sense of an abstract 56203- // syntax tree. It can therefore not be used to re-construct a hierarchy of 56204- // the symbols. 56205- Location Location `json:"location"` 56206- // The name of this symbol. 56207- Name string `json:"name"` 56208- // The kind of this symbol. 56209- Kind SymbolKind `json:"kind"` 56210- // Tags for this symbol. 56211- // 56212- // @since 3.16.0 56213- Tags []SymbolTag `json:"tags,omitempty"` 56214- // The name of the symbol containing this symbol. This information is for 56215- // user interface purposes (e.g. to render a qualifier in the user interface 56216- // if necessary). It can't be used to re-infer a hierarchy for the document 56217- // symbols. 56218- ContainerName string `json:"containerName,omitempty"` 56219-} 56220- 56221-// A symbol kind. 56222-type SymbolKind uint32 // line 12841 56223-// Symbol tags are extra annotations that tweak the rendering of a symbol. 56224-// 56225-// @since 3.16 56226-type SymbolTag uint32 // line 12955 56227-// Describe options to be used when registered for text document change events. 56228-type TextDocumentChangeRegistrationOptions struct { // line 4312 56229- // How documents are synced to the server. 56230- SyncKind TextDocumentSyncKind `json:"syncKind"` 56231- TextDocumentRegistrationOptions 56232-} 56233- 56234-// Text document specific client capabilities. 56235-type TextDocumentClientCapabilities struct { // line 10323 56236- // Defines which synchronization capabilities the client supports. 56237- Synchronization *TextDocumentSyncClientCapabilities `json:"synchronization,omitempty"` 56238- // Capabilities specific to the `textDocument/completion` request. 56239- Completion CompletionClientCapabilities `json:"completion,omitempty"` 56240- // Capabilities specific to the `textDocument/hover` request. 56241- Hover *HoverClientCapabilities `json:"hover,omitempty"` 56242- // Capabilities specific to the `textDocument/signatureHelp` request. 56243- SignatureHelp *SignatureHelpClientCapabilities `json:"signatureHelp,omitempty"` 56244- // Capabilities specific to the `textDocument/declaration` request. 56245- // 56246- // @since 3.14.0 56247- Declaration *DeclarationClientCapabilities `json:"declaration,omitempty"` 56248- // Capabilities specific to the `textDocument/definition` request. 56249- Definition *DefinitionClientCapabilities `json:"definition,omitempty"` 56250- // Capabilities specific to the `textDocument/typeDefinition` request. 56251- // 56252- // @since 3.6.0 56253- TypeDefinition *TypeDefinitionClientCapabilities `json:"typeDefinition,omitempty"` 56254- // Capabilities specific to the `textDocument/implementation` request. 56255- // 56256- // @since 3.6.0 56257- Implementation *ImplementationClientCapabilities `json:"implementation,omitempty"` 56258- // Capabilities specific to the `textDocument/references` request. 56259- References *ReferenceClientCapabilities `json:"references,omitempty"` 56260- // Capabilities specific to the `textDocument/documentHighlight` request. 56261- DocumentHighlight *DocumentHighlightClientCapabilities `json:"documentHighlight,omitempty"` 56262- // Capabilities specific to the `textDocument/documentSymbol` request. 56263- DocumentSymbol DocumentSymbolClientCapabilities `json:"documentSymbol,omitempty"` 56264- // Capabilities specific to the `textDocument/codeAction` request. 56265- CodeAction CodeActionClientCapabilities `json:"codeAction,omitempty"` 56266- // Capabilities specific to the `textDocument/codeLens` request. 56267- CodeLens *CodeLensClientCapabilities `json:"codeLens,omitempty"` 56268- // Capabilities specific to the `textDocument/documentLink` request. 56269- DocumentLink *DocumentLinkClientCapabilities `json:"documentLink,omitempty"` 56270- // Capabilities specific to the `textDocument/documentColor` and the 56271- // `textDocument/colorPresentation` request. 56272- // 56273- // @since 3.6.0 56274- ColorProvider *DocumentColorClientCapabilities `json:"colorProvider,omitempty"` 56275- // Capabilities specific to the `textDocument/formatting` request. 56276- Formatting *DocumentFormattingClientCapabilities `json:"formatting,omitempty"` 56277- // Capabilities specific to the `textDocument/rangeFormatting` request. 56278- RangeFormatting *DocumentRangeFormattingClientCapabilities `json:"rangeFormatting,omitempty"` 56279- // Capabilities specific to the `textDocument/onTypeFormatting` request. 56280- OnTypeFormatting *DocumentOnTypeFormattingClientCapabilities `json:"onTypeFormatting,omitempty"` 56281- // Capabilities specific to the `textDocument/rename` request. 56282- Rename *RenameClientCapabilities `json:"rename,omitempty"` 56283- // Capabilities specific to the `textDocument/foldingRange` request. 56284- // 56285- // @since 3.10.0 56286- FoldingRange *FoldingRangeClientCapabilities `json:"foldingRange,omitempty"` 56287- // Capabilities specific to the `textDocument/selectionRange` request. 56288- // 56289- // @since 3.15.0 56290- SelectionRange *SelectionRangeClientCapabilities `json:"selectionRange,omitempty"` 56291- // Capabilities specific to the `textDocument/publishDiagnostics` notification. 56292- PublishDiagnostics PublishDiagnosticsClientCapabilities `json:"publishDiagnostics,omitempty"` 56293- // Capabilities specific to the various call hierarchy requests. 56294- // 56295- // @since 3.16.0 56296- CallHierarchy *CallHierarchyClientCapabilities `json:"callHierarchy,omitempty"` 56297- // Capabilities specific to the various semantic token request. 56298- // 56299- // @since 3.16.0 56300- SemanticTokens SemanticTokensClientCapabilities `json:"semanticTokens,omitempty"` 56301- // Capabilities specific to the `textDocument/linkedEditingRange` request. 56302- // 56303- // @since 3.16.0 56304- LinkedEditingRange *LinkedEditingRangeClientCapabilities `json:"linkedEditingRange,omitempty"` 56305- // Client capabilities specific to the `textDocument/moniker` request. 56306- // 56307- // @since 3.16.0 56308- Moniker *MonikerClientCapabilities `json:"moniker,omitempty"` 56309- // Capabilities specific to the various type hierarchy requests. 56310- // 56311- // @since 3.17.0 56312- TypeHierarchy *TypeHierarchyClientCapabilities `json:"typeHierarchy,omitempty"` 56313- // Capabilities specific to the `textDocument/inlineValue` request. 56314- // 56315- // @since 3.17.0 56316- InlineValue *InlineValueClientCapabilities `json:"inlineValue,omitempty"` 56317- // Capabilities specific to the `textDocument/inlayHint` request. 56318- // 56319- // @since 3.17.0 56320- InlayHint *InlayHintClientCapabilities `json:"inlayHint,omitempty"` 56321- // Capabilities specific to the diagnostic pull model. 56322- // 56323- // @since 3.17.0 56324- Diagnostic *DiagnosticClientCapabilities `json:"diagnostic,omitempty"` 56325-} 56326- 56327-// An event describing a change to a text document. If only a text is provided 56328-// it is considered to be the full content of the document. 56329-type TextDocumentContentChangeEvent = Msg_TextDocumentContentChangeEvent // (alias) line 14002 56330-// Describes textual changes on a text document. A TextDocumentEdit describes all changes 56331-// on a document version Si and after they are applied move the document to version Si+1. 56332-// So the creator of a TextDocumentEdit doesn't need to sort the array of edits or do any 56333-// kind of ordering. However the edits must be non overlapping. 56334-type TextDocumentEdit struct { // line 6677 56335- // The text document to change. 56336- TextDocument OptionalVersionedTextDocumentIdentifier `json:"textDocument"` 56337- // The edits to be applied. 56338- // 56339- // @since 3.16.0 - support for AnnotatedTextEdit. This is guarded using a 56340- // client capability. 56341- Edits []TextEdit `json:"edits"` 56342-} 56343- 56344-// A document filter denotes a document by different properties like 56345-// the {@link TextDocument.languageId language}, the {@link Uri.scheme scheme} of 56346-// its resource, or a glob-pattern that is applied to the {@link TextDocument.fileName path}. 56347-// 56348-// Glob patterns can have the following syntax: 56349-// 56350-// - `*` to match one or more characters in a path segment 56351-// - `?` to match on one character in a path segment 56352-// - `**` to match any number of path segments, including none 56353-// - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) 56354-// - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) 56355-// - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) 56356-// 56357-// @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` 56358-// @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` 56359-// 56360-// @since 3.17.0 56361-type TextDocumentFilter = Msg_TextDocumentFilter // (alias) line 14145 56362-// A literal to identify a text document in the client. 56363-type TextDocumentIdentifier struct { // line 6419 56364- // The text document's uri. 56365- URI DocumentURI `json:"uri"` 56366-} 56367- 56368-// An item to transfer a text document from the client to the 56369-// server. 56370-type TextDocumentItem struct { // line 7405 56371- // The text document's uri. 56372- URI DocumentURI `json:"uri"` 56373- // The text document's language identifier. 56374- LanguageID string `json:"languageId"` 56375- // The version number of this document (it will increase after each 56376- // change, including undo/redo). 56377- Version int32 `json:"version"` 56378- // The content of the opened text document. 56379- Text string `json:"text"` 56380-} 56381- 56382-// A parameter literal used in requests to pass a text document and a position inside that 56383-// document. 56384-type TextDocumentPositionParams struct { // line 6222 56385- // The text document. 56386- TextDocument TextDocumentIdentifier `json:"textDocument"` 56387- // The position inside the text document. 56388- Position Position `json:"position"` 56389-} 56390- 56391-// General text document registration options. 56392-type TextDocumentRegistrationOptions struct { // line 2368 56393- // A document selector to identify the scope of the registration. If set to null 56394- // the document selector provided on the client side will be used. 56395- DocumentSelector DocumentSelector `json:"documentSelector"` 56396-} 56397- 56398-// Represents reasons why a text document is saved. 56399-type TextDocumentSaveReason uint32 // line 13109 56400-// Save registration options. 56401-type TextDocumentSaveRegistrationOptions struct { // line 4369 56402- TextDocumentRegistrationOptions 56403- SaveOptions 56404-} 56405-type TextDocumentSyncClientCapabilities struct { // line 11127 56406- // Whether text document synchronization supports dynamic registration. 56407- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 56408- // The client supports sending will save notifications. 56409- WillSave bool `json:"willSave,omitempty"` 56410- // The client supports sending a will save request and 56411- // waits for a response providing text edits which will 56412- // be applied to the document before it is saved. 56413- WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` 56414- // The client supports did save notifications. 56415- DidSave bool `json:"didSave,omitempty"` 56416-} 56417- 56418-// Defines how the host (editor) should sync 56419-// document changes to the language server. 56420-type TextDocumentSyncKind uint32 // line 13084 56421-type TextDocumentSyncOptions struct { // line 9736 56422- // Open and close notifications are sent to the server. If omitted open close notification should not 56423- // be sent. 56424- OpenClose bool `json:"openClose,omitempty"` 56425- // Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full 56426- // and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None. 56427- Change TextDocumentSyncKind `json:"change,omitempty"` 56428- // If present will save notifications are sent to the server. If omitted the notification should not be 56429- // sent. 56430- WillSave bool `json:"willSave,omitempty"` 56431- // If present will save wait until requests are sent to the server. If omitted the request should not be 56432- // sent. 56433- WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` 56434- // If present save notifications are sent to the server. If omitted the notification should not be 56435- // sent. 56436- Save *SaveOptions `json:"save,omitempty"` 56437-} 56438- 56439-// A text edit applicable to a text document. 56440-type TextEdit struct { // line 4406 56441- // The range of the text document to be manipulated. To insert 56442- // text into a document create a range where start === end. 56443- Range Range `json:"range"` 56444- // The string to be inserted. For delete operations use an 56445- // empty string. 56446- NewText string `json:"newText"` 56447-} 56448-type TokenFormat string // line 13736 56449-type TraceValues string // line 13383 56450-// Since 3.6.0 56451-type TypeDefinitionClientCapabilities struct { // line 11559 56452- // Whether implementation supports dynamic registration. If this is set to `true` 56453- // the client supports the new `TypeDefinitionRegistrationOptions` return value 56454- // for the corresponding server capability as well. 56455- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 56456- // The client supports additional metadata in the form of definition links. 56457- // 56458- // Since 3.14.0 56459- LinkSupport bool `json:"linkSupport,omitempty"` 56460-} 56461-type TypeDefinitionOptions struct { // line 6358 56462- WorkDoneProgressOptions 56463-} 56464-type TypeDefinitionParams struct { // line 2123 56465- TextDocumentPositionParams 56466- WorkDoneProgressParams 56467- PartialResultParams 56468-} 56469-type TypeDefinitionRegistrationOptions struct { // line 2143 56470- TextDocumentRegistrationOptions 56471- TypeDefinitionOptions 56472- StaticRegistrationOptions 56473-} 56474- 56475-// @since 3.17.0 56476-type TypeHierarchyClientCapabilities struct { // line 12337 56477- // Whether implementation supports dynamic registration. If this is set to `true` 56478- // the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` 56479- // return value for the corresponding server capability as well. 56480- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 56481-} 56482- 56483-// @since 3.17.0 56484-type TypeHierarchyItem struct { // line 3410 56485- // The name of this item. 56486- Name string `json:"name"` 56487- // The kind of this item. 56488- Kind SymbolKind `json:"kind"` 56489- // Tags for this item. 56490- Tags []SymbolTag `json:"tags,omitempty"` 56491- // More detail for this item, e.g. the signature of a function. 56492- Detail string `json:"detail,omitempty"` 56493- // The resource identifier of this item. 56494- URI DocumentURI `json:"uri"` 56495- // The range enclosing this symbol not including leading/trailing whitespace 56496- // but everything else, e.g. comments and code. 56497- Range Range `json:"range"` 56498- // The range that should be selected and revealed when this symbol is being 56499- // picked, e.g. the name of a function. Must be contained by the 56500- // {@link TypeHierarchyItem.range `range`}. 56501- SelectionRange Range `json:"selectionRange"` 56502- // A data entry field that is preserved between a type hierarchy prepare and 56503- // supertypes or subtypes requests. It could also be used to identify the 56504- // type hierarchy in the server, helping improve the performance on 56505- // resolving supertypes and subtypes. 56506- Data interface{} `json:"data,omitempty"` 56507-} 56508- 56509-// Type hierarchy options used during static registration. 56510-// 56511-// @since 3.17.0 56512-type TypeHierarchyOptions struct { // line 6936 56513- WorkDoneProgressOptions 56514-} 56515- 56516-// The parameter of a `textDocument/prepareTypeHierarchy` request. 56517-// 56518-// @since 3.17.0 56519-type TypeHierarchyPrepareParams struct { // line 3392 56520- TextDocumentPositionParams 56521- WorkDoneProgressParams 56522-} 56523- 56524-// Type hierarchy options used during static or dynamic registration. 56525-// 56526-// @since 3.17.0 56527-type TypeHierarchyRegistrationOptions struct { // line 3487 56528- TextDocumentRegistrationOptions 56529- TypeHierarchyOptions 56530- StaticRegistrationOptions 56531-} 56532- 56533-// The parameter of a `typeHierarchy/subtypes` request. 56534-// 56535-// @since 3.17.0 56536-type TypeHierarchySubtypesParams struct { // line 3533 56537- Item TypeHierarchyItem `json:"item"` 56538- WorkDoneProgressParams 56539- PartialResultParams 56540-} 56541- 56542-// The parameter of a `typeHierarchy/supertypes` request. 56543-// 56544-// @since 3.17.0 56545-type TypeHierarchySupertypesParams struct { // line 3509 56546- Item TypeHierarchyItem `json:"item"` 56547- WorkDoneProgressParams 56548- PartialResultParams 56549-} 56550- 56551-// created for Tuple 56552-type UIntCommaUInt struct { // line 10076 56553- Fld0 uint32 `json:"fld0"` 56554- Fld1 uint32 `json:"fld1"` 56555-} 56556-type URI = string 56557- 56558-// A diagnostic report indicating that the last returned 56559-// report is still accurate. 56560-// 56561-// @since 3.17.0 56562-type UnchangedDocumentDiagnosticReport struct { // line 7270 56563- // A document diagnostic report indicating 56564- // no changes to the last result. A server can 56565- // only return `unchanged` if result ids are 56566- // provided. 56567- Kind string `json:"kind"` 56568- // A result id which will be sent on the next 56569- // diagnostic request for the same document. 56570- ResultID string `json:"resultId"` 56571-} 56572- 56573-// Moniker uniqueness level to define scope of the moniker. 56574-// 56575-// @since 3.16.0 56576-type UniquenessLevel string // line 12971 56577-// General parameters to unregister a request or notification. 56578-type Unregistration struct { // line 7628 56579- // The id used to unregister the request or notification. Usually an id 56580- // provided during the register request. 56581- ID string `json:"id"` 56582- // The method to unregister for. 56583- Method string `json:"method"` 56584-} 56585-type UnregistrationParams struct { // line 4053 56586- Unregisterations []Unregistration `json:"unregisterations"` 56587-} 56588- 56589-// A versioned notebook document identifier. 56590-// 56591-// @since 3.17.0 56592-type VersionedNotebookDocumentIdentifier struct { // line 7443 56593- // The version number of this notebook document. 56594- Version int32 `json:"version"` 56595- // The notebook document's uri. 56596- URI URI `json:"uri"` 56597-} 56598- 56599-// A text document identifier to denote a specific version of a text document. 56600-type VersionedTextDocumentIdentifier struct { // line 8445 56601- // The version number of this document. 56602- Version int32 `json:"version"` 56603- TextDocumentIdentifier 56604-} 56605-type WatchKind = uint32 // line 13505// The parameters sent in a will save text document notification. 56606-type WillSaveTextDocumentParams struct { // line 4384 56607- // The document that will be saved. 56608- TextDocument TextDocumentIdentifier `json:"textDocument"` 56609- // The 'TextDocumentSaveReason'. 56610- Reason TextDocumentSaveReason `json:"reason"` 56611-} 56612-type WindowClientCapabilities struct { // line 10629 56613- // It indicates whether the client supports server initiated 56614- // progress using the `window/workDoneProgress/create` request. 56615- // 56616- // The capability also controls Whether client supports handling 56617- // of progress notifications. If set servers are allowed to report a 56618- // `workDoneProgress` property in the request specific server 56619- // capabilities. 56620- // 56621- // @since 3.15.0 56622- WorkDoneProgress bool `json:"workDoneProgress,omitempty"` 56623- // Capabilities specific to the showMessage request. 56624- // 56625- // @since 3.16.0 56626- ShowMessage *ShowMessageRequestClientCapabilities `json:"showMessage,omitempty"` 56627- // Capabilities specific to the showDocument request. 56628- // 56629- // @since 3.16.0 56630- ShowDocument *ShowDocumentClientCapabilities `json:"showDocument,omitempty"` 56631-} 56632-type WorkDoneProgressBegin struct { // line 6040 56633- Kind string `json:"kind"` 56634- // Mandatory title of the progress operation. Used to briefly inform about 56635- // the kind of operation being performed. 56636- // 56637- // Examples: "Indexing" or "Linking dependencies". 56638- Title string `json:"title"` 56639- // Controls if a cancel button should show to allow the user to cancel the 56640- // long running operation. Clients that don't support cancellation are allowed 56641- // to ignore the setting. 56642- Cancellable bool `json:"cancellable,omitempty"` 56643- // Optional, more detailed associated progress message. Contains 56644- // complementary information to the `title`. 56645- // 56646- // Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". 56647- // If unset, the previous progress message (if any) is still valid. 56648- Message string `json:"message,omitempty"` 56649- // Optional progress percentage to display (value 100 is considered 100%). 56650- // If not provided infinite progress is assumed and clients are allowed 56651- // to ignore the `percentage` value in subsequent in report notifications. 56652- // 56653- // The value should be steadily rising. Clients are free to ignore values 56654- // that are not following this rule. The value range is [0, 100]. 56655- Percentage uint32 `json:"percentage,omitempty"` 56656-} 56657-type WorkDoneProgressCancelParams struct { // line 2625 56658- // The token to be used to report progress. 56659- Token ProgressToken `json:"token"` 56660-} 56661-type WorkDoneProgressCreateParams struct { // line 2612 56662- // The token to be used to report progress. 56663- Token ProgressToken `json:"token"` 56664-} 56665-type WorkDoneProgressEnd struct { // line 6126 56666- Kind string `json:"kind"` 56667- // Optional, a final message indicating to for example indicate the outcome 56668- // of the operation. 56669- Message string `json:"message,omitempty"` 56670-} 56671-type WorkDoneProgressOptions struct { // line 2355 56672- WorkDoneProgress bool `json:"workDoneProgress,omitempty"` 56673-} 56674- 56675-// created for And 56676-type WorkDoneProgressOptionsAndTextDocumentRegistrationOptions struct { // line 196 56677- WorkDoneProgressOptions 56678- TextDocumentRegistrationOptions 56679-} 56680-type WorkDoneProgressParams struct { // line 6244 56681- // An optional token that a server can use to report work done progress. 56682- WorkDoneToken ProgressToken `json:"workDoneToken,omitempty"` 56683-} 56684-type WorkDoneProgressReport struct { // line 6087 56685- Kind string `json:"kind"` 56686- // Controls enablement state of a cancel button. 56687- // 56688- // Clients that don't support cancellation or don't support controlling the button's 56689- // enablement state are allowed to ignore the property. 56690- Cancellable bool `json:"cancellable,omitempty"` 56691- // Optional, more detailed associated progress message. Contains 56692- // complementary information to the `title`. 56693- // 56694- // Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". 56695- // If unset, the previous progress message (if any) is still valid. 56696- Message string `json:"message,omitempty"` 56697- // Optional progress percentage to display (value 100 is considered 100%). 56698- // If not provided infinite progress is assumed and clients are allowed 56699- // to ignore the `percentage` value in subsequent in report notifications. 56700- // 56701- // The value should be steadily rising. Clients are free to ignore values 56702- // that are not following this rule. The value range is [0, 100] 56703- Percentage uint32 `json:"percentage,omitempty"` 56704-} 56705- 56706-// created for Literal (Lit_ServerCapabilities_workspace) 56707-type Workspace6Gn struct { // line 8404 56708- // The server supports workspace folder. 56709- // 56710- // @since 3.6.0 56711- WorkspaceFolders *WorkspaceFolders5Gn `json:"workspaceFolders,omitempty"` 56712- // The server is interested in notifications/requests for operations on files. 56713- // 56714- // @since 3.16.0 56715- FileOperations *FileOperationOptions `json:"fileOperations,omitempty"` 56716-} 56717- 56718-// Workspace specific client capabilities. 56719-type WorkspaceClientCapabilities struct { // line 10184 56720- // The client supports applying batch edits 56721- // to the workspace by supporting the request 56722- // 'workspace/applyEdit' 56723- ApplyEdit bool `json:"applyEdit,omitempty"` 56724- // Capabilities specific to `WorkspaceEdit`s. 56725- WorkspaceEdit *WorkspaceEditClientCapabilities `json:"workspaceEdit,omitempty"` 56726- // Capabilities specific to the `workspace/didChangeConfiguration` notification. 56727- DidChangeConfiguration DidChangeConfigurationClientCapabilities `json:"didChangeConfiguration,omitempty"` 56728- // Capabilities specific to the `workspace/didChangeWatchedFiles` notification. 56729- DidChangeWatchedFiles DidChangeWatchedFilesClientCapabilities `json:"didChangeWatchedFiles,omitempty"` 56730- // Capabilities specific to the `workspace/symbol` request. 56731- Symbol *WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"` 56732- // Capabilities specific to the `workspace/executeCommand` request. 56733- ExecuteCommand *ExecuteCommandClientCapabilities `json:"executeCommand,omitempty"` 56734- // The client has support for workspace folders. 56735- // 56736- // @since 3.6.0 56737- WorkspaceFolders bool `json:"workspaceFolders,omitempty"` 56738- // The client supports `workspace/configuration` requests. 56739- // 56740- // @since 3.6.0 56741- Configuration bool `json:"configuration,omitempty"` 56742- // Capabilities specific to the semantic token requests scoped to the 56743- // workspace. 56744- // 56745- // @since 3.16.0. 56746- SemanticTokens *SemanticTokensWorkspaceClientCapabilities `json:"semanticTokens,omitempty"` 56747- // Capabilities specific to the code lens requests scoped to the 56748- // workspace. 56749- // 56750- // @since 3.16.0. 56751- CodeLens *CodeLensWorkspaceClientCapabilities `json:"codeLens,omitempty"` 56752- // The client has support for file notifications/requests for user operations on files. 56753- // 56754- // Since 3.16.0 56755- FileOperations *FileOperationClientCapabilities `json:"fileOperations,omitempty"` 56756- // Capabilities specific to the inline values requests scoped to the 56757- // workspace. 56758- // 56759- // @since 3.17.0. 56760- InlineValue *InlineValueWorkspaceClientCapabilities `json:"inlineValue,omitempty"` 56761- // Capabilities specific to the inlay hint requests scoped to the 56762- // workspace. 56763- // 56764- // @since 3.17.0. 56765- InlayHint *InlayHintWorkspaceClientCapabilities `json:"inlayHint,omitempty"` 56766- // Capabilities specific to the diagnostic requests scoped to the 56767- // workspace. 56768- // 56769- // @since 3.17.0. 56770- Diagnostics *DiagnosticWorkspaceClientCapabilities `json:"diagnostics,omitempty"` 56771-} 56772- 56773-// Parameters of the workspace diagnostic request. 56774-// 56775-// @since 3.17.0 56776-type WorkspaceDiagnosticParams struct { // line 3877 56777- // The additional identifier provided during registration. 56778- Identifier string `json:"identifier,omitempty"` 56779- // The currently known diagnostic reports with their 56780- // previous result ids. 56781- PreviousResultIds []PreviousResultID `json:"previousResultIds"` 56782- WorkDoneProgressParams 56783- PartialResultParams 56784-} 56785- 56786-// A workspace diagnostic report. 56787-// 56788-// @since 3.17.0 56789-type WorkspaceDiagnosticReport struct { // line 3914 56790- Items []WorkspaceDocumentDiagnosticReport `json:"items"` 56791-} 56792- 56793-// A partial result for a workspace diagnostic report. 56794-// 56795-// @since 3.17.0 56796-type WorkspaceDiagnosticReportPartialResult struct { // line 3931 56797- Items []WorkspaceDocumentDiagnosticReport `json:"items"` 56798-} 56799- 56800-// A workspace diagnostic document report. 56801-// 56802-// @since 3.17.0 56803-type WorkspaceDocumentDiagnosticReport = Or_WorkspaceDocumentDiagnosticReport // (alias) line 13984 56804-// A workspace edit represents changes to many resources managed in the workspace. The edit 56805-// should either provide `changes` or `documentChanges`. If documentChanges are present 56806-// they are preferred over `changes` if the client can handle versioned document edits. 56807-// 56808-// Since version 3.13.0 a workspace edit can contain resource operations as well. If resource 56809-// operations are present clients need to execute the operations in the order in which they 56810-// are provided. So a workspace edit for example can consist of the following two changes: 56811-// (1) a create file a.txt and (2) a text document edit which insert text into file a.txt. 56812-// 56813-// An invalid sequence (e.g. (1) delete file a.txt and (2) insert text into file a.txt) will 56814-// cause failure of the operation. How the client recovers from the failure is described by 56815-// the client capability: `workspace.workspaceEdit.failureHandling` 56816-type WorkspaceEdit struct { // line 3193 56817- // Holds changes to existing resources. 56818- Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"` 56819- // Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes 56820- // are either an array of `TextDocumentEdit`s to express changes to n different text documents 56821- // where each text document edit addresses a specific version of a text document. Or it can contain 56822- // above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. 56823- // 56824- // Whether a client supports versioned document edits is expressed via 56825- // `workspace.workspaceEdit.documentChanges` client capability. 56826- // 56827- // If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then 56828- // only plain `TextEdit`s using the `changes` property are supported. 56829- DocumentChanges []DocumentChanges `json:"documentChanges,omitempty"` 56830- // A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and 56831- // delete file / folder operations. 56832- // 56833- // Whether clients honor this property depends on the client capability `workspace.changeAnnotationSupport`. 56834- // 56835- // @since 3.16.0 56836- ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations,omitempty"` 56837-} 56838-type WorkspaceEditClientCapabilities struct { // line 10768 56839- // The client supports versioned document changes in `WorkspaceEdit`s 56840- DocumentChanges bool `json:"documentChanges,omitempty"` 56841- // The resource operations the client supports. Clients should at least 56842- // support 'create', 'rename' and 'delete' files and folders. 56843- // 56844- // @since 3.13.0 56845- ResourceOperations []ResourceOperationKind `json:"resourceOperations,omitempty"` 56846- // The failure handling strategy of a client if applying the workspace edit 56847- // fails. 56848- // 56849- // @since 3.13.0 56850- FailureHandling *FailureHandlingKind `json:"failureHandling,omitempty"` 56851- // Whether the client normalizes line endings to the client specific 56852- // setting. 56853- // If set to `true` the client will normalize line ending characters 56854- // in a workspace edit to the client-specified new line 56855- // character. 56856- // 56857- // @since 3.16.0 56858- NormalizesLineEndings bool `json:"normalizesLineEndings,omitempty"` 56859- // Whether the client in general supports change annotations on text edits, 56860- // create file, rename file and delete file changes. 56861- // 56862- // @since 3.16.0 56863- ChangeAnnotationSupport *PChangeAnnotationSupportPWorkspaceEdit `json:"changeAnnotationSupport,omitempty"` 56864-} 56865- 56866-// A workspace folder inside a client. 56867-type WorkspaceFolder struct { // line 2163 56868- // The associated URI for this workspace folder. 56869- URI URI `json:"uri"` 56870- // The name of the workspace folder. Used to refer to this 56871- // workspace folder in the user interface. 56872- Name string `json:"name"` 56873-} 56874-type WorkspaceFolders5Gn struct { // line 9933 56875- // The server has support for workspace folders 56876- Supported bool `json:"supported,omitempty"` 56877- // Whether the server wants to receive workspace folder 56878- // change notifications. 56879- // 56880- // If a string is provided the string is treated as an ID 56881- // under which the notification is registered on the client 56882- // side. The ID can be used to unregister for these events 56883- // using the `client/unregisterCapability` request. 56884- ChangeNotifications string `json:"changeNotifications,omitempty"` 56885-} 56886- 56887-// The workspace folder change event. 56888-type WorkspaceFoldersChangeEvent struct { // line 6368 56889- // The array of added workspace folders 56890- Added []WorkspaceFolder `json:"added"` 56891- // The array of the removed workspace folders 56892- Removed []WorkspaceFolder `json:"removed"` 56893-} 56894-type WorkspaceFoldersInitializeParams struct { // line 7782 56895- // The workspace folders configured in the client when the server starts. 56896- // 56897- // This property is only available if the client supports workspace folders. 56898- // It can be `null` if the client supports workspace folders but none are 56899- // configured. 56900- // 56901- // @since 3.6.0 56902- WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"` 56903-} 56904-type WorkspaceFoldersServerCapabilities struct { // line 9933 56905- // The server has support for workspace folders 56906- Supported bool `json:"supported,omitempty"` 56907- // Whether the server wants to receive workspace folder 56908- // change notifications. 56909- // 56910- // If a string is provided the string is treated as an ID 56911- // under which the notification is registered on the client 56912- // side. The ID can be used to unregister for these events 56913- // using the `client/unregisterCapability` request. 56914- ChangeNotifications string `json:"changeNotifications,omitempty"` 56915-} 56916- 56917-// A full document diagnostic report for a workspace diagnostic result. 56918-// 56919-// @since 3.17.0 56920-type WorkspaceFullDocumentDiagnosticReport struct { // line 9522 56921- // The URI for which diagnostic information is reported. 56922- URI DocumentURI `json:"uri"` 56923- // The version number for which the diagnostics are reported. 56924- // If the document is not marked as open `null` can be provided. 56925- Version int32 `json:"version"` 56926- FullDocumentDiagnosticReport 56927-} 56928- 56929-// A special workspace symbol that supports locations without a range. 56930-// 56931-// See also SymbolInformation. 56932-// 56933-// @since 3.17.0 56934-type WorkspaceSymbol struct { // line 5515 56935- // The location of the symbol. Whether a server is allowed to 56936- // return a location without a range depends on the client 56937- // capability `workspace.symbol.resolveSupport`. 56938- // 56939- // See SymbolInformation#location for more details. 56940- Location OrPLocation_workspace_symbol `json:"location"` 56941- // A data entry field that is preserved on a workspace symbol between a 56942- // workspace symbol request and a workspace symbol resolve request. 56943- Data interface{} `json:"data,omitempty"` 56944- BaseSymbolInformation 56945-} 56946- 56947-// Client capabilities for a {@link WorkspaceSymbolRequest}. 56948-type WorkspaceSymbolClientCapabilities struct { // line 10875 56949- // Symbol request supports dynamic registration. 56950- DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 56951- // Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. 56952- SymbolKind *PSymbolKindPSymbol `json:"symbolKind,omitempty"` 56953- // The client supports tags on `SymbolInformation`. 56954- // Clients supporting tags have to handle unknown tags gracefully. 56955- // 56956- // @since 3.16.0 56957- TagSupport *PTagSupportPSymbol `json:"tagSupport,omitempty"` 56958- // The client support partial workspace symbols. The client will send the 56959- // request `workspaceSymbol/resolve` to the server to resolve additional 56960- // properties. 56961- // 56962- // @since 3.17.0 56963- ResolveSupport *PResolveSupportPSymbol `json:"resolveSupport,omitempty"` 56964-} 56965- 56966-// Server capabilities for a {@link WorkspaceSymbolRequest}. 56967-type WorkspaceSymbolOptions struct { // line 9105 56968- // The server provides support to resolve additional 56969- // information for a workspace symbol. 56970- // 56971- // @since 3.17.0 56972- ResolveProvider bool `json:"resolveProvider,omitempty"` 56973- WorkDoneProgressOptions 56974-} 56975- 56976-// The parameters of a {@link WorkspaceSymbolRequest}. 56977-type WorkspaceSymbolParams struct { // line 5491 56978- // A query string to filter symbols by. Clients may send an empty 56979- // string here to request all symbols. 56980- Query string `json:"query"` 56981- WorkDoneProgressParams 56982- PartialResultParams 56983-} 56984- 56985-// Registration options for a {@link WorkspaceSymbolRequest}. 56986-type WorkspaceSymbolRegistrationOptions struct { // line 5564 56987- WorkspaceSymbolOptions 56988-} 56989- 56990-// An unchanged document diagnostic report for a workspace diagnostic result. 56991-// 56992-// @since 3.17.0 56993-type WorkspaceUnchangedDocumentDiagnosticReport struct { // line 9560 56994- // The URI for which diagnostic information is reported. 56995- URI DocumentURI `json:"uri"` 56996- // The version number for which the diagnostics are reported. 56997- // If the document is not marked as open `null` can be provided. 56998- Version int32 `json:"version"` 56999- UnchangedDocumentDiagnosticReport 57000-} 57001- 57002-// The initialize parameters 57003-type XInitializeParams struct { // line 7650 57004- // The process Id of the parent process that started 57005- // the server. 57006- // 57007- // Is `null` if the process has not been started by another process. 57008- // If the parent process is not alive then the server should exit. 57009- ProcessID int32 `json:"processId"` 57010- // Information about the client 57011- // 57012- // @since 3.15.0 57013- ClientInfo *Msg_XInitializeParams_clientInfo `json:"clientInfo,omitempty"` 57014- // The locale the client is currently showing the user interface 57015- // in. This must not necessarily be the locale of the operating 57016- // system. 57017- // 57018- // Uses IETF language tags as the value's syntax 57019- // (See https://en.wikipedia.org/wiki/IETF_language_tag) 57020- // 57021- // @since 3.16.0 57022- Locale string `json:"locale,omitempty"` 57023- // The rootPath of the workspace. Is null 57024- // if no folder is open. 57025- // 57026- // @deprecated in favour of rootUri. 57027- RootPath string `json:"rootPath,omitempty"` 57028- // The rootUri of the workspace. Is null if no 57029- // folder is open. If both `rootPath` and `rootUri` are set 57030- // `rootUri` wins. 57031- // 57032- // @deprecated in favour of workspaceFolders. 57033- RootURI DocumentURI `json:"rootUri"` 57034- // The capabilities provided by the client (editor or tool) 57035- Capabilities ClientCapabilities `json:"capabilities"` 57036- // User provided initialization options. 57037- InitializationOptions interface{} `json:"initializationOptions,omitempty"` 57038- // The initial trace setting. If omitted trace is disabled ('off'). 57039- Trace *TraceValues `json:"trace,omitempty"` 57040- WorkDoneProgressParams 57041-} 57042- 57043-// The initialize parameters 57044-type _InitializeParams struct { // line 7650 57045- // The process Id of the parent process that started 57046- // the server. 57047- // 57048- // Is `null` if the process has not been started by another process. 57049- // If the parent process is not alive then the server should exit. 57050- ProcessID int32 `json:"processId"` 57051- // Information about the client 57052- // 57053- // @since 3.15.0 57054- ClientInfo *Msg_XInitializeParams_clientInfo `json:"clientInfo,omitempty"` 57055- // The locale the client is currently showing the user interface 57056- // in. This must not necessarily be the locale of the operating 57057- // system. 57058- // 57059- // Uses IETF language tags as the value's syntax 57060- // (See https://en.wikipedia.org/wiki/IETF_language_tag) 57061- // 57062- // @since 3.16.0 57063- Locale string `json:"locale,omitempty"` 57064- // The rootPath of the workspace. Is null 57065- // if no folder is open. 57066- // 57067- // @deprecated in favour of rootUri. 57068- RootPath string `json:"rootPath,omitempty"` 57069- // The rootUri of the workspace. Is null if no 57070- // folder is open. If both `rootPath` and `rootUri` are set 57071- // `rootUri` wins. 57072- // 57073- // @deprecated in favour of workspaceFolders. 57074- RootURI DocumentURI `json:"rootUri"` 57075- // The capabilities provided by the client (editor or tool) 57076- Capabilities ClientCapabilities `json:"capabilities"` 57077- // User provided initialization options. 57078- InitializationOptions interface{} `json:"initializationOptions,omitempty"` 57079- // The initial trace setting. If omitted trace is disabled ('off'). 57080- Trace *TraceValues `json:"trace,omitempty"` 57081- WorkDoneProgressParams 57082-} 57083- 57084-const ( 57085- // A set of predefined code action kinds 57086- // Empty kind. 57087- Empty CodeActionKind = "" // line 13333 57088- // Base kind for quickfix actions: 'quickfix' 57089- QuickFix CodeActionKind = "quickfix" // line 13338 57090- // Base kind for refactoring actions: 'refactor' 57091- Refactor CodeActionKind = "refactor" // line 13343 57092- // Base kind for refactoring extraction actions: 'refactor.extract' 57093- // 57094- // Example extract actions: 57095- // 57096- // 57097- // - Extract method 57098- // - Extract function 57099- // - Extract variable 57100- // - Extract interface from class 57101- // - ... 57102- RefactorExtract CodeActionKind = "refactor.extract" // line 13348 57103- // Base kind for refactoring inline actions: 'refactor.inline' 57104- // 57105- // Example inline actions: 57106- // 57107- // 57108- // - Inline function 57109- // - Inline variable 57110- // - Inline constant 57111- // - ... 57112- RefactorInline CodeActionKind = "refactor.inline" // line 13353 57113- // Base kind for refactoring rewrite actions: 'refactor.rewrite' 57114- // 57115- // Example rewrite actions: 57116- // 57117- // 57118- // - Convert JavaScript function to class 57119- // - Add or remove parameter 57120- // - Encapsulate field 57121- // - Make method static 57122- // - Move method to base class 57123- // - ... 57124- RefactorRewrite CodeActionKind = "refactor.rewrite" // line 13358 57125- // Base kind for source actions: `source` 57126- // 57127- // Source code actions apply to the entire file. 57128- Source CodeActionKind = "source" // line 13363 57129- // Base kind for an organize imports source action: `source.organizeImports` 57130- SourceOrganizeImports CodeActionKind = "source.organizeImports" // line 13368 57131- // Base kind for auto-fix source actions: `source.fixAll`. 57132- // 57133- // Fix all actions automatically fix errors that have a clear fix that do not require user input. 57134- // They should not suppress errors or perform unsafe fixes such as generating new types or classes. 57135- // 57136- // @since 3.15.0 57137- SourceFixAll CodeActionKind = "source.fixAll" // line 13373 57138- // The reason why code actions were requested. 57139- // 57140- // @since 3.17.0 57141- // Code actions were explicitly requested by the user or by an extension. 57142- CodeActionInvoked CodeActionTriggerKind = 1 // line 13613 57143- // Code actions were requested automatically. 57144- // 57145- // This typically happens when current selection in a file changes, but can 57146- // also be triggered when file content changes. 57147- CodeActionAutomatic CodeActionTriggerKind = 2 // line 13618 57148- // The kind of a completion entry. 57149- TextCompletion CompletionItemKind = 1 // line 13141 57150- MethodCompletion CompletionItemKind = 2 // line 13145 57151- FunctionCompletion CompletionItemKind = 3 // line 13149 57152- ConstructorCompletion CompletionItemKind = 4 // line 13153 57153- FieldCompletion CompletionItemKind = 5 // line 13157 57154- VariableCompletion CompletionItemKind = 6 // line 13161 57155- ClassCompletion CompletionItemKind = 7 // line 13165 57156- InterfaceCompletion CompletionItemKind = 8 // line 13169 57157- ModuleCompletion CompletionItemKind = 9 // line 13173 57158- PropertyCompletion CompletionItemKind = 10 // line 13177 57159- UnitCompletion CompletionItemKind = 11 // line 13181 57160- ValueCompletion CompletionItemKind = 12 // line 13185 57161- EnumCompletion CompletionItemKind = 13 // line 13189 57162- KeywordCompletion CompletionItemKind = 14 // line 13193 57163- SnippetCompletion CompletionItemKind = 15 // line 13197 57164- ColorCompletion CompletionItemKind = 16 // line 13201 57165- FileCompletion CompletionItemKind = 17 // line 13205 57166- ReferenceCompletion CompletionItemKind = 18 // line 13209 57167- FolderCompletion CompletionItemKind = 19 // line 13213 57168- EnumMemberCompletion CompletionItemKind = 20 // line 13217 57169- ConstantCompletion CompletionItemKind = 21 // line 13221 57170- StructCompletion CompletionItemKind = 22 // line 13225 57171- EventCompletion CompletionItemKind = 23 // line 13229 57172- OperatorCompletion CompletionItemKind = 24 // line 13233 57173- TypeParameterCompletion CompletionItemKind = 25 // line 13237 57174- // Completion item tags are extra annotations that tweak the rendering of a completion 57175- // item. 57176- // 57177- // @since 3.15.0 57178- // Render a completion as obsolete, usually using a strike-out. 57179- ComplDeprecated CompletionItemTag = 1 // line 13251 57180- // How a completion was triggered 57181- // Completion was triggered by typing an identifier (24x7 code 57182- // complete), manual invocation (e.g Ctrl+Space) or via API. 57183- Invoked CompletionTriggerKind = 1 // line 13562 57184- // Completion was triggered by a trigger character specified by 57185- // the `triggerCharacters` properties of the `CompletionRegistrationOptions`. 57186- TriggerCharacter CompletionTriggerKind = 2 // line 13567 57187- // Completion was re-triggered as current completion list is incomplete 57188- TriggerForIncompleteCompletions CompletionTriggerKind = 3 // line 13572 57189- // The diagnostic's severity. 57190- // Reports an error. 57191- SeverityError DiagnosticSeverity = 1 // line 13511 57192- // Reports a warning. 57193- SeverityWarning DiagnosticSeverity = 2 // line 13516 57194- // Reports an information. 57195- SeverityInformation DiagnosticSeverity = 3 // line 13521 57196- // Reports a hint. 57197- SeverityHint DiagnosticSeverity = 4 // line 13526 57198- // The diagnostic tags. 57199- // 57200- // @since 3.15.0 57201- // Unused or unnecessary code. 57202- // 57203- // Clients are allowed to render diagnostics with this tag faded out instead of having 57204- // an error squiggle. 57205- Unnecessary DiagnosticTag = 1 // line 13541 57206- // Deprecated or obsolete code. 57207- // 57208- // Clients are allowed to rendered diagnostics with this tag strike through. 57209- Deprecated DiagnosticTag = 2 // line 13546 57210- // The document diagnostic report kinds. 57211- // 57212- // @since 3.17.0 57213- // A diagnostic report with a full 57214- // set of problems. 57215- DiagnosticFull DocumentDiagnosticReportKind = "full" // line 12729 57216- // A report indicating that the last 57217- // returned report is still accurate. 57218- DiagnosticUnchanged DocumentDiagnosticReportKind = "unchanged" // line 12734 57219- // A document highlight kind. 57220- // A textual occurrence. 57221- Text DocumentHighlightKind = 1 // line 13308 57222- // Read-access of a symbol, like reading a variable. 57223- Read DocumentHighlightKind = 2 // line 13313 57224- // Write-access of a symbol, like writing to a variable. 57225- Write DocumentHighlightKind = 3 // line 13318 57226- // Predefined error codes. 57227- ParseError ErrorCodes = -32700 // line 12750 57228- InvalidRequest ErrorCodes = -32600 // line 12754 57229- MethodNotFound ErrorCodes = -32601 // line 12758 57230- InvalidParams ErrorCodes = -32602 // line 12762 57231- InternalError ErrorCodes = -32603 // line 12766 57232- // Error code indicating that a server received a notification or 57233- // request before the server has received the `initialize` request. 57234- ServerNotInitialized ErrorCodes = -32002 // line 12770 57235- UnknownErrorCode ErrorCodes = -32001 // line 12775 57236- // Applying the workspace change is simply aborted if one of the changes provided 57237- // fails. All operations executed before the failing operation stay executed. 57238- Abort FailureHandlingKind = "abort" // line 13700 57239- // All operations are executed transactional. That means they either all 57240- // succeed or no changes at all are applied to the workspace. 57241- Transactional FailureHandlingKind = "transactional" // line 13705 57242- // If the workspace edit contains only textual file changes they are executed transactional. 57243- // If resource changes (create, rename or delete file) are part of the change the failure 57244- // handling strategy is abort. 57245- TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional" // line 13710 57246- // The client tries to undo the operations already executed. But there is no 57247- // guarantee that this is succeeding. 57248- Undo FailureHandlingKind = "undo" // line 13715 57249- // The file event type 57250- // The file got created. 57251- Created FileChangeType = 1 // line 13461 57252- // The file got changed. 57253- Changed FileChangeType = 2 // line 13466 57254- // The file got deleted. 57255- Deleted FileChangeType = 3 // line 13471 57256- // A pattern kind describing if a glob pattern matches a file a folder or 57257- // both. 57258- // 57259- // @since 3.16.0 57260- // The pattern matches a file only. 57261- FilePattern FileOperationPatternKind = "file" // line 13634 57262- // The pattern matches a folder only. 57263- FolderPattern FileOperationPatternKind = "folder" // line 13639 57264- // A set of predefined range kinds. 57265- // Folding range for a comment 57266- Comment FoldingRangeKind = "comment" // line 12822 57267- // Folding range for an import or include 57268- Imports FoldingRangeKind = "imports" // line 12827 57269- // Folding range for a region (e.g. `#region`) 57270- Region FoldingRangeKind = "region" // line 12832 57271- // Inlay hint kinds. 57272- // 57273- // @since 3.17.0 57274- // An inlay hint that for a type annotation. 57275- Type InlayHintKind = 1 // line 13040 57276- // An inlay hint that is for a parameter. 57277- Parameter InlayHintKind = 2 // line 13045 57278- // Defines whether the insert text in a completion item should be interpreted as 57279- // plain text or a snippet. 57280- // The primary text to be inserted is treated as a plain string. 57281- PlainTextTextFormat InsertTextFormat = 1 // line 13267 57282- // The primary text to be inserted is treated as a snippet. 57283- // 57284- // A snippet can define tab stops and placeholders with `$1`, `$2` 57285- // and `${3:foo}`. `$0` defines the final tab stop, it defaults to 57286- // the end of the snippet. Placeholders with equal identifiers are linked, 57287- // that is typing in one will update others too. 57288- // 57289- // See also: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#snippet_syntax 57290- SnippetTextFormat InsertTextFormat = 2 // line 13272 57291- // How whitespace and indentation is handled during completion 57292- // item insertion. 57293- // 57294- // @since 3.16.0 57295- // The insertion or replace strings is taken as it is. If the 57296- // value is multi line the lines below the cursor will be 57297- // inserted using the indentation defined in the string value. 57298- // The client will not apply any kind of adjustments to the 57299- // string. 57300- AsIs InsertTextMode = 1 // line 13287 57301- // The editor adjusts leading whitespace of new lines so that 57302- // they match the indentation up to the cursor of the line for 57303- // which the item is accepted. 57304- // 57305- // Consider a line like this: <2tabs><cursor><3tabs>foo. Accepting a 57306- // multi line completion item is indented using 2 tabs and all 57307- // following lines inserted will be indented using 2 tabs as well. 57308- AdjustIndentation InsertTextMode = 2 // line 13292 57309- // A request failed but it was syntactically correct, e.g the 57310- // method name was known and the parameters were valid. The error 57311- // message should contain human readable information about why 57312- // the request failed. 57313- // 57314- // @since 3.17.0 57315- RequestFailed LSPErrorCodes = -32803 // line 12790 57316- // The server cancelled the request. This error code should 57317- // only be used for requests that explicitly support being 57318- // server cancellable. 57319- // 57320- // @since 3.17.0 57321- ServerCancelled LSPErrorCodes = -32802 // line 12796 57322- // The server detected that the content of a document got 57323- // modified outside normal conditions. A server should 57324- // NOT send this error code if it detects a content change 57325- // in it unprocessed messages. The result even computed 57326- // on an older state might still be useful for the client. 57327- // 57328- // If a client decides that a result is not of any use anymore 57329- // the client should cancel the request. 57330- ContentModified LSPErrorCodes = -32801 // line 12802 57331- // The client has canceled a request and a server as detected 57332- // the cancel. 57333- RequestCancelled LSPErrorCodes = -32800 // line 12807 57334- // Describes the content type that a client supports in various 57335- // result literals like `Hover`, `ParameterInfo` or `CompletionItem`. 57336- // 57337- // Please note that `MarkupKinds` must not start with a `$`. This kinds 57338- // are reserved for internal usage. 57339- // Plain text is supported as a content format 57340- PlainText MarkupKind = "plaintext" // line 13414 57341- // Markdown is supported as a content format 57342- Markdown MarkupKind = "markdown" // line 13419 57343- // The message type 57344- // An error message. 57345- Error MessageType = 1 // line 13061 57346- // A warning message. 57347- Warning MessageType = 2 // line 13066 57348- // An information message. 57349- Info MessageType = 3 // line 13071 57350- // A log message. 57351- Log MessageType = 4 // line 13076 57352- // The moniker kind. 57353- // 57354- // @since 3.16.0 57355- // The moniker represent a symbol that is imported into a project 57356- Import MonikerKind = "import" // line 13014 57357- // The moniker represents a symbol that is exported from a project 57358- Export MonikerKind = "export" // line 13019 57359- // The moniker represents a symbol that is local to a project (e.g. a local 57360- // variable of a function, a class not visible outside the project, ...) 57361- Local MonikerKind = "local" // line 13024 57362- // A notebook cell kind. 57363- // 57364- // @since 3.17.0 57365- // A markup-cell is formatted source that is used for display. 57366- Markup NotebookCellKind = 1 // line 13655 57367- // A code-cell is source code. 57368- Code NotebookCellKind = 2 // line 13660 57369- // A set of predefined position encoding kinds. 57370- // 57371- // @since 3.17.0 57372- // Character offsets count UTF-8 code units. 57373- UTF8 PositionEncodingKind = "utf-8" // line 13434 57374- // Character offsets count UTF-16 code units. 57375- // 57376- // This is the default and must always be supported 57377- // by servers 57378- UTF16 PositionEncodingKind = "utf-16" // line 13439 57379- // Character offsets count UTF-32 code units. 57380- // 57381- // Implementation note: these are the same as Unicode code points, 57382- // so this `PositionEncodingKind` may also be used for an 57383- // encoding-agnostic representation of character offsets. 57384- UTF32 PositionEncodingKind = "utf-32" // line 13444 57385- // The client's default behavior is to select the identifier 57386- // according the to language's syntax rule. 57387- Identifier PrepareSupportDefaultBehavior = 1 // line 13729 57388- // Supports creating new files and folders. 57389- Create ResourceOperationKind = "create" // line 13676 57390- // Supports renaming existing files and folders. 57391- Rename ResourceOperationKind = "rename" // line 13681 57392- // Supports deleting existing files and folders. 57393- Delete ResourceOperationKind = "delete" // line 13686 57394- // A set of predefined token modifiers. This set is not fixed 57395- // an clients can specify additional token types via the 57396- // corresponding client capabilities. 57397- // 57398- // @since 3.16.0 57399- ModDeclaration SemanticTokenModifiers = "declaration" // line 12677 57400- ModDefinition SemanticTokenModifiers = "definition" // line 12681 57401- ModReadonly SemanticTokenModifiers = "readonly" // line 12685 57402- ModStatic SemanticTokenModifiers = "static" // line 12689 57403- ModDeprecated SemanticTokenModifiers = "deprecated" // line 12693 57404- ModAbstract SemanticTokenModifiers = "abstract" // line 12697 57405- ModAsync SemanticTokenModifiers = "async" // line 12701 57406- ModModification SemanticTokenModifiers = "modification" // line 12705 57407- ModDocumentation SemanticTokenModifiers = "documentation" // line 12709 57408- ModDefaultLibrary SemanticTokenModifiers = "defaultLibrary" // line 12713 57409- // A set of predefined token types. This set is not fixed 57410- // an clients can specify additional token types via the 57411- // corresponding client capabilities. 57412- // 57413- // @since 3.16.0 57414- NamespaceType SemanticTokenTypes = "namespace" // line 12570 57415- // Represents a generic type. Acts as a fallback for types which can't be mapped to 57416- // a specific type like class or enum. 57417- TypeType SemanticTokenTypes = "type" // line 12574 57418- ClassType SemanticTokenTypes = "class" // line 12579 57419- EnumType SemanticTokenTypes = "enum" // line 12583 57420- InterfaceType SemanticTokenTypes = "interface" // line 12587 57421- StructType SemanticTokenTypes = "struct" // line 12591 57422- TypeParameterType SemanticTokenTypes = "typeParameter" // line 12595 57423- ParameterType SemanticTokenTypes = "parameter" // line 12599 57424- VariableType SemanticTokenTypes = "variable" // line 12603 57425- PropertyType SemanticTokenTypes = "property" // line 12607 57426- EnumMemberType SemanticTokenTypes = "enumMember" // line 12611 57427- EventType SemanticTokenTypes = "event" // line 12615 57428- FunctionType SemanticTokenTypes = "function" // line 12619 57429- MethodType SemanticTokenTypes = "method" // line 12623 57430- MacroType SemanticTokenTypes = "macro" // line 12627 57431- KeywordType SemanticTokenTypes = "keyword" // line 12631 57432- ModifierType SemanticTokenTypes = "modifier" // line 12635 57433- CommentType SemanticTokenTypes = "comment" // line 12639 57434- StringType SemanticTokenTypes = "string" // line 12643 57435- NumberType SemanticTokenTypes = "number" // line 12647 57436- RegexpType SemanticTokenTypes = "regexp" // line 12651 57437- OperatorType SemanticTokenTypes = "operator" // line 12655 57438- // @since 3.17.0 57439- DecoratorType SemanticTokenTypes = "decorator" // line 12659 57440- // How a signature help was triggered. 57441- // 57442- // @since 3.15.0 57443- // Signature help was invoked manually by the user or by a command. 57444- SigInvoked SignatureHelpTriggerKind = 1 // line 13587 57445- // Signature help was triggered by a trigger character. 57446- SigTriggerCharacter SignatureHelpTriggerKind = 2 // line 13592 57447- // Signature help was triggered by the cursor moving or by the document content changing. 57448- SigContentChange SignatureHelpTriggerKind = 3 // line 13597 57449- // A symbol kind. 57450- File SymbolKind = 1 // line 12848 57451- Module SymbolKind = 2 // line 12852 57452- Namespace SymbolKind = 3 // line 12856 57453- Package SymbolKind = 4 // line 12860 57454- Class SymbolKind = 5 // line 12864 57455- Method SymbolKind = 6 // line 12868 57456- Property SymbolKind = 7 // line 12872 57457- Field SymbolKind = 8 // line 12876 57458- Constructor SymbolKind = 9 // line 12880 57459- Enum SymbolKind = 10 // line 12884 57460- Interface SymbolKind = 11 // line 12888 57461- Function SymbolKind = 12 // line 12892 57462- Variable SymbolKind = 13 // line 12896 57463- Constant SymbolKind = 14 // line 12900 57464- String SymbolKind = 15 // line 12904 57465- Number SymbolKind = 16 // line 12908 57466- Boolean SymbolKind = 17 // line 12912 57467- Array SymbolKind = 18 // line 12916 57468- Object SymbolKind = 19 // line 12920 57469- Key SymbolKind = 20 // line 12924 57470- Null SymbolKind = 21 // line 12928 57471- EnumMember SymbolKind = 22 // line 12932 57472- Struct SymbolKind = 23 // line 12936 57473- Event SymbolKind = 24 // line 12940 57474- Operator SymbolKind = 25 // line 12944 57475- TypeParameter SymbolKind = 26 // line 12948 57476- // Symbol tags are extra annotations that tweak the rendering of a symbol. 57477- // 57478- // @since 3.16 57479- // Render a symbol as obsolete, usually using a strike-out. 57480- DeprecatedSymbol SymbolTag = 1 // line 12962 57481- // Represents reasons why a text document is saved. 57482- // Manually triggered, e.g. by the user pressing save, by starting debugging, 57483- // or by an API call. 57484- Manual TextDocumentSaveReason = 1 // line 13116 57485- // Automatic after a delay. 57486- AfterDelay TextDocumentSaveReason = 2 // line 13121 57487- // When the editor lost focus. 57488- FocusOut TextDocumentSaveReason = 3 // line 13126 57489- // Defines how the host (editor) should sync 57490- // document changes to the language server. 57491- // Documents should not be synced at all. 57492- None TextDocumentSyncKind = 0 // line 13091 57493- // Documents are synced by always sending the full content 57494- // of the document. 57495- Full TextDocumentSyncKind = 1 // line 13096 57496- // Documents are synced by sending the full content on open. 57497- // After that only incremental updates to the document are 57498- // send. 57499- Incremental TextDocumentSyncKind = 2 // line 13101 57500- Relative TokenFormat = "relative" // line 13743 57501- // Turn tracing off. 57502- Off TraceValues = "off" // line 13390 57503- // Trace messages only. 57504- Messages TraceValues = "messages" // line 13395 57505- // Verbose message tracing. 57506- Verbose TraceValues = "verbose" // line 13400 57507- // Moniker uniqueness level to define scope of the moniker. 57508- // 57509- // @since 3.16.0 57510- // The moniker is only unique inside a document 57511- Document UniquenessLevel = "document" // line 12978 57512- // The moniker is unique inside a project for which a dump got created 57513- Project UniquenessLevel = "project" // line 12983 57514- // The moniker is unique inside the group to which a project belongs 57515- Group UniquenessLevel = "group" // line 12988 57516- // The moniker is unique inside the moniker scheme. 57517- Scheme UniquenessLevel = "scheme" // line 12993 57518- // The moniker is globally unique 57519- Global UniquenessLevel = "global" // line 12998 57520- // Interested in create events. 57521- WatchCreate WatchKind = 1 // line 13486 57522- // Interested in change events 57523- WatchChange WatchKind = 2 // line 13491 57524- // Interested in delete events 57525- WatchDelete WatchKind = 4 // line 13496 57526-) 57527diff -urN a/gopls/internal/lsp/protocol/tsserver.go b/gopls/internal/lsp/protocol/tsserver.go 57528--- a/gopls/internal/lsp/protocol/tsserver.go 2000-01-01 00:00:00.000000000 -0000 57529+++ b/gopls/internal/lsp/protocol/tsserver.go 1970-01-01 00:00:00.000000000 +0000 57530@@ -1,1160 +0,0 @@ 57531-// Copyright 2023 The Go Authors. All rights reserved. 57532-// Use of this source code is governed by a BSD-style 57533-// license that can be found in the LICENSE file. 57534- 57535-// Code generated for LSP. DO NOT EDIT. 57536- 57537-package protocol 57538- 57539-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f). 57540-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json 57541-// LSP metaData.version = 3.17.0. 57542- 57543-import ( 57544- "context" 57545- "encoding/json" 57546- 57547- "golang.org/x/tools/internal/jsonrpc2" 57548-) 57549- 57550-type Server interface { 57551- Progress(context.Context, *ProgressParams) error // $/progress 57552- SetTrace(context.Context, *SetTraceParams) error // $/setTrace 57553- IncomingCalls(context.Context, *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall, error) // callHierarchy/incomingCalls 57554- OutgoingCalls(context.Context, *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall, error) // callHierarchy/outgoingCalls 57555- ResolveCodeAction(context.Context, *CodeAction) (*CodeAction, error) // codeAction/resolve 57556- ResolveCodeLens(context.Context, *CodeLens) (*CodeLens, error) // codeLens/resolve 57557- ResolveCompletionItem(context.Context, *CompletionItem) (*CompletionItem, error) // completionItem/resolve 57558- ResolveDocumentLink(context.Context, *DocumentLink) (*DocumentLink, error) // documentLink/resolve 57559- Exit(context.Context) error // exit 57560- Initialize(context.Context, *ParamInitialize) (*InitializeResult, error) // initialize 57561- Initialized(context.Context, *InitializedParams) error // initialized 57562- Resolve(context.Context, *InlayHint) (*InlayHint, error) // inlayHint/resolve 57563- DidChangeNotebookDocument(context.Context, *DidChangeNotebookDocumentParams) error // notebookDocument/didChange 57564- DidCloseNotebookDocument(context.Context, *DidCloseNotebookDocumentParams) error // notebookDocument/didClose 57565- DidOpenNotebookDocument(context.Context, *DidOpenNotebookDocumentParams) error // notebookDocument/didOpen 57566- DidSaveNotebookDocument(context.Context, *DidSaveNotebookDocumentParams) error // notebookDocument/didSave 57567- Shutdown(context.Context) error // shutdown 57568- CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error) // textDocument/codeAction 57569- CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error) // textDocument/codeLens 57570- ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error) // textDocument/colorPresentation 57571- Completion(context.Context, *CompletionParams) (*CompletionList, error) // textDocument/completion 57572- Declaration(context.Context, *DeclarationParams) (*Or_textDocument_declaration, error) // textDocument/declaration 57573- Definition(context.Context, *DefinitionParams) ([]Location, error) // textDocument/definition 57574- Diagnostic(context.Context, *string) (*string, error) // textDocument/diagnostic 57575- DidChange(context.Context, *DidChangeTextDocumentParams) error // textDocument/didChange 57576- DidClose(context.Context, *DidCloseTextDocumentParams) error // textDocument/didClose 57577- DidOpen(context.Context, *DidOpenTextDocumentParams) error // textDocument/didOpen 57578- DidSave(context.Context, *DidSaveTextDocumentParams) error // textDocument/didSave 57579- DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error) // textDocument/documentColor 57580- DocumentHighlight(context.Context, *DocumentHighlightParams) ([]DocumentHighlight, error) // textDocument/documentHighlight 57581- DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error) // textDocument/documentLink 57582- DocumentSymbol(context.Context, *DocumentSymbolParams) ([]interface{}, error) // textDocument/documentSymbol 57583- FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange, error) // textDocument/foldingRange 57584- Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error) // textDocument/formatting 57585- Hover(context.Context, *HoverParams) (*Hover, error) // textDocument/hover 57586- Implementation(context.Context, *ImplementationParams) ([]Location, error) // textDocument/implementation 57587- InlayHint(context.Context, *InlayHintParams) ([]InlayHint, error) // textDocument/inlayHint 57588- InlineValue(context.Context, *InlineValueParams) ([]InlineValue, error) // textDocument/inlineValue 57589- LinkedEditingRange(context.Context, *LinkedEditingRangeParams) (*LinkedEditingRanges, error) // textDocument/linkedEditingRange 57590- Moniker(context.Context, *MonikerParams) ([]Moniker, error) // textDocument/moniker 57591- OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error) // textDocument/onTypeFormatting 57592- PrepareCallHierarchy(context.Context, *CallHierarchyPrepareParams) ([]CallHierarchyItem, error) // textDocument/prepareCallHierarchy 57593- PrepareRename(context.Context, *PrepareRenameParams) (*PrepareRename2Gn, error) // textDocument/prepareRename 57594- PrepareTypeHierarchy(context.Context, *TypeHierarchyPrepareParams) ([]TypeHierarchyItem, error) // textDocument/prepareTypeHierarchy 57595- RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error) // textDocument/rangeFormatting 57596- References(context.Context, *ReferenceParams) ([]Location, error) // textDocument/references 57597- Rename(context.Context, *RenameParams) (*WorkspaceEdit, error) // textDocument/rename 57598- SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange, error) // textDocument/selectionRange 57599- SemanticTokensFull(context.Context, *SemanticTokensParams) (*SemanticTokens, error) // textDocument/semanticTokens/full 57600- SemanticTokensFullDelta(context.Context, *SemanticTokensDeltaParams) (interface{}, error) // textDocument/semanticTokens/full/delta 57601- SemanticTokensRange(context.Context, *SemanticTokensRangeParams) (*SemanticTokens, error) // textDocument/semanticTokens/range 57602- SignatureHelp(context.Context, *SignatureHelpParams) (*SignatureHelp, error) // textDocument/signatureHelp 57603- TypeDefinition(context.Context, *TypeDefinitionParams) ([]Location, error) // textDocument/typeDefinition 57604- WillSave(context.Context, *WillSaveTextDocumentParams) error // textDocument/willSave 57605- WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error) // textDocument/willSaveWaitUntil 57606- Subtypes(context.Context, *TypeHierarchySubtypesParams) ([]TypeHierarchyItem, error) // typeHierarchy/subtypes 57607- Supertypes(context.Context, *TypeHierarchySupertypesParams) ([]TypeHierarchyItem, error) // typeHierarchy/supertypes 57608- WorkDoneProgressCancel(context.Context, *WorkDoneProgressCancelParams) error // window/workDoneProgress/cancel 57609- DiagnosticWorkspace(context.Context, *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error) // workspace/diagnostic 57610- DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error // workspace/didChangeConfiguration 57611- DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error // workspace/didChangeWatchedFiles 57612- DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error // workspace/didChangeWorkspaceFolders 57613- DidCreateFiles(context.Context, *CreateFilesParams) error // workspace/didCreateFiles 57614- DidDeleteFiles(context.Context, *DeleteFilesParams) error // workspace/didDeleteFiles 57615- DidRenameFiles(context.Context, *RenameFilesParams) error // workspace/didRenameFiles 57616- ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error) // workspace/executeCommand 57617- Symbol(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error) // workspace/symbol 57618- WillCreateFiles(context.Context, *CreateFilesParams) (*WorkspaceEdit, error) // workspace/willCreateFiles 57619- WillDeleteFiles(context.Context, *DeleteFilesParams) (*WorkspaceEdit, error) // workspace/willDeleteFiles 57620- WillRenameFiles(context.Context, *RenameFilesParams) (*WorkspaceEdit, error) // workspace/willRenameFiles 57621- ResolveWorkspaceSymbol(context.Context, *WorkspaceSymbol) (*WorkspaceSymbol, error) // workspaceSymbol/resolve 57622- NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) 57623-} 57624- 57625-func serverDispatch(ctx context.Context, server Server, reply jsonrpc2.Replier, r jsonrpc2.Request) (bool, error) { 57626- switch r.Method() { 57627- case "$/progress": 57628- var params ProgressParams 57629- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57630- return true, sendParseError(ctx, reply, err) 57631- } 57632- err := server.Progress(ctx, ¶ms) 57633- return true, reply(ctx, nil, err) 57634- case "$/setTrace": 57635- var params SetTraceParams 57636- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57637- return true, sendParseError(ctx, reply, err) 57638- } 57639- err := server.SetTrace(ctx, ¶ms) 57640- return true, reply(ctx, nil, err) 57641- case "callHierarchy/incomingCalls": 57642- var params CallHierarchyIncomingCallsParams 57643- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57644- return true, sendParseError(ctx, reply, err) 57645- } 57646- resp, err := server.IncomingCalls(ctx, ¶ms) 57647- if err != nil { 57648- return true, reply(ctx, nil, err) 57649- } 57650- return true, reply(ctx, resp, nil) 57651- case "callHierarchy/outgoingCalls": 57652- var params CallHierarchyOutgoingCallsParams 57653- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57654- return true, sendParseError(ctx, reply, err) 57655- } 57656- resp, err := server.OutgoingCalls(ctx, ¶ms) 57657- if err != nil { 57658- return true, reply(ctx, nil, err) 57659- } 57660- return true, reply(ctx, resp, nil) 57661- case "codeAction/resolve": 57662- var params CodeAction 57663- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57664- return true, sendParseError(ctx, reply, err) 57665- } 57666- resp, err := server.ResolveCodeAction(ctx, ¶ms) 57667- if err != nil { 57668- return true, reply(ctx, nil, err) 57669- } 57670- return true, reply(ctx, resp, nil) 57671- case "codeLens/resolve": 57672- var params CodeLens 57673- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57674- return true, sendParseError(ctx, reply, err) 57675- } 57676- resp, err := server.ResolveCodeLens(ctx, ¶ms) 57677- if err != nil { 57678- return true, reply(ctx, nil, err) 57679- } 57680- return true, reply(ctx, resp, nil) 57681- case "completionItem/resolve": 57682- var params CompletionItem 57683- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57684- return true, sendParseError(ctx, reply, err) 57685- } 57686- resp, err := server.ResolveCompletionItem(ctx, ¶ms) 57687- if err != nil { 57688- return true, reply(ctx, nil, err) 57689- } 57690- return true, reply(ctx, resp, nil) 57691- case "documentLink/resolve": 57692- var params DocumentLink 57693- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57694- return true, sendParseError(ctx, reply, err) 57695- } 57696- resp, err := server.ResolveDocumentLink(ctx, ¶ms) 57697- if err != nil { 57698- return true, reply(ctx, nil, err) 57699- } 57700- return true, reply(ctx, resp, nil) 57701- case "exit": 57702- err := server.Exit(ctx) 57703- return true, reply(ctx, nil, err) 57704- case "initialize": 57705- var params ParamInitialize 57706- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57707- return true, sendParseError(ctx, reply, err) 57708- } 57709- resp, err := server.Initialize(ctx, ¶ms) 57710- if err != nil { 57711- return true, reply(ctx, nil, err) 57712- } 57713- return true, reply(ctx, resp, nil) 57714- case "initialized": 57715- var params InitializedParams 57716- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57717- return true, sendParseError(ctx, reply, err) 57718- } 57719- err := server.Initialized(ctx, ¶ms) 57720- return true, reply(ctx, nil, err) 57721- case "inlayHint/resolve": 57722- var params InlayHint 57723- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57724- return true, sendParseError(ctx, reply, err) 57725- } 57726- resp, err := server.Resolve(ctx, ¶ms) 57727- if err != nil { 57728- return true, reply(ctx, nil, err) 57729- } 57730- return true, reply(ctx, resp, nil) 57731- case "notebookDocument/didChange": 57732- var params DidChangeNotebookDocumentParams 57733- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57734- return true, sendParseError(ctx, reply, err) 57735- } 57736- err := server.DidChangeNotebookDocument(ctx, ¶ms) 57737- return true, reply(ctx, nil, err) 57738- case "notebookDocument/didClose": 57739- var params DidCloseNotebookDocumentParams 57740- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57741- return true, sendParseError(ctx, reply, err) 57742- } 57743- err := server.DidCloseNotebookDocument(ctx, ¶ms) 57744- return true, reply(ctx, nil, err) 57745- case "notebookDocument/didOpen": 57746- var params DidOpenNotebookDocumentParams 57747- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57748- return true, sendParseError(ctx, reply, err) 57749- } 57750- err := server.DidOpenNotebookDocument(ctx, ¶ms) 57751- return true, reply(ctx, nil, err) 57752- case "notebookDocument/didSave": 57753- var params DidSaveNotebookDocumentParams 57754- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57755- return true, sendParseError(ctx, reply, err) 57756- } 57757- err := server.DidSaveNotebookDocument(ctx, ¶ms) 57758- return true, reply(ctx, nil, err) 57759- case "shutdown": 57760- err := server.Shutdown(ctx) 57761- return true, reply(ctx, nil, err) 57762- case "textDocument/codeAction": 57763- var params CodeActionParams 57764- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57765- return true, sendParseError(ctx, reply, err) 57766- } 57767- resp, err := server.CodeAction(ctx, ¶ms) 57768- if err != nil { 57769- return true, reply(ctx, nil, err) 57770- } 57771- return true, reply(ctx, resp, nil) 57772- case "textDocument/codeLens": 57773- var params CodeLensParams 57774- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57775- return true, sendParseError(ctx, reply, err) 57776- } 57777- resp, err := server.CodeLens(ctx, ¶ms) 57778- if err != nil { 57779- return true, reply(ctx, nil, err) 57780- } 57781- return true, reply(ctx, resp, nil) 57782- case "textDocument/colorPresentation": 57783- var params ColorPresentationParams 57784- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57785- return true, sendParseError(ctx, reply, err) 57786- } 57787- resp, err := server.ColorPresentation(ctx, ¶ms) 57788- if err != nil { 57789- return true, reply(ctx, nil, err) 57790- } 57791- return true, reply(ctx, resp, nil) 57792- case "textDocument/completion": 57793- var params CompletionParams 57794- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57795- return true, sendParseError(ctx, reply, err) 57796- } 57797- resp, err := server.Completion(ctx, ¶ms) 57798- if err != nil { 57799- return true, reply(ctx, nil, err) 57800- } 57801- return true, reply(ctx, resp, nil) 57802- case "textDocument/declaration": 57803- var params DeclarationParams 57804- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57805- return true, sendParseError(ctx, reply, err) 57806- } 57807- resp, err := server.Declaration(ctx, ¶ms) 57808- if err != nil { 57809- return true, reply(ctx, nil, err) 57810- } 57811- return true, reply(ctx, resp, nil) 57812- case "textDocument/definition": 57813- var params DefinitionParams 57814- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57815- return true, sendParseError(ctx, reply, err) 57816- } 57817- resp, err := server.Definition(ctx, ¶ms) 57818- if err != nil { 57819- return true, reply(ctx, nil, err) 57820- } 57821- return true, reply(ctx, resp, nil) 57822- case "textDocument/diagnostic": 57823- var params string 57824- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57825- return true, sendParseError(ctx, reply, err) 57826- } 57827- resp, err := server.Diagnostic(ctx, ¶ms) 57828- if err != nil { 57829- return true, reply(ctx, nil, err) 57830- } 57831- return true, reply(ctx, resp, nil) 57832- case "textDocument/didChange": 57833- var params DidChangeTextDocumentParams 57834- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57835- return true, sendParseError(ctx, reply, err) 57836- } 57837- err := server.DidChange(ctx, ¶ms) 57838- return true, reply(ctx, nil, err) 57839- case "textDocument/didClose": 57840- var params DidCloseTextDocumentParams 57841- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57842- return true, sendParseError(ctx, reply, err) 57843- } 57844- err := server.DidClose(ctx, ¶ms) 57845- return true, reply(ctx, nil, err) 57846- case "textDocument/didOpen": 57847- var params DidOpenTextDocumentParams 57848- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57849- return true, sendParseError(ctx, reply, err) 57850- } 57851- err := server.DidOpen(ctx, ¶ms) 57852- return true, reply(ctx, nil, err) 57853- case "textDocument/didSave": 57854- var params DidSaveTextDocumentParams 57855- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57856- return true, sendParseError(ctx, reply, err) 57857- } 57858- err := server.DidSave(ctx, ¶ms) 57859- return true, reply(ctx, nil, err) 57860- case "textDocument/documentColor": 57861- var params DocumentColorParams 57862- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57863- return true, sendParseError(ctx, reply, err) 57864- } 57865- resp, err := server.DocumentColor(ctx, ¶ms) 57866- if err != nil { 57867- return true, reply(ctx, nil, err) 57868- } 57869- return true, reply(ctx, resp, nil) 57870- case "textDocument/documentHighlight": 57871- var params DocumentHighlightParams 57872- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57873- return true, sendParseError(ctx, reply, err) 57874- } 57875- resp, err := server.DocumentHighlight(ctx, ¶ms) 57876- if err != nil { 57877- return true, reply(ctx, nil, err) 57878- } 57879- return true, reply(ctx, resp, nil) 57880- case "textDocument/documentLink": 57881- var params DocumentLinkParams 57882- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57883- return true, sendParseError(ctx, reply, err) 57884- } 57885- resp, err := server.DocumentLink(ctx, ¶ms) 57886- if err != nil { 57887- return true, reply(ctx, nil, err) 57888- } 57889- return true, reply(ctx, resp, nil) 57890- case "textDocument/documentSymbol": 57891- var params DocumentSymbolParams 57892- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57893- return true, sendParseError(ctx, reply, err) 57894- } 57895- resp, err := server.DocumentSymbol(ctx, ¶ms) 57896- if err != nil { 57897- return true, reply(ctx, nil, err) 57898- } 57899- return true, reply(ctx, resp, nil) 57900- case "textDocument/foldingRange": 57901- var params FoldingRangeParams 57902- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57903- return true, sendParseError(ctx, reply, err) 57904- } 57905- resp, err := server.FoldingRange(ctx, ¶ms) 57906- if err != nil { 57907- return true, reply(ctx, nil, err) 57908- } 57909- return true, reply(ctx, resp, nil) 57910- case "textDocument/formatting": 57911- var params DocumentFormattingParams 57912- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57913- return true, sendParseError(ctx, reply, err) 57914- } 57915- resp, err := server.Formatting(ctx, ¶ms) 57916- if err != nil { 57917- return true, reply(ctx, nil, err) 57918- } 57919- return true, reply(ctx, resp, nil) 57920- case "textDocument/hover": 57921- var params HoverParams 57922- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57923- return true, sendParseError(ctx, reply, err) 57924- } 57925- resp, err := server.Hover(ctx, ¶ms) 57926- if err != nil { 57927- return true, reply(ctx, nil, err) 57928- } 57929- return true, reply(ctx, resp, nil) 57930- case "textDocument/implementation": 57931- var params ImplementationParams 57932- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57933- return true, sendParseError(ctx, reply, err) 57934- } 57935- resp, err := server.Implementation(ctx, ¶ms) 57936- if err != nil { 57937- return true, reply(ctx, nil, err) 57938- } 57939- return true, reply(ctx, resp, nil) 57940- case "textDocument/inlayHint": 57941- var params InlayHintParams 57942- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57943- return true, sendParseError(ctx, reply, err) 57944- } 57945- resp, err := server.InlayHint(ctx, ¶ms) 57946- if err != nil { 57947- return true, reply(ctx, nil, err) 57948- } 57949- return true, reply(ctx, resp, nil) 57950- case "textDocument/inlineValue": 57951- var params InlineValueParams 57952- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57953- return true, sendParseError(ctx, reply, err) 57954- } 57955- resp, err := server.InlineValue(ctx, ¶ms) 57956- if err != nil { 57957- return true, reply(ctx, nil, err) 57958- } 57959- return true, reply(ctx, resp, nil) 57960- case "textDocument/linkedEditingRange": 57961- var params LinkedEditingRangeParams 57962- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57963- return true, sendParseError(ctx, reply, err) 57964- } 57965- resp, err := server.LinkedEditingRange(ctx, ¶ms) 57966- if err != nil { 57967- return true, reply(ctx, nil, err) 57968- } 57969- return true, reply(ctx, resp, nil) 57970- case "textDocument/moniker": 57971- var params MonikerParams 57972- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57973- return true, sendParseError(ctx, reply, err) 57974- } 57975- resp, err := server.Moniker(ctx, ¶ms) 57976- if err != nil { 57977- return true, reply(ctx, nil, err) 57978- } 57979- return true, reply(ctx, resp, nil) 57980- case "textDocument/onTypeFormatting": 57981- var params DocumentOnTypeFormattingParams 57982- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57983- return true, sendParseError(ctx, reply, err) 57984- } 57985- resp, err := server.OnTypeFormatting(ctx, ¶ms) 57986- if err != nil { 57987- return true, reply(ctx, nil, err) 57988- } 57989- return true, reply(ctx, resp, nil) 57990- case "textDocument/prepareCallHierarchy": 57991- var params CallHierarchyPrepareParams 57992- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 57993- return true, sendParseError(ctx, reply, err) 57994- } 57995- resp, err := server.PrepareCallHierarchy(ctx, ¶ms) 57996- if err != nil { 57997- return true, reply(ctx, nil, err) 57998- } 57999- return true, reply(ctx, resp, nil) 58000- case "textDocument/prepareRename": 58001- var params PrepareRenameParams 58002- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58003- return true, sendParseError(ctx, reply, err) 58004- } 58005- resp, err := server.PrepareRename(ctx, ¶ms) 58006- if err != nil { 58007- return true, reply(ctx, nil, err) 58008- } 58009- return true, reply(ctx, resp, nil) 58010- case "textDocument/prepareTypeHierarchy": 58011- var params TypeHierarchyPrepareParams 58012- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58013- return true, sendParseError(ctx, reply, err) 58014- } 58015- resp, err := server.PrepareTypeHierarchy(ctx, ¶ms) 58016- if err != nil { 58017- return true, reply(ctx, nil, err) 58018- } 58019- return true, reply(ctx, resp, nil) 58020- case "textDocument/rangeFormatting": 58021- var params DocumentRangeFormattingParams 58022- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58023- return true, sendParseError(ctx, reply, err) 58024- } 58025- resp, err := server.RangeFormatting(ctx, ¶ms) 58026- if err != nil { 58027- return true, reply(ctx, nil, err) 58028- } 58029- return true, reply(ctx, resp, nil) 58030- case "textDocument/references": 58031- var params ReferenceParams 58032- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58033- return true, sendParseError(ctx, reply, err) 58034- } 58035- resp, err := server.References(ctx, ¶ms) 58036- if err != nil { 58037- return true, reply(ctx, nil, err) 58038- } 58039- return true, reply(ctx, resp, nil) 58040- case "textDocument/rename": 58041- var params RenameParams 58042- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58043- return true, sendParseError(ctx, reply, err) 58044- } 58045- resp, err := server.Rename(ctx, ¶ms) 58046- if err != nil { 58047- return true, reply(ctx, nil, err) 58048- } 58049- return true, reply(ctx, resp, nil) 58050- case "textDocument/selectionRange": 58051- var params SelectionRangeParams 58052- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58053- return true, sendParseError(ctx, reply, err) 58054- } 58055- resp, err := server.SelectionRange(ctx, ¶ms) 58056- if err != nil { 58057- return true, reply(ctx, nil, err) 58058- } 58059- return true, reply(ctx, resp, nil) 58060- case "textDocument/semanticTokens/full": 58061- var params SemanticTokensParams 58062- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58063- return true, sendParseError(ctx, reply, err) 58064- } 58065- resp, err := server.SemanticTokensFull(ctx, ¶ms) 58066- if err != nil { 58067- return true, reply(ctx, nil, err) 58068- } 58069- return true, reply(ctx, resp, nil) 58070- case "textDocument/semanticTokens/full/delta": 58071- var params SemanticTokensDeltaParams 58072- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58073- return true, sendParseError(ctx, reply, err) 58074- } 58075- resp, err := server.SemanticTokensFullDelta(ctx, ¶ms) 58076- if err != nil { 58077- return true, reply(ctx, nil, err) 58078- } 58079- return true, reply(ctx, resp, nil) 58080- case "textDocument/semanticTokens/range": 58081- var params SemanticTokensRangeParams 58082- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58083- return true, sendParseError(ctx, reply, err) 58084- } 58085- resp, err := server.SemanticTokensRange(ctx, ¶ms) 58086- if err != nil { 58087- return true, reply(ctx, nil, err) 58088- } 58089- return true, reply(ctx, resp, nil) 58090- case "textDocument/signatureHelp": 58091- var params SignatureHelpParams 58092- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58093- return true, sendParseError(ctx, reply, err) 58094- } 58095- resp, err := server.SignatureHelp(ctx, ¶ms) 58096- if err != nil { 58097- return true, reply(ctx, nil, err) 58098- } 58099- return true, reply(ctx, resp, nil) 58100- case "textDocument/typeDefinition": 58101- var params TypeDefinitionParams 58102- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58103- return true, sendParseError(ctx, reply, err) 58104- } 58105- resp, err := server.TypeDefinition(ctx, ¶ms) 58106- if err != nil { 58107- return true, reply(ctx, nil, err) 58108- } 58109- return true, reply(ctx, resp, nil) 58110- case "textDocument/willSave": 58111- var params WillSaveTextDocumentParams 58112- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58113- return true, sendParseError(ctx, reply, err) 58114- } 58115- err := server.WillSave(ctx, ¶ms) 58116- return true, reply(ctx, nil, err) 58117- case "textDocument/willSaveWaitUntil": 58118- var params WillSaveTextDocumentParams 58119- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58120- return true, sendParseError(ctx, reply, err) 58121- } 58122- resp, err := server.WillSaveWaitUntil(ctx, ¶ms) 58123- if err != nil { 58124- return true, reply(ctx, nil, err) 58125- } 58126- return true, reply(ctx, resp, nil) 58127- case "typeHierarchy/subtypes": 58128- var params TypeHierarchySubtypesParams 58129- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58130- return true, sendParseError(ctx, reply, err) 58131- } 58132- resp, err := server.Subtypes(ctx, ¶ms) 58133- if err != nil { 58134- return true, reply(ctx, nil, err) 58135- } 58136- return true, reply(ctx, resp, nil) 58137- case "typeHierarchy/supertypes": 58138- var params TypeHierarchySupertypesParams 58139- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58140- return true, sendParseError(ctx, reply, err) 58141- } 58142- resp, err := server.Supertypes(ctx, ¶ms) 58143- if err != nil { 58144- return true, reply(ctx, nil, err) 58145- } 58146- return true, reply(ctx, resp, nil) 58147- case "window/workDoneProgress/cancel": 58148- var params WorkDoneProgressCancelParams 58149- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58150- return true, sendParseError(ctx, reply, err) 58151- } 58152- err := server.WorkDoneProgressCancel(ctx, ¶ms) 58153- return true, reply(ctx, nil, err) 58154- case "workspace/diagnostic": 58155- var params WorkspaceDiagnosticParams 58156- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58157- return true, sendParseError(ctx, reply, err) 58158- } 58159- resp, err := server.DiagnosticWorkspace(ctx, ¶ms) 58160- if err != nil { 58161- return true, reply(ctx, nil, err) 58162- } 58163- return true, reply(ctx, resp, nil) 58164- case "workspace/didChangeConfiguration": 58165- var params DidChangeConfigurationParams 58166- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58167- return true, sendParseError(ctx, reply, err) 58168- } 58169- err := server.DidChangeConfiguration(ctx, ¶ms) 58170- return true, reply(ctx, nil, err) 58171- case "workspace/didChangeWatchedFiles": 58172- var params DidChangeWatchedFilesParams 58173- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58174- return true, sendParseError(ctx, reply, err) 58175- } 58176- err := server.DidChangeWatchedFiles(ctx, ¶ms) 58177- return true, reply(ctx, nil, err) 58178- case "workspace/didChangeWorkspaceFolders": 58179- var params DidChangeWorkspaceFoldersParams 58180- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58181- return true, sendParseError(ctx, reply, err) 58182- } 58183- err := server.DidChangeWorkspaceFolders(ctx, ¶ms) 58184- return true, reply(ctx, nil, err) 58185- case "workspace/didCreateFiles": 58186- var params CreateFilesParams 58187- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58188- return true, sendParseError(ctx, reply, err) 58189- } 58190- err := server.DidCreateFiles(ctx, ¶ms) 58191- return true, reply(ctx, nil, err) 58192- case "workspace/didDeleteFiles": 58193- var params DeleteFilesParams 58194- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58195- return true, sendParseError(ctx, reply, err) 58196- } 58197- err := server.DidDeleteFiles(ctx, ¶ms) 58198- return true, reply(ctx, nil, err) 58199- case "workspace/didRenameFiles": 58200- var params RenameFilesParams 58201- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58202- return true, sendParseError(ctx, reply, err) 58203- } 58204- err := server.DidRenameFiles(ctx, ¶ms) 58205- return true, reply(ctx, nil, err) 58206- case "workspace/executeCommand": 58207- var params ExecuteCommandParams 58208- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58209- return true, sendParseError(ctx, reply, err) 58210- } 58211- resp, err := server.ExecuteCommand(ctx, ¶ms) 58212- if err != nil { 58213- return true, reply(ctx, nil, err) 58214- } 58215- return true, reply(ctx, resp, nil) 58216- case "workspace/symbol": 58217- var params WorkspaceSymbolParams 58218- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58219- return true, sendParseError(ctx, reply, err) 58220- } 58221- resp, err := server.Symbol(ctx, ¶ms) 58222- if err != nil { 58223- return true, reply(ctx, nil, err) 58224- } 58225- return true, reply(ctx, resp, nil) 58226- case "workspace/willCreateFiles": 58227- var params CreateFilesParams 58228- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58229- return true, sendParseError(ctx, reply, err) 58230- } 58231- resp, err := server.WillCreateFiles(ctx, ¶ms) 58232- if err != nil { 58233- return true, reply(ctx, nil, err) 58234- } 58235- return true, reply(ctx, resp, nil) 58236- case "workspace/willDeleteFiles": 58237- var params DeleteFilesParams 58238- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58239- return true, sendParseError(ctx, reply, err) 58240- } 58241- resp, err := server.WillDeleteFiles(ctx, ¶ms) 58242- if err != nil { 58243- return true, reply(ctx, nil, err) 58244- } 58245- return true, reply(ctx, resp, nil) 58246- case "workspace/willRenameFiles": 58247- var params RenameFilesParams 58248- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58249- return true, sendParseError(ctx, reply, err) 58250- } 58251- resp, err := server.WillRenameFiles(ctx, ¶ms) 58252- if err != nil { 58253- return true, reply(ctx, nil, err) 58254- } 58255- return true, reply(ctx, resp, nil) 58256- case "workspaceSymbol/resolve": 58257- var params WorkspaceSymbol 58258- if err := json.Unmarshal(r.Params(), ¶ms); err != nil { 58259- return true, sendParseError(ctx, reply, err) 58260- } 58261- resp, err := server.ResolveWorkspaceSymbol(ctx, ¶ms) 58262- if err != nil { 58263- return true, reply(ctx, nil, err) 58264- } 58265- return true, reply(ctx, resp, nil) 58266- default: 58267- return false, nil 58268- } 58269-} 58270- 58271-func (s *serverDispatcher) Progress(ctx context.Context, params *ProgressParams) error { 58272- return s.sender.Notify(ctx, "$/progress", params) 58273-} 58274-func (s *serverDispatcher) SetTrace(ctx context.Context, params *SetTraceParams) error { 58275- return s.sender.Notify(ctx, "$/setTrace", params) 58276-} 58277-func (s *serverDispatcher) IncomingCalls(ctx context.Context, params *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall, error) { 58278- var result []CallHierarchyIncomingCall 58279- if err := s.sender.Call(ctx, "callHierarchy/incomingCalls", params, &result); err != nil { 58280- return nil, err 58281- } 58282- return result, nil 58283-} 58284-func (s *serverDispatcher) OutgoingCalls(ctx context.Context, params *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall, error) { 58285- var result []CallHierarchyOutgoingCall 58286- if err := s.sender.Call(ctx, "callHierarchy/outgoingCalls", params, &result); err != nil { 58287- return nil, err 58288- } 58289- return result, nil 58290-} 58291-func (s *serverDispatcher) ResolveCodeAction(ctx context.Context, params *CodeAction) (*CodeAction, error) { 58292- var result *CodeAction 58293- if err := s.sender.Call(ctx, "codeAction/resolve", params, &result); err != nil { 58294- return nil, err 58295- } 58296- return result, nil 58297-} 58298-func (s *serverDispatcher) ResolveCodeLens(ctx context.Context, params *CodeLens) (*CodeLens, error) { 58299- var result *CodeLens 58300- if err := s.sender.Call(ctx, "codeLens/resolve", params, &result); err != nil { 58301- return nil, err 58302- } 58303- return result, nil 58304-} 58305-func (s *serverDispatcher) ResolveCompletionItem(ctx context.Context, params *CompletionItem) (*CompletionItem, error) { 58306- var result *CompletionItem 58307- if err := s.sender.Call(ctx, "completionItem/resolve", params, &result); err != nil { 58308- return nil, err 58309- } 58310- return result, nil 58311-} 58312-func (s *serverDispatcher) ResolveDocumentLink(ctx context.Context, params *DocumentLink) (*DocumentLink, error) { 58313- var result *DocumentLink 58314- if err := s.sender.Call(ctx, "documentLink/resolve", params, &result); err != nil { 58315- return nil, err 58316- } 58317- return result, nil 58318-} 58319-func (s *serverDispatcher) Exit(ctx context.Context) error { 58320- return s.sender.Notify(ctx, "exit", nil) 58321-} 58322-func (s *serverDispatcher) Initialize(ctx context.Context, params *ParamInitialize) (*InitializeResult, error) { 58323- var result *InitializeResult 58324- if err := s.sender.Call(ctx, "initialize", params, &result); err != nil { 58325- return nil, err 58326- } 58327- return result, nil 58328-} 58329-func (s *serverDispatcher) Initialized(ctx context.Context, params *InitializedParams) error { 58330- return s.sender.Notify(ctx, "initialized", params) 58331-} 58332-func (s *serverDispatcher) Resolve(ctx context.Context, params *InlayHint) (*InlayHint, error) { 58333- var result *InlayHint 58334- if err := s.sender.Call(ctx, "inlayHint/resolve", params, &result); err != nil { 58335- return nil, err 58336- } 58337- return result, nil 58338-} 58339-func (s *serverDispatcher) DidChangeNotebookDocument(ctx context.Context, params *DidChangeNotebookDocumentParams) error { 58340- return s.sender.Notify(ctx, "notebookDocument/didChange", params) 58341-} 58342-func (s *serverDispatcher) DidCloseNotebookDocument(ctx context.Context, params *DidCloseNotebookDocumentParams) error { 58343- return s.sender.Notify(ctx, "notebookDocument/didClose", params) 58344-} 58345-func (s *serverDispatcher) DidOpenNotebookDocument(ctx context.Context, params *DidOpenNotebookDocumentParams) error { 58346- return s.sender.Notify(ctx, "notebookDocument/didOpen", params) 58347-} 58348-func (s *serverDispatcher) DidSaveNotebookDocument(ctx context.Context, params *DidSaveNotebookDocumentParams) error { 58349- return s.sender.Notify(ctx, "notebookDocument/didSave", params) 58350-} 58351-func (s *serverDispatcher) Shutdown(ctx context.Context) error { 58352- return s.sender.Call(ctx, "shutdown", nil, nil) 58353-} 58354-func (s *serverDispatcher) CodeAction(ctx context.Context, params *CodeActionParams) ([]CodeAction, error) { 58355- var result []CodeAction 58356- if err := s.sender.Call(ctx, "textDocument/codeAction", params, &result); err != nil { 58357- return nil, err 58358- } 58359- return result, nil 58360-} 58361-func (s *serverDispatcher) CodeLens(ctx context.Context, params *CodeLensParams) ([]CodeLens, error) { 58362- var result []CodeLens 58363- if err := s.sender.Call(ctx, "textDocument/codeLens", params, &result); err != nil { 58364- return nil, err 58365- } 58366- return result, nil 58367-} 58368-func (s *serverDispatcher) ColorPresentation(ctx context.Context, params *ColorPresentationParams) ([]ColorPresentation, error) { 58369- var result []ColorPresentation 58370- if err := s.sender.Call(ctx, "textDocument/colorPresentation", params, &result); err != nil { 58371- return nil, err 58372- } 58373- return result, nil 58374-} 58375-func (s *serverDispatcher) Completion(ctx context.Context, params *CompletionParams) (*CompletionList, error) { 58376- var result *CompletionList 58377- if err := s.sender.Call(ctx, "textDocument/completion", params, &result); err != nil { 58378- return nil, err 58379- } 58380- return result, nil 58381-} 58382-func (s *serverDispatcher) Declaration(ctx context.Context, params *DeclarationParams) (*Or_textDocument_declaration, error) { 58383- var result *Or_textDocument_declaration 58384- if err := s.sender.Call(ctx, "textDocument/declaration", params, &result); err != nil { 58385- return nil, err 58386- } 58387- return result, nil 58388-} 58389-func (s *serverDispatcher) Definition(ctx context.Context, params *DefinitionParams) ([]Location, error) { 58390- var result []Location 58391- if err := s.sender.Call(ctx, "textDocument/definition", params, &result); err != nil { 58392- return nil, err 58393- } 58394- return result, nil 58395-} 58396-func (s *serverDispatcher) Diagnostic(ctx context.Context, params *string) (*string, error) { 58397- var result *string 58398- if err := s.sender.Call(ctx, "textDocument/diagnostic", params, &result); err != nil { 58399- return nil, err 58400- } 58401- return result, nil 58402-} 58403-func (s *serverDispatcher) DidChange(ctx context.Context, params *DidChangeTextDocumentParams) error { 58404- return s.sender.Notify(ctx, "textDocument/didChange", params) 58405-} 58406-func (s *serverDispatcher) DidClose(ctx context.Context, params *DidCloseTextDocumentParams) error { 58407- return s.sender.Notify(ctx, "textDocument/didClose", params) 58408-} 58409-func (s *serverDispatcher) DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) error { 58410- return s.sender.Notify(ctx, "textDocument/didOpen", params) 58411-} 58412-func (s *serverDispatcher) DidSave(ctx context.Context, params *DidSaveTextDocumentParams) error { 58413- return s.sender.Notify(ctx, "textDocument/didSave", params) 58414-} 58415-func (s *serverDispatcher) DocumentColor(ctx context.Context, params *DocumentColorParams) ([]ColorInformation, error) { 58416- var result []ColorInformation 58417- if err := s.sender.Call(ctx, "textDocument/documentColor", params, &result); err != nil { 58418- return nil, err 58419- } 58420- return result, nil 58421-} 58422-func (s *serverDispatcher) DocumentHighlight(ctx context.Context, params *DocumentHighlightParams) ([]DocumentHighlight, error) { 58423- var result []DocumentHighlight 58424- if err := s.sender.Call(ctx, "textDocument/documentHighlight", params, &result); err != nil { 58425- return nil, err 58426- } 58427- return result, nil 58428-} 58429-func (s *serverDispatcher) DocumentLink(ctx context.Context, params *DocumentLinkParams) ([]DocumentLink, error) { 58430- var result []DocumentLink 58431- if err := s.sender.Call(ctx, "textDocument/documentLink", params, &result); err != nil { 58432- return nil, err 58433- } 58434- return result, nil 58435-} 58436-func (s *serverDispatcher) DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) ([]interface{}, error) { 58437- var result []interface{} 58438- if err := s.sender.Call(ctx, "textDocument/documentSymbol", params, &result); err != nil { 58439- return nil, err 58440- } 58441- return result, nil 58442-} 58443-func (s *serverDispatcher) FoldingRange(ctx context.Context, params *FoldingRangeParams) ([]FoldingRange, error) { 58444- var result []FoldingRange 58445- if err := s.sender.Call(ctx, "textDocument/foldingRange", params, &result); err != nil { 58446- return nil, err 58447- } 58448- return result, nil 58449-} 58450-func (s *serverDispatcher) Formatting(ctx context.Context, params *DocumentFormattingParams) ([]TextEdit, error) { 58451- var result []TextEdit 58452- if err := s.sender.Call(ctx, "textDocument/formatting", params, &result); err != nil { 58453- return nil, err 58454- } 58455- return result, nil 58456-} 58457-func (s *serverDispatcher) Hover(ctx context.Context, params *HoverParams) (*Hover, error) { 58458- var result *Hover 58459- if err := s.sender.Call(ctx, "textDocument/hover", params, &result); err != nil { 58460- return nil, err 58461- } 58462- return result, nil 58463-} 58464-func (s *serverDispatcher) Implementation(ctx context.Context, params *ImplementationParams) ([]Location, error) { 58465- var result []Location 58466- if err := s.sender.Call(ctx, "textDocument/implementation", params, &result); err != nil { 58467- return nil, err 58468- } 58469- return result, nil 58470-} 58471-func (s *serverDispatcher) InlayHint(ctx context.Context, params *InlayHintParams) ([]InlayHint, error) { 58472- var result []InlayHint 58473- if err := s.sender.Call(ctx, "textDocument/inlayHint", params, &result); err != nil { 58474- return nil, err 58475- } 58476- return result, nil 58477-} 58478-func (s *serverDispatcher) InlineValue(ctx context.Context, params *InlineValueParams) ([]InlineValue, error) { 58479- var result []InlineValue 58480- if err := s.sender.Call(ctx, "textDocument/inlineValue", params, &result); err != nil { 58481- return nil, err 58482- } 58483- return result, nil 58484-} 58485-func (s *serverDispatcher) LinkedEditingRange(ctx context.Context, params *LinkedEditingRangeParams) (*LinkedEditingRanges, error) { 58486- var result *LinkedEditingRanges 58487- if err := s.sender.Call(ctx, "textDocument/linkedEditingRange", params, &result); err != nil { 58488- return nil, err 58489- } 58490- return result, nil 58491-} 58492-func (s *serverDispatcher) Moniker(ctx context.Context, params *MonikerParams) ([]Moniker, error) { 58493- var result []Moniker 58494- if err := s.sender.Call(ctx, "textDocument/moniker", params, &result); err != nil { 58495- return nil, err 58496- } 58497- return result, nil 58498-} 58499-func (s *serverDispatcher) OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) ([]TextEdit, error) { 58500- var result []TextEdit 58501- if err := s.sender.Call(ctx, "textDocument/onTypeFormatting", params, &result); err != nil { 58502- return nil, err 58503- } 58504- return result, nil 58505-} 58506-func (s *serverDispatcher) PrepareCallHierarchy(ctx context.Context, params *CallHierarchyPrepareParams) ([]CallHierarchyItem, error) { 58507- var result []CallHierarchyItem 58508- if err := s.sender.Call(ctx, "textDocument/prepareCallHierarchy", params, &result); err != nil { 58509- return nil, err 58510- } 58511- return result, nil 58512-} 58513-func (s *serverDispatcher) PrepareRename(ctx context.Context, params *PrepareRenameParams) (*PrepareRename2Gn, error) { 58514- var result *PrepareRename2Gn 58515- if err := s.sender.Call(ctx, "textDocument/prepareRename", params, &result); err != nil { 58516- return nil, err 58517- } 58518- return result, nil 58519-} 58520-func (s *serverDispatcher) PrepareTypeHierarchy(ctx context.Context, params *TypeHierarchyPrepareParams) ([]TypeHierarchyItem, error) { 58521- var result []TypeHierarchyItem 58522- if err := s.sender.Call(ctx, "textDocument/prepareTypeHierarchy", params, &result); err != nil { 58523- return nil, err 58524- } 58525- return result, nil 58526-} 58527-func (s *serverDispatcher) RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) ([]TextEdit, error) { 58528- var result []TextEdit 58529- if err := s.sender.Call(ctx, "textDocument/rangeFormatting", params, &result); err != nil { 58530- return nil, err 58531- } 58532- return result, nil 58533-} 58534-func (s *serverDispatcher) References(ctx context.Context, params *ReferenceParams) ([]Location, error) { 58535- var result []Location 58536- if err := s.sender.Call(ctx, "textDocument/references", params, &result); err != nil { 58537- return nil, err 58538- } 58539- return result, nil 58540-} 58541-func (s *serverDispatcher) Rename(ctx context.Context, params *RenameParams) (*WorkspaceEdit, error) { 58542- var result *WorkspaceEdit 58543- if err := s.sender.Call(ctx, "textDocument/rename", params, &result); err != nil { 58544- return nil, err 58545- } 58546- return result, nil 58547-} 58548-func (s *serverDispatcher) SelectionRange(ctx context.Context, params *SelectionRangeParams) ([]SelectionRange, error) { 58549- var result []SelectionRange 58550- if err := s.sender.Call(ctx, "textDocument/selectionRange", params, &result); err != nil { 58551- return nil, err 58552- } 58553- return result, nil 58554-} 58555-func (s *serverDispatcher) SemanticTokensFull(ctx context.Context, params *SemanticTokensParams) (*SemanticTokens, error) { 58556- var result *SemanticTokens 58557- if err := s.sender.Call(ctx, "textDocument/semanticTokens/full", params, &result); err != nil { 58558- return nil, err 58559- } 58560- return result, nil 58561-} 58562-func (s *serverDispatcher) SemanticTokensFullDelta(ctx context.Context, params *SemanticTokensDeltaParams) (interface{}, error) { 58563- var result interface{} 58564- if err := s.sender.Call(ctx, "textDocument/semanticTokens/full/delta", params, &result); err != nil { 58565- return nil, err 58566- } 58567- return result, nil 58568-} 58569-func (s *serverDispatcher) SemanticTokensRange(ctx context.Context, params *SemanticTokensRangeParams) (*SemanticTokens, error) { 58570- var result *SemanticTokens 58571- if err := s.sender.Call(ctx, "textDocument/semanticTokens/range", params, &result); err != nil { 58572- return nil, err 58573- } 58574- return result, nil 58575-} 58576-func (s *serverDispatcher) SignatureHelp(ctx context.Context, params *SignatureHelpParams) (*SignatureHelp, error) { 58577- var result *SignatureHelp 58578- if err := s.sender.Call(ctx, "textDocument/signatureHelp", params, &result); err != nil { 58579- return nil, err 58580- } 58581- return result, nil 58582-} 58583-func (s *serverDispatcher) TypeDefinition(ctx context.Context, params *TypeDefinitionParams) ([]Location, error) { 58584- var result []Location 58585- if err := s.sender.Call(ctx, "textDocument/typeDefinition", params, &result); err != nil { 58586- return nil, err 58587- } 58588- return result, nil 58589-} 58590-func (s *serverDispatcher) WillSave(ctx context.Context, params *WillSaveTextDocumentParams) error { 58591- return s.sender.Notify(ctx, "textDocument/willSave", params) 58592-} 58593-func (s *serverDispatcher) WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) ([]TextEdit, error) { 58594- var result []TextEdit 58595- if err := s.sender.Call(ctx, "textDocument/willSaveWaitUntil", params, &result); err != nil { 58596- return nil, err 58597- } 58598- return result, nil 58599-} 58600-func (s *serverDispatcher) Subtypes(ctx context.Context, params *TypeHierarchySubtypesParams) ([]TypeHierarchyItem, error) { 58601- var result []TypeHierarchyItem 58602- if err := s.sender.Call(ctx, "typeHierarchy/subtypes", params, &result); err != nil { 58603- return nil, err 58604- } 58605- return result, nil 58606-} 58607-func (s *serverDispatcher) Supertypes(ctx context.Context, params *TypeHierarchySupertypesParams) ([]TypeHierarchyItem, error) { 58608- var result []TypeHierarchyItem 58609- if err := s.sender.Call(ctx, "typeHierarchy/supertypes", params, &result); err != nil { 58610- return nil, err 58611- } 58612- return result, nil 58613-} 58614-func (s *serverDispatcher) WorkDoneProgressCancel(ctx context.Context, params *WorkDoneProgressCancelParams) error { 58615- return s.sender.Notify(ctx, "window/workDoneProgress/cancel", params) 58616-} 58617-func (s *serverDispatcher) DiagnosticWorkspace(ctx context.Context, params *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error) { 58618- var result *WorkspaceDiagnosticReport 58619- if err := s.sender.Call(ctx, "workspace/diagnostic", params, &result); err != nil { 58620- return nil, err 58621- } 58622- return result, nil 58623-} 58624-func (s *serverDispatcher) DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) error { 58625- return s.sender.Notify(ctx, "workspace/didChangeConfiguration", params) 58626-} 58627-func (s *serverDispatcher) DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) error { 58628- return s.sender.Notify(ctx, "workspace/didChangeWatchedFiles", params) 58629-} 58630-func (s *serverDispatcher) DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) error { 58631- return s.sender.Notify(ctx, "workspace/didChangeWorkspaceFolders", params) 58632-} 58633-func (s *serverDispatcher) DidCreateFiles(ctx context.Context, params *CreateFilesParams) error { 58634- return s.sender.Notify(ctx, "workspace/didCreateFiles", params) 58635-} 58636-func (s *serverDispatcher) DidDeleteFiles(ctx context.Context, params *DeleteFilesParams) error { 58637- return s.sender.Notify(ctx, "workspace/didDeleteFiles", params) 58638-} 58639-func (s *serverDispatcher) DidRenameFiles(ctx context.Context, params *RenameFilesParams) error { 58640- return s.sender.Notify(ctx, "workspace/didRenameFiles", params) 58641-} 58642-func (s *serverDispatcher) ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (interface{}, error) { 58643- var result interface{} 58644- if err := s.sender.Call(ctx, "workspace/executeCommand", params, &result); err != nil { 58645- return nil, err 58646- } 58647- return result, nil 58648-} 58649-func (s *serverDispatcher) Symbol(ctx context.Context, params *WorkspaceSymbolParams) ([]SymbolInformation, error) { 58650- var result []SymbolInformation 58651- if err := s.sender.Call(ctx, "workspace/symbol", params, &result); err != nil { 58652- return nil, err 58653- } 58654- return result, nil 58655-} 58656-func (s *serverDispatcher) WillCreateFiles(ctx context.Context, params *CreateFilesParams) (*WorkspaceEdit, error) { 58657- var result *WorkspaceEdit 58658- if err := s.sender.Call(ctx, "workspace/willCreateFiles", params, &result); err != nil { 58659- return nil, err 58660- } 58661- return result, nil 58662-} 58663-func (s *serverDispatcher) WillDeleteFiles(ctx context.Context, params *DeleteFilesParams) (*WorkspaceEdit, error) { 58664- var result *WorkspaceEdit 58665- if err := s.sender.Call(ctx, "workspace/willDeleteFiles", params, &result); err != nil { 58666- return nil, err 58667- } 58668- return result, nil 58669-} 58670-func (s *serverDispatcher) WillRenameFiles(ctx context.Context, params *RenameFilesParams) (*WorkspaceEdit, error) { 58671- var result *WorkspaceEdit 58672- if err := s.sender.Call(ctx, "workspace/willRenameFiles", params, &result); err != nil { 58673- return nil, err 58674- } 58675- return result, nil 58676-} 58677-func (s *serverDispatcher) ResolveWorkspaceSymbol(ctx context.Context, params *WorkspaceSymbol) (*WorkspaceSymbol, error) { 58678- var result *WorkspaceSymbol 58679- if err := s.sender.Call(ctx, "workspaceSymbol/resolve", params, &result); err != nil { 58680- return nil, err 58681- } 58682- return result, nil 58683-} 58684-func (s *serverDispatcher) NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) { 58685- var result interface{} 58686- if err := s.sender.Call(ctx, method, params, &result); err != nil { 58687- return nil, err 58688- } 58689- return result, nil 58690-} 58691diff -urN a/gopls/internal/lsp/README.md b/gopls/internal/lsp/README.md 58692--- a/gopls/internal/lsp/README.md 2000-01-01 00:00:00.000000000 -0000 58693+++ b/gopls/internal/lsp/README.md 1970-01-01 00:00:00.000000000 +0000 58694@@ -1,7 +0,0 @@ 58695-# lsp 58696- 58697-internal/lsp provides much of the Language Server Protocol (lsp) implementation 58698-for gopls. 58699- 58700-Documentation for users and contributors can be found in the 58701-[`gopls/doc`](../../gopls/doc) directory. 58702diff -urN a/gopls/internal/lsp/references.go b/gopls/internal/lsp/references.go 58703--- a/gopls/internal/lsp/references.go 2000-01-01 00:00:00.000000000 -0000 58704+++ b/gopls/internal/lsp/references.go 1970-01-01 00:00:00.000000000 +0000 58705@@ -1,25 +0,0 @@ 58706-// Copyright 2019 The Go Authors. All rights reserved. 58707-// Use of this source code is governed by a BSD-style 58708-// license that can be found in the LICENSE file. 58709- 58710-package lsp 58711- 58712-import ( 58713- "context" 58714- 58715- "golang.org/x/tools/gopls/internal/lsp/protocol" 58716- "golang.org/x/tools/gopls/internal/lsp/source" 58717- "golang.org/x/tools/gopls/internal/lsp/template" 58718-) 58719- 58720-func (s *Server) references(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) { 58721- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 58722- defer release() 58723- if !ok { 58724- return nil, err 58725- } 58726- if snapshot.View().FileKind(fh) == source.Tmpl { 58727- return template.References(ctx, snapshot, fh, params) 58728- } 58729- return source.References(ctx, snapshot, fh, params.Position, params.Context.IncludeDeclaration) 58730-} 58731diff -urN a/gopls/internal/lsp/regtest/doc.go b/gopls/internal/lsp/regtest/doc.go 58732--- a/gopls/internal/lsp/regtest/doc.go 2000-01-01 00:00:00.000000000 -0000 58733+++ b/gopls/internal/lsp/regtest/doc.go 1970-01-01 00:00:00.000000000 +0000 58734@@ -1,157 +0,0 @@ 58735-// Copyright 2020 The Go Authors. All rights reserved. 58736-// Use of this source code is governed by a BSD-style 58737-// license that can be found in the LICENSE file. 58738- 58739-// Package regtest provides a framework for writing gopls regression tests. 58740-// 58741-// User reported regressions are often expressed in terms of editor 58742-// interactions. For example: "When I open my editor in this directory, 58743-// navigate to this file, and change this line, I get a diagnostic that doesn't 58744-// make sense". In these cases reproducing, diagnosing, and writing a test to 58745-// protect against this regression can be difficult. 58746-// 58747-// The regtest package provides an API for developers to express these types of 58748-// user interactions in ordinary Go tests, validate them, and run them in a 58749-// variety of execution modes. 58750-// 58751-// # Test package setup 58752-// 58753-// The regression test package uses a couple of uncommon patterns to reduce 58754-// boilerplate in test bodies. First, it is intended to be imported as "." so 58755-// that helpers do not need to be qualified. Second, it requires some setup 58756-// that is currently implemented in the regtest.Main function, which must be 58757-// invoked by TestMain. Therefore, a minimal regtest testing package looks 58758-// like this: 58759-// 58760-// package lsptests 58761-// 58762-// import ( 58763-// "fmt" 58764-// "testing" 58765-// 58766-// "golang.org/x/tools/gopls/internal/hooks" 58767-// . "golang.org/x/tools/gopls/internal/lsp/regtest" 58768-// ) 58769-// 58770-// func TestMain(m *testing.M) { 58771-// Main(m, hooks.Options) 58772-// } 58773-// 58774-// # Writing a simple regression test 58775-// 58776-// To run a regression test use the regtest.Run function, which accepts a 58777-// txtar-encoded archive defining the initial workspace state. This function 58778-// sets up the workspace in a temporary directory, creates a fake text editor, 58779-// starts gopls, and initializes an LSP session. It then invokes the provided 58780-// test function with an *Env handle encapsulating the newly created 58781-// environment. Because gopls may be run in various modes (as a sidecar or 58782-// daemon process, with different settings), the test runner may perform this 58783-// process multiple times, re-running the test function each time with a new 58784-// environment. 58785-// 58786-// func TestOpenFile(t *testing.T) { 58787-// const files = ` 58788-// -- go.mod -- 58789-// module mod.com 58790-// 58791-// go 1.12 58792-// -- foo.go -- 58793-// package foo 58794-// ` 58795-// Run(t, files, func(t *testing.T, env *Env) { 58796-// env.OpenFile("foo.go") 58797-// }) 58798-// } 58799-// 58800-// # Configuring Regtest Execution 58801-// 58802-// The regtest package exposes several options that affect the setup process 58803-// described above. To use these options, use the WithOptions function: 58804-// 58805-// WithOptions(opts...).Run(...) 58806-// 58807-// See options.go for a full list of available options. 58808-// 58809-// # Operating on editor state 58810-// 58811-// To operate on editor state within the test body, the Env type provides 58812-// access to the workspace directory (Env.SandBox), text editor (Env.Editor), 58813-// LSP server (Env.Server), and 'awaiter' (Env.Awaiter). 58814-// 58815-// In most cases, operations on these primitive building blocks of the 58816-// regression test environment expect a Context (which should be a child of 58817-// env.Ctx), and return an error. To avoid boilerplate, the Env exposes a set 58818-// of wrappers in wrappers.go for use in scripting: 58819-// 58820-// env.CreateBuffer("c/c.go", "") 58821-// env.EditBuffer("c/c.go", fake.Edit{ 58822-// Text: `package c`, 58823-// }) 58824-// 58825-// These wrappers thread through Env.Ctx, and call t.Fatal on any errors. 58826-// 58827-// # Expressing expectations 58828-// 58829-// The general pattern for a regression test is to script interactions with the 58830-// fake editor and sandbox, and assert that gopls behaves correctly after each 58831-// state change. Unfortunately, this is complicated by the fact that state 58832-// changes are communicated to gopls via unidirectional client->server 58833-// notifications (didOpen, didChange, etc.), and resulting gopls behavior such 58834-// as diagnostics, logs, or messages is communicated back via server->client 58835-// notifications. Therefore, within regression tests we must be able to say "do 58836-// this, and then eventually gopls should do that". To achieve this, the 58837-// regtest package provides a framework for expressing conditions that must 58838-// eventually be met, in terms of the Expectation type. 58839-// 58840-// To express the assertion that "eventually gopls must meet these 58841-// expectations", use env.Await(...): 58842-// 58843-// env.RegexpReplace("x/x.go", `package x`, `package main`) 58844-// env.Await(env.DiagnosticAtRegexp("x/main.go", `fmt`)) 58845-// 58846-// Await evaluates the provided expectations atomically, whenever the client 58847-// receives a state-changing notification from gopls. See expectation.go for a 58848-// full list of available expectations. 58849-// 58850-// A fundamental problem with this model is that if gopls never meets the 58851-// provided expectations, the test runner will hang until the test timeout 58852-// (which defaults to 10m). There are two ways to work around this poor 58853-// behavior: 58854-// 58855-// 1. Use a precondition to define precisely when we expect conditions to be 58856-// met. Gopls provides the OnceMet(precondition, expectations...) pattern 58857-// to express ("once this precondition is met, the following expectations 58858-// must all hold"). To instrument preconditions, gopls uses verbose 58859-// progress notifications to inform the client about ongoing work (see 58860-// CompletedWork). The most common precondition is to wait for gopls to be 58861-// done processing all change notifications, for which the regtest package 58862-// provides the AfterChange helper. For example: 58863-// 58864-// // We expect diagnostics to be cleared after gopls is done processing the 58865-// // didSave notification. 58866-// env.SaveBuffer("a/go.mod") 58867-// env.AfterChange(EmptyDiagnostics("a/go.mod")) 58868-// 58869-// 2. Set a shorter timeout during development, if you expect to be breaking 58870-// tests. By setting the environment variable GOPLS_REGTEST_TIMEOUT=5s, 58871-// regression tests will time out after 5 seconds. 58872-// 58873-// # Tips & Tricks 58874-// 58875-// Here are some tips and tricks for working with regression tests: 58876-// 58877-// 1. Set the environment variable GOPLS_REGTEST_TIMEOUT=5s during development. 58878-// 2. Run tests with -short. This will only run regression tests in the 58879-// default gopls execution mode. 58880-// 3. Use capture groups to narrow regexp positions. All regular-expression 58881-// based positions (such as DiagnosticAtRegexp) will match the position of 58882-// the first capture group, if any are provided. This can be used to 58883-// identify a specific position in the code for a pattern that may occur in 58884-// multiple places. For example `var (mu) sync.Mutex` matches the position 58885-// of "mu" within the variable declaration. 58886-// 4. Read diagnostics into a variable to implement more complicated 58887-// assertions about diagnostic state in the editor. To do this, use the 58888-// pattern OnceMet(precondition, ReadDiagnostics("file.go", &d)) to capture 58889-// the current diagnostics as soon as the precondition is met. This is 58890-// preferable to accessing the diagnostics directly, as it avoids races. 58891-package regtest 58892diff -urN a/gopls/internal/lsp/regtest/env.go b/gopls/internal/lsp/regtest/env.go 58893--- a/gopls/internal/lsp/regtest/env.go 2000-01-01 00:00:00.000000000 -0000 58894+++ b/gopls/internal/lsp/regtest/env.go 1970-01-01 00:00:00.000000000 +0000 58895@@ -1,391 +0,0 @@ 58896-// Copyright 2020 The Go Authors. All rights reserved. 58897-// Use of this source code is governed by a BSD-style 58898-// license that can be found in the LICENSE file. 58899- 58900-package regtest 58901- 58902-import ( 58903- "context" 58904- "fmt" 58905- "strings" 58906- "sync" 58907- "testing" 58908- 58909- "golang.org/x/tools/gopls/internal/lsp/fake" 58910- "golang.org/x/tools/gopls/internal/lsp/protocol" 58911- "golang.org/x/tools/internal/jsonrpc2/servertest" 58912-) 58913- 58914-// Env holds the building blocks of an editor testing environment, providing 58915-// wrapper methods that hide the boilerplate of plumbing contexts and checking 58916-// errors. 58917-type Env struct { 58918- T testing.TB // TODO(rfindley): rename to TB 58919- Ctx context.Context 58920- 58921- // Most tests should not need to access the scratch area, editor, server, or 58922- // connection, but they are available if needed. 58923- Sandbox *fake.Sandbox 58924- Server servertest.Connector 58925- 58926- // Editor is owned by the Env, and shut down 58927- Editor *fake.Editor 58928- 58929- Awaiter *Awaiter 58930-} 58931- 58932-// An Awaiter keeps track of relevant LSP state, so that it may be asserted 58933-// upon with Expectations. 58934-// 58935-// Wire it into a fake.Editor using Awaiter.Hooks(). 58936-// 58937-// TODO(rfindley): consider simply merging Awaiter with the fake.Editor. It 58938-// probably is not worth its own abstraction. 58939-type Awaiter struct { 58940- workdir *fake.Workdir 58941- 58942- mu sync.Mutex 58943- // For simplicity, each waiter gets a unique ID. 58944- nextWaiterID int 58945- state State 58946- waiters map[int]*condition 58947-} 58948- 58949-func NewAwaiter(workdir *fake.Workdir) *Awaiter { 58950- return &Awaiter{ 58951- workdir: workdir, 58952- state: State{ 58953- diagnostics: make(map[string]*protocol.PublishDiagnosticsParams), 58954- work: make(map[protocol.ProgressToken]*workProgress), 58955- }, 58956- waiters: make(map[int]*condition), 58957- } 58958-} 58959- 58960-// Hooks returns LSP client hooks required for awaiting asynchronous expectations. 58961-func (a *Awaiter) Hooks() fake.ClientHooks { 58962- return fake.ClientHooks{ 58963- OnDiagnostics: a.onDiagnostics, 58964- OnLogMessage: a.onLogMessage, 58965- OnWorkDoneProgressCreate: a.onWorkDoneProgressCreate, 58966- OnProgress: a.onProgress, 58967- OnShowMessage: a.onShowMessage, 58968- OnShowMessageRequest: a.onShowMessageRequest, 58969- OnRegisterCapability: a.onRegisterCapability, 58970- OnUnregisterCapability: a.onUnregisterCapability, 58971- OnApplyEdit: a.onApplyEdit, 58972- } 58973-} 58974- 58975-// State encapsulates the server state TODO: explain more 58976-type State struct { 58977- // diagnostics are a map of relative path->diagnostics params 58978- diagnostics map[string]*protocol.PublishDiagnosticsParams 58979- logs []*protocol.LogMessageParams 58980- showMessage []*protocol.ShowMessageParams 58981- showMessageRequest []*protocol.ShowMessageRequestParams 58982- 58983- registrations []*protocol.RegistrationParams 58984- registeredCapabilities map[string]protocol.Registration 58985- unregistrations []*protocol.UnregistrationParams 58986- documentChanges []protocol.DocumentChanges // collected from ApplyEdit downcalls 58987- 58988- // outstandingWork is a map of token->work summary. All tokens are assumed to 58989- // be string, though the spec allows for numeric tokens as well. When work 58990- // completes, it is deleted from this map. 58991- work map[protocol.ProgressToken]*workProgress 58992-} 58993- 58994-// outstandingWork counts started but not complete work items by title. 58995-func (s State) outstandingWork() map[string]uint64 { 58996- outstanding := make(map[string]uint64) 58997- for _, work := range s.work { 58998- if !work.complete { 58999- outstanding[work.title]++ 59000- } 59001- } 59002- return outstanding 59003-} 59004- 59005-// completedWork counts complete work items by title. 59006-func (s State) completedWork() map[string]uint64 { 59007- completed := make(map[string]uint64) 59008- for _, work := range s.work { 59009- if work.complete { 59010- completed[work.title]++ 59011- } 59012- } 59013- return completed 59014-} 59015- 59016-// startedWork counts started (and possibly complete) work items. 59017-func (s State) startedWork() map[string]uint64 { 59018- started := make(map[string]uint64) 59019- for _, work := range s.work { 59020- started[work.title]++ 59021- } 59022- return started 59023-} 59024- 59025-type workProgress struct { 59026- title, msg, endMsg string 59027- percent float64 59028- complete bool // seen 'end'. 59029-} 59030- 59031-// This method, provided for debugging, accesses mutable fields without a lock, 59032-// so it must not be called concurrent with any State mutation. 59033-func (s State) String() string { 59034- var b strings.Builder 59035- b.WriteString("#### log messages (see RPC logs for full text):\n") 59036- for _, msg := range s.logs { 59037- summary := fmt.Sprintf("%v: %q", msg.Type, msg.Message) 59038- if len(summary) > 60 { 59039- summary = summary[:57] + "..." 59040- } 59041- // Some logs are quite long, and since they should be reproduced in the RPC 59042- // logs on any failure we include here just a short summary. 59043- fmt.Fprint(&b, "\t"+summary+"\n") 59044- } 59045- b.WriteString("\n") 59046- b.WriteString("#### diagnostics:\n") 59047- for name, params := range s.diagnostics { 59048- fmt.Fprintf(&b, "\t%s (version %d):\n", name, int(params.Version)) 59049- for _, d := range params.Diagnostics { 59050- fmt.Fprintf(&b, "\t\t(%d, %d) [%s]: %s\n", int(d.Range.Start.Line), int(d.Range.Start.Character), d.Source, d.Message) 59051- } 59052- } 59053- b.WriteString("\n") 59054- b.WriteString("#### outstanding work:\n") 59055- for token, state := range s.work { 59056- if state.complete { 59057- continue 59058- } 59059- name := state.title 59060- if name == "" { 59061- name = fmt.Sprintf("!NO NAME(token: %s)", token) 59062- } 59063- fmt.Fprintf(&b, "\t%s: %.2f\n", name, state.percent) 59064- } 59065- b.WriteString("#### completed work:\n") 59066- for name, count := range s.completedWork() { 59067- fmt.Fprintf(&b, "\t%s: %d\n", name, count) 59068- } 59069- return b.String() 59070-} 59071- 59072-// A condition is satisfied when all expectations are simultaneously 59073-// met. At that point, the 'met' channel is closed. On any failure, err is set 59074-// and the failed channel is closed. 59075-type condition struct { 59076- expectations []Expectation 59077- verdict chan Verdict 59078-} 59079- 59080-func (a *Awaiter) onApplyEdit(_ context.Context, params *protocol.ApplyWorkspaceEditParams) error { 59081- a.mu.Lock() 59082- defer a.mu.Unlock() 59083- 59084- a.state.documentChanges = append(a.state.documentChanges, params.Edit.DocumentChanges...) 59085- a.checkConditionsLocked() 59086- return nil 59087-} 59088- 59089-func (a *Awaiter) onDiagnostics(_ context.Context, d *protocol.PublishDiagnosticsParams) error { 59090- a.mu.Lock() 59091- defer a.mu.Unlock() 59092- 59093- pth := a.workdir.URIToPath(d.URI) 59094- a.state.diagnostics[pth] = d 59095- a.checkConditionsLocked() 59096- return nil 59097-} 59098- 59099-func (a *Awaiter) onShowMessage(_ context.Context, m *protocol.ShowMessageParams) error { 59100- a.mu.Lock() 59101- defer a.mu.Unlock() 59102- 59103- a.state.showMessage = append(a.state.showMessage, m) 59104- a.checkConditionsLocked() 59105- return nil 59106-} 59107- 59108-func (a *Awaiter) onShowMessageRequest(_ context.Context, m *protocol.ShowMessageRequestParams) error { 59109- a.mu.Lock() 59110- defer a.mu.Unlock() 59111- 59112- a.state.showMessageRequest = append(a.state.showMessageRequest, m) 59113- a.checkConditionsLocked() 59114- return nil 59115-} 59116- 59117-func (a *Awaiter) onLogMessage(_ context.Context, m *protocol.LogMessageParams) error { 59118- a.mu.Lock() 59119- defer a.mu.Unlock() 59120- 59121- a.state.logs = append(a.state.logs, m) 59122- a.checkConditionsLocked() 59123- return nil 59124-} 59125- 59126-func (a *Awaiter) onWorkDoneProgressCreate(_ context.Context, m *protocol.WorkDoneProgressCreateParams) error { 59127- a.mu.Lock() 59128- defer a.mu.Unlock() 59129- 59130- a.state.work[m.Token] = &workProgress{} 59131- return nil 59132-} 59133- 59134-func (a *Awaiter) onProgress(_ context.Context, m *protocol.ProgressParams) error { 59135- a.mu.Lock() 59136- defer a.mu.Unlock() 59137- work, ok := a.state.work[m.Token] 59138- if !ok { 59139- panic(fmt.Sprintf("got progress report for unknown report %v: %v", m.Token, m)) 59140- } 59141- v := m.Value.(map[string]interface{}) 59142- switch kind := v["kind"]; kind { 59143- case "begin": 59144- work.title = v["title"].(string) 59145- if msg, ok := v["message"]; ok { 59146- work.msg = msg.(string) 59147- } 59148- case "report": 59149- if pct, ok := v["percentage"]; ok { 59150- work.percent = pct.(float64) 59151- } 59152- if msg, ok := v["message"]; ok { 59153- work.msg = msg.(string) 59154- } 59155- case "end": 59156- work.complete = true 59157- if msg, ok := v["message"]; ok { 59158- work.endMsg = msg.(string) 59159- } 59160- } 59161- a.checkConditionsLocked() 59162- return nil 59163-} 59164- 59165-func (a *Awaiter) onRegisterCapability(_ context.Context, m *protocol.RegistrationParams) error { 59166- a.mu.Lock() 59167- defer a.mu.Unlock() 59168- 59169- a.state.registrations = append(a.state.registrations, m) 59170- if a.state.registeredCapabilities == nil { 59171- a.state.registeredCapabilities = make(map[string]protocol.Registration) 59172- } 59173- for _, reg := range m.Registrations { 59174- a.state.registeredCapabilities[reg.Method] = reg 59175- } 59176- a.checkConditionsLocked() 59177- return nil 59178-} 59179- 59180-func (a *Awaiter) onUnregisterCapability(_ context.Context, m *protocol.UnregistrationParams) error { 59181- a.mu.Lock() 59182- defer a.mu.Unlock() 59183- 59184- a.state.unregistrations = append(a.state.unregistrations, m) 59185- a.checkConditionsLocked() 59186- return nil 59187-} 59188- 59189-func (a *Awaiter) checkConditionsLocked() { 59190- for id, condition := range a.waiters { 59191- if v, _ := checkExpectations(a.state, condition.expectations); v != Unmet { 59192- delete(a.waiters, id) 59193- condition.verdict <- v 59194- } 59195- } 59196-} 59197- 59198-// takeDocumentChanges returns any accumulated document changes (from 59199-// server ApplyEdit RPC downcalls) and resets the list. 59200-func (a *Awaiter) takeDocumentChanges() []protocol.DocumentChanges { 59201- a.mu.Lock() 59202- defer a.mu.Unlock() 59203- 59204- res := a.state.documentChanges 59205- a.state.documentChanges = nil 59206- return res 59207-} 59208- 59209-// checkExpectations reports whether s meets all expectations. 59210-func checkExpectations(s State, expectations []Expectation) (Verdict, string) { 59211- finalVerdict := Met 59212- var summary strings.Builder 59213- for _, e := range expectations { 59214- v := e.Check(s) 59215- if v > finalVerdict { 59216- finalVerdict = v 59217- } 59218- fmt.Fprintf(&summary, "%v: %s\n", v, e.Description) 59219- } 59220- return finalVerdict, summary.String() 59221-} 59222- 59223-// Await blocks until the given expectations are all simultaneously met. 59224-// 59225-// Generally speaking Await should be avoided because it blocks indefinitely if 59226-// gopls ends up in a state where the expectations are never going to be met. 59227-// Use AfterChange or OnceMet instead, so that the runner knows when to stop 59228-// waiting. 59229-func (e *Env) Await(expectations ...Expectation) { 59230- e.T.Helper() 59231- if err := e.Awaiter.Await(e.Ctx, expectations...); err != nil { 59232- e.T.Fatal(err) 59233- } 59234-} 59235- 59236-// OnceMet blocks until the precondition is met by the state or becomes 59237-// unmeetable. If it was met, OnceMet checks that the state meets all 59238-// expectations in mustMeets. 59239-func (e *Env) OnceMet(precondition Expectation, mustMeets ...Expectation) { 59240- e.Await(OnceMet(precondition, mustMeets...)) 59241-} 59242- 59243-// Await waits for all expectations to simultaneously be met. It should only be 59244-// called from the main test goroutine. 59245-func (a *Awaiter) Await(ctx context.Context, expectations ...Expectation) error { 59246- a.mu.Lock() 59247- // Before adding the waiter, we check if the condition is currently met or 59248- // failed to avoid a race where the condition was realized before Await was 59249- // called. 59250- switch verdict, summary := checkExpectations(a.state, expectations); verdict { 59251- case Met: 59252- a.mu.Unlock() 59253- return nil 59254- case Unmeetable: 59255- err := fmt.Errorf("unmeetable expectations:\n%s\nstate:\n%v", summary, a.state) 59256- a.mu.Unlock() 59257- return err 59258- } 59259- cond := &condition{ 59260- expectations: expectations, 59261- verdict: make(chan Verdict), 59262- } 59263- a.waiters[a.nextWaiterID] = cond 59264- a.nextWaiterID++ 59265- a.mu.Unlock() 59266- 59267- var err error 59268- select { 59269- case <-ctx.Done(): 59270- err = ctx.Err() 59271- case v := <-cond.verdict: 59272- if v != Met { 59273- err = fmt.Errorf("condition has final verdict %v", v) 59274- } 59275- } 59276- a.mu.Lock() 59277- defer a.mu.Unlock() 59278- _, summary := checkExpectations(a.state, expectations) 59279- 59280- // Debugging an unmet expectation can be tricky, so we put some effort into 59281- // nicely formatting the failure. 59282- if err != nil { 59283- return fmt.Errorf("waiting on:\n%s\nerr:%v\n\nstate:\n%v", summary, err, a.state) 59284- } 59285- return nil 59286-} 59287diff -urN a/gopls/internal/lsp/regtest/env_test.go b/gopls/internal/lsp/regtest/env_test.go 59288--- a/gopls/internal/lsp/regtest/env_test.go 2000-01-01 00:00:00.000000000 -0000 59289+++ b/gopls/internal/lsp/regtest/env_test.go 1970-01-01 00:00:00.000000000 +0000 59290@@ -1,66 +0,0 @@ 59291-// Copyright 2020 The Go Authors. All rights reserved. 59292-// Use of this source code is governed by a BSD-style 59293-// license that can be found in the LICENSE file. 59294- 59295-package regtest 59296- 59297-import ( 59298- "context" 59299- "encoding/json" 59300- "testing" 59301- 59302- "golang.org/x/tools/gopls/internal/lsp/protocol" 59303-) 59304- 59305-func TestProgressUpdating(t *testing.T) { 59306- a := &Awaiter{ 59307- state: State{ 59308- work: make(map[protocol.ProgressToken]*workProgress), 59309- }, 59310- } 59311- ctx := context.Background() 59312- if err := a.onWorkDoneProgressCreate(ctx, &protocol.WorkDoneProgressCreateParams{ 59313- Token: "foo", 59314- }); err != nil { 59315- t.Fatal(err) 59316- } 59317- if err := a.onWorkDoneProgressCreate(ctx, &protocol.WorkDoneProgressCreateParams{ 59318- Token: "bar", 59319- }); err != nil { 59320- t.Fatal(err) 59321- } 59322- updates := []struct { 59323- token string 59324- value interface{} 59325- }{ 59326- {"foo", protocol.WorkDoneProgressBegin{Kind: "begin", Title: "foo work"}}, 59327- {"bar", protocol.WorkDoneProgressBegin{Kind: "begin", Title: "bar work"}}, 59328- {"foo", protocol.WorkDoneProgressEnd{Kind: "end"}}, 59329- {"bar", protocol.WorkDoneProgressReport{Kind: "report", Percentage: 42}}, 59330- } 59331- for _, update := range updates { 59332- params := &protocol.ProgressParams{ 59333- Token: update.token, 59334- Value: update.value, 59335- } 59336- data, err := json.Marshal(params) 59337- if err != nil { 59338- t.Fatal(err) 59339- } 59340- var unmarshaled protocol.ProgressParams 59341- if err := json.Unmarshal(data, &unmarshaled); err != nil { 59342- t.Fatal(err) 59343- } 59344- if err := a.onProgress(ctx, &unmarshaled); err != nil { 59345- t.Fatal(err) 59346- } 59347- } 59348- if !a.state.work["foo"].complete { 59349- t.Error("work entry \"foo\" is incomplete, want complete") 59350- } 59351- got := *a.state.work["bar"] 59352- want := workProgress{title: "bar work", percent: 42} 59353- if got != want { 59354- t.Errorf("work progress for \"bar\": %v, want %v", got, want) 59355- } 59356-} 59357diff -urN a/gopls/internal/lsp/regtest/expectation.go b/gopls/internal/lsp/regtest/expectation.go 59358--- a/gopls/internal/lsp/regtest/expectation.go 2000-01-01 00:00:00.000000000 -0000 59359+++ b/gopls/internal/lsp/regtest/expectation.go 1970-01-01 00:00:00.000000000 +0000 59360@@ -1,769 +0,0 @@ 59361-// Copyright 2020 The Go Authors. All rights reserved. 59362-// Use of this source code is governed by a BSD-style 59363-// license that can be found in the LICENSE file. 59364- 59365-package regtest 59366- 59367-import ( 59368- "fmt" 59369- "regexp" 59370- "sort" 59371- "strings" 59372- 59373- "golang.org/x/tools/gopls/internal/lsp" 59374- "golang.org/x/tools/gopls/internal/lsp/protocol" 59375-) 59376- 59377-var ( 59378- // InitialWorkspaceLoad is an expectation that the workspace initial load has 59379- // completed. It is verified via workdone reporting. 59380- InitialWorkspaceLoad = CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromInitialWorkspaceLoad), 1, false) 59381-) 59382- 59383-// A Verdict is the result of checking an expectation against the current 59384-// editor state. 59385-type Verdict int 59386- 59387-// Order matters for the following constants: verdicts are sorted in order of 59388-// decisiveness. 59389-const ( 59390- // Met indicates that an expectation is satisfied by the current state. 59391- Met Verdict = iota 59392- // Unmet indicates that an expectation is not currently met, but could be met 59393- // in the future. 59394- Unmet 59395- // Unmeetable indicates that an expectation cannot be satisfied in the 59396- // future. 59397- Unmeetable 59398-) 59399- 59400-func (v Verdict) String() string { 59401- switch v { 59402- case Met: 59403- return "Met" 59404- case Unmet: 59405- return "Unmet" 59406- case Unmeetable: 59407- return "Unmeetable" 59408- } 59409- return fmt.Sprintf("unrecognized verdict %d", v) 59410-} 59411- 59412-// An Expectation is an expected property of the state of the LSP client. 59413-// The Check function reports whether the property is met. 59414-// 59415-// Expectations are combinators. By composing them, tests may express 59416-// complex expectations in terms of simpler ones. 59417-// 59418-// TODO(rfindley): as expectations are combined, it becomes harder to identify 59419-// why they failed. A better signature for Check would be 59420-// 59421-// func(State) (Verdict, string) 59422-// 59423-// returning a reason for the verdict that can be composed similarly to 59424-// descriptions. 59425-type Expectation struct { 59426- Check func(State) Verdict 59427- 59428- // Description holds a noun-phrase identifying what the expectation checks. 59429- // 59430- // TODO(rfindley): revisit existing descriptions to ensure they compose nicely. 59431- Description string 59432-} 59433- 59434-// OnceMet returns an Expectation that, once the precondition is met, asserts 59435-// that mustMeet is met. 59436-func OnceMet(precondition Expectation, mustMeets ...Expectation) Expectation { 59437- check := func(s State) Verdict { 59438- switch pre := precondition.Check(s); pre { 59439- case Unmeetable: 59440- return Unmeetable 59441- case Met: 59442- for _, mustMeet := range mustMeets { 59443- verdict := mustMeet.Check(s) 59444- if verdict != Met { 59445- return Unmeetable 59446- } 59447- } 59448- return Met 59449- default: 59450- return Unmet 59451- } 59452- } 59453- description := describeExpectations(mustMeets...) 59454- return Expectation{ 59455- Check: check, 59456- Description: fmt.Sprintf("once %q is met, must have:\n%s", precondition.Description, description), 59457- } 59458-} 59459- 59460-func describeExpectations(expectations ...Expectation) string { 59461- var descriptions []string 59462- for _, e := range expectations { 59463- descriptions = append(descriptions, e.Description) 59464- } 59465- return strings.Join(descriptions, "\n") 59466-} 59467- 59468-// AnyOf returns an expectation that is satisfied when any of the given 59469-// expectations is met. 59470-func AnyOf(anyOf ...Expectation) Expectation { 59471- check := func(s State) Verdict { 59472- for _, e := range anyOf { 59473- verdict := e.Check(s) 59474- if verdict == Met { 59475- return Met 59476- } 59477- } 59478- return Unmet 59479- } 59480- description := describeExpectations(anyOf...) 59481- return Expectation{ 59482- Check: check, 59483- Description: fmt.Sprintf("Any of:\n%s", description), 59484- } 59485-} 59486- 59487-// AllOf expects that all given expectations are met. 59488-// 59489-// TODO(rfindley): the problem with these types of combinators (OnceMet, AnyOf 59490-// and AllOf) is that we lose the information of *why* they failed: the Awaiter 59491-// is not smart enough to look inside. 59492-// 59493-// Refactor the API such that the Check function is responsible for explaining 59494-// why an expectation failed. This should allow us to significantly improve 59495-// test output: we won't need to summarize state at all, as the verdict 59496-// explanation itself should describe clearly why the expectation not met. 59497-func AllOf(allOf ...Expectation) Expectation { 59498- check := func(s State) Verdict { 59499- verdict := Met 59500- for _, e := range allOf { 59501- if v := e.Check(s); v > verdict { 59502- verdict = v 59503- } 59504- } 59505- return verdict 59506- } 59507- description := describeExpectations(allOf...) 59508- return Expectation{ 59509- Check: check, 59510- Description: fmt.Sprintf("All of:\n%s", description), 59511- } 59512-} 59513- 59514-// ReadDiagnostics is an Expectation that stores the current diagnostics for 59515-// fileName in into, whenever it is evaluated. 59516-// 59517-// It can be used in combination with OnceMet or AfterChange to capture the 59518-// state of diagnostics when other expectations are satisfied. 59519-func ReadDiagnostics(fileName string, into *protocol.PublishDiagnosticsParams) Expectation { 59520- check := func(s State) Verdict { 59521- diags, ok := s.diagnostics[fileName] 59522- if !ok { 59523- return Unmeetable 59524- } 59525- *into = *diags 59526- return Met 59527- } 59528- return Expectation{ 59529- Check: check, 59530- Description: fmt.Sprintf("read diagnostics for %q", fileName), 59531- } 59532-} 59533- 59534-// ReadAllDiagnostics is an expectation that stores all published diagnostics 59535-// into the provided map, whenever it is evaluated. 59536-// 59537-// It can be used in combination with OnceMet or AfterChange to capture the 59538-// state of diagnostics when other expectations are satisfied. 59539-func ReadAllDiagnostics(into *map[string]*protocol.PublishDiagnosticsParams) Expectation { 59540- check := func(s State) Verdict { 59541- allDiags := make(map[string]*protocol.PublishDiagnosticsParams) 59542- for name, diags := range s.diagnostics { 59543- allDiags[name] = diags 59544- } 59545- *into = allDiags 59546- return Met 59547- } 59548- return Expectation{ 59549- Check: check, 59550- Description: "read all diagnostics", 59551- } 59552-} 59553- 59554-// NoOutstandingWork asserts that there is no work initiated using the LSP 59555-// $/progress API that has not completed. 59556-func NoOutstandingWork() Expectation { 59557- check := func(s State) Verdict { 59558- if len(s.outstandingWork()) == 0 { 59559- return Met 59560- } 59561- return Unmet 59562- } 59563- return Expectation{ 59564- Check: check, 59565- Description: "no outstanding work", 59566- } 59567-} 59568- 59569-// NoShownMessage asserts that the editor has not received a ShowMessage. 59570-func NoShownMessage(subString string) Expectation { 59571- check := func(s State) Verdict { 59572- for _, m := range s.showMessage { 59573- if strings.Contains(m.Message, subString) { 59574- return Unmeetable 59575- } 59576- } 59577- return Met 59578- } 59579- return Expectation{ 59580- Check: check, 59581- Description: fmt.Sprintf("no ShowMessage received containing %q", subString), 59582- } 59583-} 59584- 59585-// ShownMessage asserts that the editor has received a ShowMessageRequest 59586-// containing the given substring. 59587-func ShownMessage(containing string) Expectation { 59588- check := func(s State) Verdict { 59589- for _, m := range s.showMessage { 59590- if strings.Contains(m.Message, containing) { 59591- return Met 59592- } 59593- } 59594- return Unmet 59595- } 59596- return Expectation{ 59597- Check: check, 59598- Description: "received ShowMessage", 59599- } 59600-} 59601- 59602-// ShowMessageRequest asserts that the editor has received a ShowMessageRequest 59603-// with an action item that has the given title. 59604-func ShowMessageRequest(title string) Expectation { 59605- check := func(s State) Verdict { 59606- if len(s.showMessageRequest) == 0 { 59607- return Unmet 59608- } 59609- // Only check the most recent one. 59610- m := s.showMessageRequest[len(s.showMessageRequest)-1] 59611- if len(m.Actions) == 0 || len(m.Actions) > 1 { 59612- return Unmet 59613- } 59614- if m.Actions[0].Title == title { 59615- return Met 59616- } 59617- return Unmet 59618- } 59619- return Expectation{ 59620- Check: check, 59621- Description: "received ShowMessageRequest", 59622- } 59623-} 59624- 59625-// DoneDiagnosingChanges expects that diagnostics are complete from common 59626-// change notifications: didOpen, didChange, didSave, didChangeWatchedFiles, 59627-// and didClose. 59628-// 59629-// This can be used when multiple notifications may have been sent, such as 59630-// when a didChange is immediately followed by a didSave. It is insufficient to 59631-// simply await NoOutstandingWork, because the LSP client has no control over 59632-// when the server starts processing a notification. Therefore, we must keep 59633-// track of 59634-func (e *Env) DoneDiagnosingChanges() Expectation { 59635- stats := e.Editor.Stats() 59636- statsBySource := map[lsp.ModificationSource]uint64{ 59637- lsp.FromDidOpen: stats.DidOpen, 59638- lsp.FromDidChange: stats.DidChange, 59639- lsp.FromDidSave: stats.DidSave, 59640- lsp.FromDidChangeWatchedFiles: stats.DidChangeWatchedFiles, 59641- lsp.FromDidClose: stats.DidClose, 59642- } 59643- 59644- var expected []lsp.ModificationSource 59645- for k, v := range statsBySource { 59646- if v > 0 { 59647- expected = append(expected, k) 59648- } 59649- } 59650- 59651- // Sort for stability. 59652- sort.Slice(expected, func(i, j int) bool { 59653- return expected[i] < expected[j] 59654- }) 59655- 59656- var all []Expectation 59657- for _, source := range expected { 59658- all = append(all, CompletedWork(lsp.DiagnosticWorkTitle(source), statsBySource[source], true)) 59659- } 59660- 59661- return AllOf(all...) 59662-} 59663- 59664-// AfterChange expects that the given expectations will be met after all 59665-// state-changing notifications have been processed by the server. 59666-// 59667-// It awaits the completion of all anticipated work before checking the given 59668-// expectations. 59669-func (e *Env) AfterChange(expectations ...Expectation) { 59670- e.T.Helper() 59671- e.OnceMet( 59672- e.DoneDiagnosingChanges(), 59673- expectations..., 59674- ) 59675-} 59676- 59677-// DoneWithOpen expects all didOpen notifications currently sent by the editor 59678-// to be completely processed. 59679-func (e *Env) DoneWithOpen() Expectation { 59680- opens := e.Editor.Stats().DidOpen 59681- return CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), opens, true) 59682-} 59683- 59684-// StartedChange expects that the server has at least started processing all 59685-// didChange notifications sent from the client. 59686-func (e *Env) StartedChange() Expectation { 59687- changes := e.Editor.Stats().DidChange 59688- return StartedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), changes) 59689-} 59690- 59691-// DoneWithChange expects all didChange notifications currently sent by the 59692-// editor to be completely processed. 59693-func (e *Env) DoneWithChange() Expectation { 59694- changes := e.Editor.Stats().DidChange 59695- return CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), changes, true) 59696-} 59697- 59698-// DoneWithSave expects all didSave notifications currently sent by the editor 59699-// to be completely processed. 59700-func (e *Env) DoneWithSave() Expectation { 59701- saves := e.Editor.Stats().DidSave 59702- return CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), saves, true) 59703-} 59704- 59705-// StartedChangeWatchedFiles expects that the server has at least started 59706-// processing all didChangeWatchedFiles notifications sent from the client. 59707-func (e *Env) StartedChangeWatchedFiles() Expectation { 59708- changes := e.Editor.Stats().DidChangeWatchedFiles 59709- return StartedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), changes) 59710-} 59711- 59712-// DoneWithChangeWatchedFiles expects all didChangeWatchedFiles notifications 59713-// currently sent by the editor to be completely processed. 59714-func (e *Env) DoneWithChangeWatchedFiles() Expectation { 59715- changes := e.Editor.Stats().DidChangeWatchedFiles 59716- return CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), changes, true) 59717-} 59718- 59719-// DoneWithClose expects all didClose notifications currently sent by the 59720-// editor to be completely processed. 59721-func (e *Env) DoneWithClose() Expectation { 59722- changes := e.Editor.Stats().DidClose 59723- return CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidClose), changes, true) 59724-} 59725- 59726-// StartedWork expect a work item to have been started >= atLeast times. 59727-// 59728-// See CompletedWork. 59729-func StartedWork(title string, atLeast uint64) Expectation { 59730- check := func(s State) Verdict { 59731- if s.startedWork()[title] >= atLeast { 59732- return Met 59733- } 59734- return Unmet 59735- } 59736- return Expectation{ 59737- Check: check, 59738- Description: fmt.Sprintf("started work %q at least %d time(s)", title, atLeast), 59739- } 59740-} 59741- 59742-// CompletedWork expects a work item to have been completed >= atLeast times. 59743-// 59744-// Since the Progress API doesn't include any hidden metadata, we must use the 59745-// progress notification title to identify the work we expect to be completed. 59746-func CompletedWork(title string, count uint64, atLeast bool) Expectation { 59747- check := func(s State) Verdict { 59748- completed := s.completedWork() 59749- if completed[title] == count || atLeast && completed[title] > count { 59750- return Met 59751- } 59752- return Unmet 59753- } 59754- desc := fmt.Sprintf("completed work %q %v times", title, count) 59755- if atLeast { 59756- desc = fmt.Sprintf("completed work %q at least %d time(s)", title, count) 59757- } 59758- return Expectation{ 59759- Check: check, 59760- Description: desc, 59761- } 59762-} 59763- 59764-type WorkStatus struct { 59765- // Last seen message from either `begin` or `report` progress. 59766- Msg string 59767- // Message sent with `end` progress message. 59768- EndMsg string 59769-} 59770- 59771-// CompletedProgress expects that workDone progress is complete for the given 59772-// progress token. When non-nil WorkStatus is provided, it will be filled 59773-// when the expectation is met. 59774-// 59775-// If the token is not a progress token that the client has seen, this 59776-// expectation is Unmeetable. 59777-func CompletedProgress(token protocol.ProgressToken, into *WorkStatus) Expectation { 59778- check := func(s State) Verdict { 59779- work, ok := s.work[token] 59780- if !ok { 59781- return Unmeetable // TODO(rfindley): refactor to allow the verdict to explain this result 59782- } 59783- if work.complete { 59784- if into != nil { 59785- into.Msg = work.msg 59786- into.EndMsg = work.endMsg 59787- } 59788- return Met 59789- } 59790- return Unmet 59791- } 59792- desc := fmt.Sprintf("completed work for token %v", token) 59793- return Expectation{ 59794- Check: check, 59795- Description: desc, 59796- } 59797-} 59798- 59799-// OutstandingWork expects a work item to be outstanding. The given title must 59800-// be an exact match, whereas the given msg must only be contained in the work 59801-// item's message. 59802-func OutstandingWork(title, msg string) Expectation { 59803- check := func(s State) Verdict { 59804- for _, work := range s.work { 59805- if work.complete { 59806- continue 59807- } 59808- if work.title == title && strings.Contains(work.msg, msg) { 59809- return Met 59810- } 59811- } 59812- return Unmet 59813- } 59814- return Expectation{ 59815- Check: check, 59816- Description: fmt.Sprintf("outstanding work: %q containing %q", title, msg), 59817- } 59818-} 59819- 59820-// NoErrorLogs asserts that the client has not received any log messages of 59821-// error severity. 59822-func NoErrorLogs() Expectation { 59823- return NoLogMatching(protocol.Error, "") 59824-} 59825- 59826-// LogMatching asserts that the client has received a log message 59827-// of type typ matching the regexp re a certain number of times. 59828-// 59829-// The count argument specifies the expected number of matching logs. If 59830-// atLeast is set, this is a lower bound, otherwise there must be exactly count 59831-// matching logs. 59832-func LogMatching(typ protocol.MessageType, re string, count int, atLeast bool) Expectation { 59833- rec, err := regexp.Compile(re) 59834- if err != nil { 59835- panic(err) 59836- } 59837- check := func(state State) Verdict { 59838- var found int 59839- for _, msg := range state.logs { 59840- if msg.Type == typ && rec.Match([]byte(msg.Message)) { 59841- found++ 59842- } 59843- } 59844- // Check for an exact or "at least" match. 59845- if found == count || (found >= count && atLeast) { 59846- return Met 59847- } 59848- return Unmet 59849- } 59850- desc := fmt.Sprintf("log message matching %q expected %v times", re, count) 59851- if atLeast { 59852- desc = fmt.Sprintf("log message matching %q expected at least %v times", re, count) 59853- } 59854- return Expectation{ 59855- Check: check, 59856- Description: desc, 59857- } 59858-} 59859- 59860-// NoLogMatching asserts that the client has not received a log message 59861-// of type typ matching the regexp re. If re is an empty string, any log 59862-// message is considered a match. 59863-func NoLogMatching(typ protocol.MessageType, re string) Expectation { 59864- var r *regexp.Regexp 59865- if re != "" { 59866- var err error 59867- r, err = regexp.Compile(re) 59868- if err != nil { 59869- panic(err) 59870- } 59871- } 59872- check := func(state State) Verdict { 59873- for _, msg := range state.logs { 59874- if msg.Type != typ { 59875- continue 59876- } 59877- if r == nil || r.Match([]byte(msg.Message)) { 59878- return Unmeetable 59879- } 59880- } 59881- return Met 59882- } 59883- return Expectation{ 59884- Check: check, 59885- Description: fmt.Sprintf("no log message matching %q", re), 59886- } 59887-} 59888- 59889-// FileWatchMatching expects that a file registration matches re. 59890-func FileWatchMatching(re string) Expectation { 59891- return Expectation{ 59892- Check: checkFileWatch(re, Met, Unmet), 59893- Description: fmt.Sprintf("file watch matching %q", re), 59894- } 59895-} 59896- 59897-// NoFileWatchMatching expects that no file registration matches re. 59898-func NoFileWatchMatching(re string) Expectation { 59899- return Expectation{ 59900- Check: checkFileWatch(re, Unmet, Met), 59901- Description: fmt.Sprintf("no file watch matching %q", re), 59902- } 59903-} 59904- 59905-func checkFileWatch(re string, onMatch, onNoMatch Verdict) func(State) Verdict { 59906- rec := regexp.MustCompile(re) 59907- return func(s State) Verdict { 59908- r := s.registeredCapabilities["workspace/didChangeWatchedFiles"] 59909- watchers := jsonProperty(r.RegisterOptions, "watchers").([]interface{}) 59910- for _, watcher := range watchers { 59911- pattern := jsonProperty(watcher, "globPattern").(string) 59912- if rec.MatchString(pattern) { 59913- return onMatch 59914- } 59915- } 59916- return onNoMatch 59917- } 59918-} 59919- 59920-// jsonProperty extracts a value from a path of JSON property names, assuming 59921-// the default encoding/json unmarshaling to the empty interface (i.e.: that 59922-// JSON objects are unmarshalled as map[string]interface{}) 59923-// 59924-// For example, if obj is unmarshalled from the following json: 59925-// 59926-// { 59927-// "foo": { "bar": 3 } 59928-// } 59929-// 59930-// Then jsonProperty(obj, "foo", "bar") will be 3. 59931-func jsonProperty(obj interface{}, path ...string) interface{} { 59932- if len(path) == 0 || obj == nil { 59933- return obj 59934- } 59935- m := obj.(map[string]interface{}) 59936- return jsonProperty(m[path[0]], path[1:]...) 59937-} 59938- 59939-// RegistrationMatching asserts that the client has received a capability 59940-// registration matching the given regexp. 59941-// 59942-// TODO(rfindley): remove this once TestWatchReplaceTargets has been revisited. 59943-// 59944-// Deprecated: use (No)FileWatchMatching 59945-func RegistrationMatching(re string) Expectation { 59946- rec := regexp.MustCompile(re) 59947- check := func(s State) Verdict { 59948- for _, p := range s.registrations { 59949- for _, r := range p.Registrations { 59950- if rec.Match([]byte(r.Method)) { 59951- return Met 59952- } 59953- } 59954- } 59955- return Unmet 59956- } 59957- return Expectation{ 59958- Check: check, 59959- Description: fmt.Sprintf("registration matching %q", re), 59960- } 59961-} 59962- 59963-// UnregistrationMatching asserts that the client has received an 59964-// unregistration whose ID matches the given regexp. 59965-func UnregistrationMatching(re string) Expectation { 59966- rec := regexp.MustCompile(re) 59967- check := func(s State) Verdict { 59968- for _, p := range s.unregistrations { 59969- for _, r := range p.Unregisterations { 59970- if rec.Match([]byte(r.Method)) { 59971- return Met 59972- } 59973- } 59974- } 59975- return Unmet 59976- } 59977- return Expectation{ 59978- Check: check, 59979- Description: fmt.Sprintf("unregistration matching %q", re), 59980- } 59981-} 59982- 59983-// Diagnostics asserts that there is at least one diagnostic matching the given 59984-// filters. 59985-func Diagnostics(filters ...DiagnosticFilter) Expectation { 59986- check := func(s State) Verdict { 59987- diags := flattenDiagnostics(s) 59988- for _, filter := range filters { 59989- var filtered []flatDiagnostic 59990- for _, d := range diags { 59991- if filter.check(d.name, d.diag) { 59992- filtered = append(filtered, d) 59993- } 59994- } 59995- if len(filtered) == 0 { 59996- // TODO(rfindley): if/when expectations describe their own failure, we 59997- // can provide more useful information here as to which filter caused 59998- // the failure. 59999- return Unmet 60000- } 60001- diags = filtered 60002- } 60003- return Met 60004- } 60005- var descs []string 60006- for _, filter := range filters { 60007- descs = append(descs, filter.desc) 60008- } 60009- return Expectation{ 60010- Check: check, 60011- Description: "any diagnostics " + strings.Join(descs, ", "), 60012- } 60013-} 60014- 60015-// NoDiagnostics asserts that there are no diagnostics matching the given 60016-// filters. Notably, if no filters are supplied this assertion checks that 60017-// there are no diagnostics at all, for any file. 60018-func NoDiagnostics(filters ...DiagnosticFilter) Expectation { 60019- check := func(s State) Verdict { 60020- diags := flattenDiagnostics(s) 60021- for _, filter := range filters { 60022- var filtered []flatDiagnostic 60023- for _, d := range diags { 60024- if filter.check(d.name, d.diag) { 60025- filtered = append(filtered, d) 60026- } 60027- } 60028- diags = filtered 60029- } 60030- if len(diags) > 0 { 60031- return Unmet 60032- } 60033- return Met 60034- } 60035- var descs []string 60036- for _, filter := range filters { 60037- descs = append(descs, filter.desc) 60038- } 60039- return Expectation{ 60040- Check: check, 60041- Description: "no diagnostics " + strings.Join(descs, ", "), 60042- } 60043-} 60044- 60045-type flatDiagnostic struct { 60046- name string 60047- diag protocol.Diagnostic 60048-} 60049- 60050-func flattenDiagnostics(state State) []flatDiagnostic { 60051- var result []flatDiagnostic 60052- for name, diags := range state.diagnostics { 60053- for _, diag := range diags.Diagnostics { 60054- result = append(result, flatDiagnostic{name, diag}) 60055- } 60056- } 60057- return result 60058-} 60059- 60060-// -- Diagnostic filters -- 60061- 60062-// A DiagnosticFilter filters the set of diagnostics, for assertion with 60063-// Diagnostics or NoDiagnostics. 60064-type DiagnosticFilter struct { 60065- desc string 60066- check func(name string, _ protocol.Diagnostic) bool 60067-} 60068- 60069-// ForFile filters to diagnostics matching the sandbox-relative file name. 60070-func ForFile(name string) DiagnosticFilter { 60071- return DiagnosticFilter{ 60072- desc: fmt.Sprintf("for file %q", name), 60073- check: func(diagName string, _ protocol.Diagnostic) bool { 60074- return diagName == name 60075- }, 60076- } 60077-} 60078- 60079-// FromSource filters to diagnostics matching the given diagnostics source. 60080-func FromSource(source string) DiagnosticFilter { 60081- return DiagnosticFilter{ 60082- desc: fmt.Sprintf("with source %q", source), 60083- check: func(_ string, d protocol.Diagnostic) bool { 60084- return d.Source == source 60085- }, 60086- } 60087-} 60088- 60089-// AtRegexp filters to diagnostics in the file with sandbox-relative path name, 60090-// at the first position matching the given regexp pattern. 60091-// 60092-// TODO(rfindley): pass in the editor to expectations, so that they may depend 60093-// on editor state and AtRegexp can be a function rather than a method. 60094-func (e *Env) AtRegexp(name, pattern string) DiagnosticFilter { 60095- loc := e.RegexpSearch(name, pattern) 60096- return DiagnosticFilter{ 60097- desc: fmt.Sprintf("at the first position matching %#q in %q", pattern, name), 60098- check: func(diagName string, d protocol.Diagnostic) bool { 60099- return diagName == name && d.Range.Start == loc.Range.Start 60100- }, 60101- } 60102-} 60103- 60104-// AtPosition filters to diagnostics at location name:line:character, for a 60105-// sandbox-relative path name. 60106-// 60107-// Line and character are 0-based, and character measures UTF-16 codes. 60108-// 60109-// Note: prefer the more readable AtRegexp. 60110-func AtPosition(name string, line, character uint32) DiagnosticFilter { 60111- pos := protocol.Position{Line: line, Character: character} 60112- return DiagnosticFilter{ 60113- desc: fmt.Sprintf("at %s:%d:%d", name, line, character), 60114- check: func(diagName string, d protocol.Diagnostic) bool { 60115- return diagName == name && d.Range.Start == pos 60116- }, 60117- } 60118-} 60119- 60120-// WithMessage filters to diagnostics whose message contains the given 60121-// substring. 60122-func WithMessage(substring string) DiagnosticFilter { 60123- return DiagnosticFilter{ 60124- desc: fmt.Sprintf("with message containing %q", substring), 60125- check: func(_ string, d protocol.Diagnostic) bool { 60126- return strings.Contains(d.Message, substring) 60127- }, 60128- } 60129-} 60130diff -urN a/gopls/internal/lsp/regtest/marker.go b/gopls/internal/lsp/regtest/marker.go 60131--- a/gopls/internal/lsp/regtest/marker.go 2000-01-01 00:00:00.000000000 -0000 60132+++ b/gopls/internal/lsp/regtest/marker.go 1970-01-01 00:00:00.000000000 +0000 60133@@ -1,1273 +0,0 @@ 60134-// Copyright 2023 The Go Authors. All rights reserved. 60135-// Use of this source code is governed by a BSD-style 60136-// license that can be found in the LICENSE file. 60137- 60138-package regtest 60139- 60140-import ( 60141- "bytes" 60142- "context" 60143- "encoding/json" 60144- "flag" 60145- "fmt" 60146- "go/token" 60147- "io/fs" 60148- "os" 60149- "path" 60150- "path/filepath" 60151- "reflect" 60152- "regexp" 60153- "sort" 60154- "strings" 60155- "testing" 60156- 60157- "golang.org/x/tools/go/expect" 60158- "golang.org/x/tools/gopls/internal/hooks" 60159- "golang.org/x/tools/gopls/internal/lsp/cache" 60160- "golang.org/x/tools/gopls/internal/lsp/debug" 60161- "golang.org/x/tools/gopls/internal/lsp/fake" 60162- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 60163- "golang.org/x/tools/gopls/internal/lsp/protocol" 60164- "golang.org/x/tools/gopls/internal/lsp/safetoken" 60165- "golang.org/x/tools/gopls/internal/lsp/source" 60166- "golang.org/x/tools/gopls/internal/lsp/tests" 60167- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 60168- "golang.org/x/tools/internal/jsonrpc2" 60169- "golang.org/x/tools/internal/jsonrpc2/servertest" 60170- "golang.org/x/tools/internal/testenv" 60171- "golang.org/x/tools/txtar" 60172-) 60173- 60174-var update = flag.Bool("update", false, "if set, update test data during marker tests") 60175- 60176-// RunMarkerTests runs "marker" tests in the given test data directory. 60177-// 60178-// A marker test uses the '//@' marker syntax of the x/tools/go/expect package 60179-// to annotate source code with various information such as locations and 60180-// arguments of LSP operations to be executed by the test. The syntax following 60181-// '@' is parsed as a comma-separated list of ordinary Go function calls, for 60182-// example 60183-// 60184-// //@foo(a, "b", 3),bar(0) 60185-// 60186-// and delegates to a corresponding function to perform LSP-related operations. 60187-// See the Marker types documentation below for a list of supported markers. 60188-// 60189-// Each call argument is converted to the type of the corresponding parameter of 60190-// the designated function. The conversion logic may use the surrounding context, 60191-// such as the position or nearby text. See the Argument conversion section below 60192-// for the full set of special conversions. As a special case, the blank 60193-// identifier '_' is treated as the zero value of the parameter type. 60194-// 60195-// The test runner collects test cases by searching the given directory for 60196-// files with the .txt extension. Each file is interpreted as a txtar archive, 60197-// which is extracted to a temporary directory. The relative path to the .txt 60198-// file is used as the subtest name. The preliminary section of the file 60199-// (before the first archive entry) is a free-form comment. 60200-// 60201-// These tests were inspired by (and in many places copied from) a previous 60202-// iteration of the marker tests built on top of the packagestest framework. 60203-// Key design decisions motivating this reimplementation are as follows: 60204-// - The old tests had a single global session, causing interaction at a 60205-// distance and several awkward workarounds. 60206-// - The old tests could not be safely parallelized, because certain tests 60207-// manipulated the server options 60208-// - Relatedly, the old tests did not have a logic grouping of assertions into 60209-// a single unit, resulting in clusters of files serving clusters of 60210-// entangled assertions. 60211-// - The old tests used locations in the source as test names and as the 60212-// identity of golden content, meaning that a single edit could change the 60213-// name of an arbitrary number of subtests, and making it difficult to 60214-// manually edit golden content. 60215-// - The old tests did not hew closely to LSP concepts, resulting in, for 60216-// example, each marker implementation doing its own position 60217-// transformations, and inventing its own mechanism for configuration. 60218-// - The old tests had an ad-hoc session initialization process. The regtest 60219-// environment has had more time devoted to its initialization, and has a 60220-// more convenient API. 60221-// - The old tests lacked documentation, and often had failures that were hard 60222-// to understand. By starting from scratch, we can revisit these aspects. 60223-// 60224-// # Special files 60225-// 60226-// There are three types of file within the test archive that are given special 60227-// treatment by the test runner: 60228-// - "flags": this file is treated as a whitespace-separated list of flags 60229-// that configure the MarkerTest instance. For example, -min_go=go1.18 sets 60230-// the minimum required Go version for the test. 60231-// TODO(rfindley): support flag values containing whitespace. 60232-// - "settings.json": this file is parsed as JSON, and used as the 60233-// session configuration (see gopls/doc/settings.md) 60234-// - "env": this file is parsed as a list of VAR=VALUE fields specifying the 60235-// editor environment. 60236-// - Golden files: Within the archive, file names starting with '@' are 60237-// treated as "golden" content, and are not written to disk, but instead are 60238-// made available to test methods expecting an argument of type *Golden, 60239-// using the identifier following '@'. For example, if the first parameter of 60240-// Foo were of type *Golden, the test runner would convert the identifier a 60241-// in the call @foo(a, "b", 3) into a *Golden by collecting golden file 60242-// data starting with "@a/". 60243-// 60244-// # Marker types 60245-// 60246-// The following markers are supported within marker tests: 60247-// 60248-// - diag(location, regexp): specifies an expected diagnostic matching the 60249-// given regexp at the given location. The test runner requires 60250-// a 1:1 correspondence between observed diagnostics and diag annotations 60251-// 60252-// - def(src, dst location): perform a textDocument/definition request at 60253-// the src location, and check the the result points to the dst location. 60254-// 60255-// - hover(src, dst location, g Golden): perform a textDocument/hover at the 60256-// src location, and checks that the result is the dst location, with hover 60257-// content matching "hover.md" in the golden data g. 60258-// 60259-// - loc(name, location): specifies the name for a location in the source. These 60260-// locations may be referenced by other markers. 60261-// 60262-// - rename(location, new, golden): specifies a renaming of the 60263-// identifier at the specified location to the new name. 60264-// The golden directory contains the transformed files. 60265-// 60266-// - renameerr(location, new, wantError): specifies a renaming that 60267-// fails with an error that matches the expectation. 60268-// 60269-// - suggestedfix(location, regexp, kind, golden): like diag, the location and 60270-// regexp identify an expected diagnostic. This diagnostic must 60271-// to have exactly one associated code action of the specified kind. 60272-// This action is executed for its editing effects on the source files. 60273-// Like rename, the golden directory contains the expected transformed files. 60274-// 60275-// # Argument conversion 60276-// 60277-// Marker arguments are first parsed by the go/expect package, which accepts 60278-// the following tokens as defined by the Go spec: 60279-// - string, int64, float64, and rune literals 60280-// - true and false 60281-// - nil 60282-// - identifiers (type expect.Identifier) 60283-// - regular expressions, denoted the two tokens re"abc" (type *regexp.Regexp) 60284-// 60285-// These values are passed as arguments to the corresponding parameter of the 60286-// test function. Additional value conversions may occur for these argument -> 60287-// parameter type pairs: 60288-// - string->regexp: the argument is parsed as a regular expressions. 60289-// - string->location: the argument is converted to the location of the first 60290-// instance of the argument in the partial line preceding the note. 60291-// - regexp->location: the argument is converted to the location of the first 60292-// match for the argument in the partial line preceding the note. If the 60293-// regular expression contains exactly one subgroup, the position of the 60294-// subgroup is used rather than the position of the submatch. 60295-// - name->location: the argument is replaced by the named location. 60296-// - name->Golden: the argument is used to look up golden content prefixed by 60297-// @<argument>. 60298-// - {string,regexp,identifier}->wantError: a wantError type specifies 60299-// an expected error message, either in the form of a substring that 60300-// must be present, a regular expression that it must match, or an 60301-// identifier (e.g. foo) such that the archive entry @foo 60302-// exists and contains the exact expected error. 60303-// 60304-// # Example 60305-// 60306-// Here is a complete example: 60307-// 60308-// -- a.go -- 60309-// package a 60310-// 60311-// const abc = 0x2a //@hover("b", "abc", abc),hover(" =", "abc", abc) 60312-// -- @abc/hover.md -- 60313-// ```go 60314-// const abc untyped int = 42 60315-// ``` 60316-// 60317-// @hover("b", "abc", abc),hover(" =", "abc", abc) 60318-// 60319-// In this example, the @hover annotation tells the test runner to run the 60320-// hoverMarker function, which has parameters: 60321-// 60322-// (mark marker, src, dsc protocol.Location, g *Golden). 60323-// 60324-// The first argument holds the test context, including fake editor with open 60325-// files, and sandboxed directory. 60326-// 60327-// Argument converters translate the "b" and "abc" arguments into locations by 60328-// interpreting each one as a regular expression and finding the location of 60329-// its first match on the preceding portion of the line, and the abc identifier 60330-// into a dictionary of golden content containing "hover.md". Then the 60331-// hoverMarker method executes a textDocument/hover LSP request at the src 60332-// position, and ensures the result spans "abc", with the markdown content from 60333-// hover.md. (Note that the markdown content includes the expect annotation as 60334-// the doc comment.) 60335-// 60336-// The next hover on the same line asserts the same result, but initiates the 60337-// hover immediately after "abc" in the source. This tests that we find the 60338-// preceding identifier when hovering. 60339-// 60340-// # Updating golden files 60341-// 60342-// To update golden content in the test archive, it is easier to regenerate 60343-// content automatically rather than edit it by hand. To do this, run the 60344-// tests with the -update flag. Only tests that actually run will be updated. 60345-// 60346-// In some cases, golden content will vary by Go version (for example, gopls 60347-// produces different markdown at Go versions before the 1.19 go/doc update). 60348-// By convention, the golden content in test archives should match the output 60349-// at Go tip. Each test function can normalize golden content for older Go 60350-// versions. 60351-// 60352-// Note that -update does not cause missing @diag or @loc markers to be added. 60353-// 60354-// # TODO 60355-// 60356-// This API is a work-in-progress, as we migrate existing marker tests from 60357-// internal/lsp/tests. 60358-// 60359-// Remaining TODO: 60360-// - parallelize/optimize test execution 60361-// - reorganize regtest packages (and rename to just 'test'?) 60362-// - Rename the files .txtar. 60363-// 60364-// Existing marker tests to port: 60365-// - CallHierarchy 60366-// - CodeLens 60367-// - Diagnostics 60368-// - CompletionItems 60369-// - Completions 60370-// - CompletionSnippets 60371-// - UnimportedCompletions 60372-// - DeepCompletions 60373-// - FuzzyCompletions 60374-// - CaseSensitiveCompletions 60375-// - RankCompletions 60376-// - FoldingRanges 60377-// - Formats 60378-// - Imports 60379-// - SemanticTokens 60380-// - SuggestedFixes 60381-// - FunctionExtractions 60382-// - MethodExtractions 60383-// - Definitions 60384-// - Implementations 60385-// - Highlights 60386-// - References 60387-// - Renames 60388-// - PrepareRenames 60389-// - Symbols 60390-// - InlayHints 60391-// - WorkspaceSymbols 60392-// - Signatures 60393-// - Links 60394-// - AddImport 60395-// - SelectionRanges 60396-func RunMarkerTests(t *testing.T, dir string) { 60397- // The marker tests must be able to run go/packages.Load. 60398- testenv.NeedsGoPackages(t) 60399- 60400- tests, err := loadMarkerTests(dir) 60401- if err != nil { 60402- t.Fatal(err) 60403- } 60404- 60405- // Opt: use a shared cache. 60406- // TODO(rfindley): opt: use a memoize store with no eviction. 60407- cache := cache.New(nil) 60408- 60409- for _, test := range tests { 60410- t.Run(test.name, func(t *testing.T) { 60411- // TODO(rfindley): it may be more useful to have full support for build 60412- // constraints. 60413- if test.minGoVersion != "" { 60414- var go1point int 60415- if _, err := fmt.Sscanf(test.minGoVersion, "go1.%d", &go1point); err != nil { 60416- t.Fatalf("parsing -min_go version: %v", err) 60417- } 60418- testenv.NeedsGo1Point(t, 18) 60419- } 60420- config := fake.EditorConfig{ 60421- Settings: test.settings, 60422- Env: test.env, 60423- } 60424- run := &markerTestRun{ 60425- test: test, 60426- env: newEnv(t, cache, test.files, config), 60427- 60428- locations: make(map[expect.Identifier]protocol.Location), 60429- diags: make(map[protocol.Location][]protocol.Diagnostic), 60430- } 60431- // TODO(rfindley): make it easier to clean up the regtest environment. 60432- defer run.env.Editor.Shutdown(context.Background()) // ignore error 60433- defer run.env.Sandbox.Close() // ignore error 60434- 60435- // Open all files so that we operate consistently with LSP clients, and 60436- // (pragmatically) so that we have a Mapper available via the fake 60437- // editor. 60438- // 60439- // This also allows avoiding mutating the editor state in tests. 60440- for file := range test.files { 60441- run.env.OpenFile(file) 60442- } 60443- 60444- // Pre-process locations. 60445- var markers []marker 60446- for _, note := range test.notes { 60447- mark := marker{run: run, note: note} 60448- switch note.Name { 60449- case "loc": 60450- mark.execute() 60451- default: 60452- markers = append(markers, mark) 60453- } 60454- } 60455- 60456- // Wait for the didOpen notifications to be processed, then collect 60457- // diagnostics. 60458- var diags map[string]*protocol.PublishDiagnosticsParams 60459- run.env.AfterChange(ReadAllDiagnostics(&diags)) 60460- for path, params := range diags { 60461- uri := run.env.Sandbox.Workdir.URI(path) 60462- for _, diag := range params.Diagnostics { 60463- loc := protocol.Location{ 60464- URI: uri, 60465- Range: diag.Range, 60466- } 60467- run.diags[loc] = append(run.diags[loc], diag) 60468- } 60469- } 60470- 60471- // Invoke each remaining marker in the test. 60472- for _, mark := range markers { 60473- mark.execute() 60474- } 60475- 60476- // Any remaining (un-eliminated) diagnostics are an error. 60477- for loc, diags := range run.diags { 60478- for _, diag := range diags { 60479- t.Errorf("%s: unexpected diagnostic: %q", run.fmtLoc(loc), diag.Message) 60480- } 60481- } 60482- 60483- formatted, err := formatTest(test) 60484- if err != nil { 60485- t.Errorf("formatTest: %v", err) 60486- } else if *update { 60487- filename := filepath.Join(dir, test.name) 60488- if err := os.WriteFile(filename, formatted, 0644); err != nil { 60489- t.Error(err) 60490- } 60491- } else { 60492- // On go 1.19 and later, verify that the testdata has not changed. 60493- // 60494- // On earlier Go versions, the golden test data varies due to different 60495- // markdown escaping. 60496- // 60497- // Only check this if the test hasn't already failed, otherwise we'd 60498- // report duplicate mismatches of golden data. 60499- if testenv.Go1Point() >= 19 && !t.Failed() { 60500- // Otherwise, verify that formatted content matches. 60501- if diff := compare.NamedText("formatted", "on-disk", string(formatted), string(test.content)); diff != "" { 60502- t.Errorf("formatted test does not match on-disk content:\n%s", diff) 60503- } 60504- } 60505- } 60506- }) 60507- } 60508-} 60509- 60510-// A marker holds state for the execution of a single @marker 60511-// annotation in the source. 60512-type marker struct { 60513- run *markerTestRun 60514- note *expect.Note 60515-} 60516- 60517-// errorf reports an error with a prefix indicating the position of the marker note. 60518-func (mark marker) errorf(format string, args ...interface{}) { 60519- msg := fmt.Sprintf(format, args...) 60520- // TODO(adonovan): consider using fmt.Fprintf(os.Stderr)+t.Fail instead of 60521- // t.Errorf to avoid reporting uninteresting positions in the Go source of 60522- // the driver. However, this loses the order of stderr wrt "FAIL: TestFoo" 60523- // subtest dividers. 60524- mark.run.env.T.Errorf("%s: %s", mark.run.fmtPos(mark.note.Pos), msg) 60525-} 60526- 60527-// execute invokes the marker's function with the arguments from note. 60528-func (mark marker) execute() { 60529- fn, ok := markerFuncs[mark.note.Name] 60530- if !ok { 60531- mark.errorf("no marker function named %s", mark.note.Name) 60532- return 60533- } 60534- 60535- // The first converter corresponds to the *Env argument. 60536- // All others must be converted from the marker syntax. 60537- if got, want := len(mark.note.Args), len(fn.converters); got != want { 60538- mark.errorf("got %d arguments to %s, expect %d", got, mark.note.Name, want) 60539- return 60540- } 60541- 60542- args := []reflect.Value{reflect.ValueOf(mark)} 60543- for i, in := range mark.note.Args { 60544- // Special handling for the blank identifier: treat it as the zero 60545- // value. 60546- if ident, ok := in.(expect.Identifier); ok && ident == "_" { 60547- zero := reflect.Zero(fn.paramTypes[i]) 60548- args = append(args, zero) 60549- continue 60550- } 60551- out, err := fn.converters[i](mark, in) 60552- if err != nil { 60553- mark.errorf("converting argument #%d of %s (%v): %v", i, mark.note.Name, in, err) 60554- return 60555- } 60556- args = append(args, reflect.ValueOf(out)) 60557- } 60558- 60559- fn.fn.Call(args) 60560-} 60561- 60562-// Supported marker functions. 60563-// 60564-// Each marker function must accept a marker as its first argument, with 60565-// subsequent arguments converted from the marker arguments. 60566-// 60567-// Marker funcs should not mutate the test environment (e.g. via opening files 60568-// or applying edits in the editor). 60569-var markerFuncs = map[string]markerFunc{ 60570- "def": makeMarkerFunc(defMarker), 60571- "diag": makeMarkerFunc(diagMarker), 60572- "hover": makeMarkerFunc(hoverMarker), 60573- "loc": makeMarkerFunc(locMarker), 60574- "rename": makeMarkerFunc(renameMarker), 60575- "renameerr": makeMarkerFunc(renameErrMarker), 60576- "suggestedfix": makeMarkerFunc(suggestedfixMarker), 60577-} 60578- 60579-// markerTest holds all the test data extracted from a test txtar archive. 60580-// 60581-// See the documentation for RunMarkerTests for more information on the archive 60582-// format. 60583-type markerTest struct { 60584- name string // relative path to the txtar file in the testdata dir 60585- fset *token.FileSet // fileset used for parsing notes 60586- content []byte // raw test content 60587- archive *txtar.Archive // original test archive 60588- settings map[string]interface{} // gopls settings 60589- env map[string]string // editor environment 60590- files map[string][]byte // data files from the archive (excluding special files) 60591- notes []*expect.Note // extracted notes from data files 60592- golden map[string]*Golden // extracted golden content, by identifier name 60593- 60594- // flags holds flags extracted from the special "flags" archive file. 60595- flags []string 60596- // Parsed flags values. 60597- minGoVersion string 60598-} 60599- 60600-// flagSet returns the flagset used for parsing the special "flags" file in the 60601-// test archive. 60602-func (t *markerTest) flagSet() *flag.FlagSet { 60603- flags := flag.NewFlagSet(t.name, flag.ContinueOnError) 60604- flags.StringVar(&t.minGoVersion, "min_go", "", "if set, the minimum go1.X version required for this test") 60605- return flags 60606-} 60607- 60608-func (t *markerTest) getGolden(id string) *Golden { 60609- golden, ok := t.golden[id] 60610- // If there was no golden content for this identifier, we must create one 60611- // to handle the case where -update is set: we need a place to store 60612- // the updated content. 60613- if !ok { 60614- golden = &Golden{id: id} 60615- 60616- // TODO(adonovan): the separation of markerTest (the 60617- // static aspects) from markerTestRun (the dynamic 60618- // ones) is evidently bogus because here we modify 60619- // markerTest during execution. Let's merge the two. 60620- t.golden[id] = golden 60621- } 60622- return golden 60623-} 60624- 60625-// Golden holds extracted golden content for a single @<name> prefix. 60626-// 60627-// When -update is set, golden captures the updated golden contents for later 60628-// writing. 60629-type Golden struct { 60630- id string 60631- data map[string][]byte // key "" => @id itself 60632- updated map[string][]byte 60633-} 60634- 60635-// Get returns golden content for the given name, which corresponds to the 60636-// relative path following the golden prefix @<name>/. For example, to access 60637-// the content of @foo/path/to/result.json from the Golden associated with 60638-// @foo, name should be "path/to/result.json". 60639-// 60640-// If -update is set, the given update function will be called to get the 60641-// updated golden content that should be written back to testdata. 60642-// 60643-// Marker functions must use this method instead of accessing data entries 60644-// directly otherwise the -update operation will delete those entries. 60645-// 60646-// TODO(rfindley): rethink the logic here. We may want to separate Get and Set, 60647-// and not delete golden content that isn't set. 60648-func (g *Golden) Get(t testing.TB, name string, updated []byte) ([]byte, bool) { 60649- if existing, ok := g.updated[name]; ok { 60650- // Multiple tests may reference the same golden data, but if they do they 60651- // must agree about its expected content. 60652- if diff := compare.NamedText("existing", "updated", string(existing), string(updated)); diff != "" { 60653- t.Errorf("conflicting updates for golden data %s/%s:\n%s", g.id, name, diff) 60654- } 60655- } 60656- if g.updated == nil { 60657- g.updated = make(map[string][]byte) 60658- } 60659- g.updated[name] = updated 60660- if *update { 60661- return updated, true 60662- } 60663- 60664- res, ok := g.data[name] 60665- return res, ok 60666-} 60667- 60668-// loadMarkerTests walks the given dir looking for .txt files, which it 60669-// interprets as a txtar archive. 60670-// 60671-// See the documentation for RunMarkerTests for more details on the test data 60672-// archive. 60673-// 60674-// TODO(rfindley): this test could sanity check the results. For example, it is 60675-// too easy to write "// @" instead of "//@", which we will happy skip silently. 60676-func loadMarkerTests(dir string) ([]*markerTest, error) { 60677- var tests []*markerTest 60678- err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { 60679- if strings.HasSuffix(path, ".txt") { 60680- content, err := os.ReadFile(path) 60681- if err != nil { 60682- return err 60683- } 60684- name := strings.TrimPrefix(path, dir+string(filepath.Separator)) 60685- test, err := loadMarkerTest(name, content) 60686- if err != nil { 60687- return fmt.Errorf("%s: %v", path, err) 60688- } 60689- tests = append(tests, test) 60690- } 60691- return nil 60692- }) 60693- return tests, err 60694-} 60695- 60696-func loadMarkerTest(name string, content []byte) (*markerTest, error) { 60697- archive := txtar.Parse(content) 60698- test := &markerTest{ 60699- name: name, 60700- fset: token.NewFileSet(), 60701- content: content, 60702- archive: archive, 60703- files: make(map[string][]byte), 60704- golden: make(map[string]*Golden), 60705- } 60706- for _, file := range archive.Files { 60707- switch { 60708- case file.Name == "flags": 60709- test.flags = strings.Fields(string(file.Data)) 60710- if err := test.flagSet().Parse(test.flags); err != nil { 60711- return nil, fmt.Errorf("parsing flags: %v", err) 60712- } 60713- 60714- case file.Name == "settings.json": 60715- if err := json.Unmarshal(file.Data, &test.settings); err != nil { 60716- return nil, err 60717- } 60718- 60719- case file.Name == "env": 60720- test.env = make(map[string]string) 60721- fields := strings.Fields(string(file.Data)) 60722- for _, field := range fields { 60723- // TODO: use strings.Cut once we are on 1.18+. 60724- key, value, ok := cut(field, "=") 60725- if !ok { 60726- return nil, fmt.Errorf("env vars must be formatted as var=value, got %q", field) 60727- } 60728- test.env[key] = value 60729- } 60730- 60731- case strings.HasPrefix(file.Name, "@"): // golden content 60732- id, name, _ := cut(file.Name[len("@"):], "/") 60733- // Note that a file.Name of just "@id" gives (id, name) = ("id", ""). 60734- if _, ok := test.golden[id]; !ok { 60735- test.golden[id] = &Golden{ 60736- id: id, 60737- data: make(map[string][]byte), 60738- } 60739- } 60740- test.golden[id].data[name] = file.Data 60741- 60742- default: // ordinary file content 60743- notes, err := expect.Parse(test.fset, file.Name, file.Data) 60744- if err != nil { 60745- return nil, fmt.Errorf("parsing notes in %q: %v", file.Name, err) 60746- } 60747- test.notes = append(test.notes, notes...) 60748- test.files[file.Name] = file.Data 60749- } 60750- } 60751- 60752- return test, nil 60753-} 60754- 60755-// cut is a copy of strings.Cut. 60756-// 60757-// TODO: once we only support Go 1.18+, just use strings.Cut. 60758-func cut(s, sep string) (before, after string, found bool) { 60759- if i := strings.Index(s, sep); i >= 0 { 60760- return s[:i], s[i+len(sep):], true 60761- } 60762- return s, "", false 60763-} 60764- 60765-// formatTest formats the test as a txtar archive. 60766-func formatTest(test *markerTest) ([]byte, error) { 60767- arch := &txtar.Archive{ 60768- Comment: test.archive.Comment, 60769- } 60770- 60771- updatedGolden := make(map[string][]byte) 60772- for id, g := range test.golden { 60773- for name, data := range g.updated { 60774- filename := "@" + path.Join(id, name) // name may be "" 60775- updatedGolden[filename] = data 60776- } 60777- } 60778- 60779- // Preserve the original ordering of archive files. 60780- for _, file := range test.archive.Files { 60781- switch file.Name { 60782- // Preserve configuration files exactly as they were. They must have parsed 60783- // if we got this far. 60784- case "flags", "settings.json", "env": 60785- arch.Files = append(arch.Files, file) 60786- default: 60787- if _, ok := test.files[file.Name]; ok { // ordinary file 60788- arch.Files = append(arch.Files, file) 60789- } else if data, ok := updatedGolden[file.Name]; ok { // golden file 60790- arch.Files = append(arch.Files, txtar.File{Name: file.Name, Data: data}) 60791- delete(updatedGolden, file.Name) 60792- } 60793- } 60794- } 60795- 60796- // ...followed by any new golden files. 60797- var newGoldenFiles []txtar.File 60798- for filename, data := range updatedGolden { 60799- newGoldenFiles = append(newGoldenFiles, txtar.File{Name: filename, Data: data}) 60800- } 60801- // Sort new golden files lexically. 60802- sort.Slice(newGoldenFiles, func(i, j int) bool { 60803- return newGoldenFiles[i].Name < newGoldenFiles[j].Name 60804- }) 60805- arch.Files = append(arch.Files, newGoldenFiles...) 60806- 60807- return txtar.Format(arch), nil 60808-} 60809- 60810-// newEnv creates a new environment for a marker test. 60811-// 60812-// TODO(rfindley): simplify and refactor the construction of testing 60813-// environments across regtests, marker tests, and benchmarks. 60814-func newEnv(t *testing.T, cache *cache.Cache, files map[string][]byte, config fake.EditorConfig) *Env { 60815- sandbox, err := fake.NewSandbox(&fake.SandboxConfig{ 60816- RootDir: t.TempDir(), 60817- GOPROXY: "https://proxy.golang.org", 60818- Files: files, 60819- }) 60820- if err != nil { 60821- t.Fatal(err) 60822- } 60823- 60824- // Put a debug instance in the context to prevent logging to stderr. 60825- // See associated TODO in runner.go: we should revisit this pattern. 60826- ctx := context.Background() 60827- ctx = debug.WithInstance(ctx, "", "off") 60828- 60829- awaiter := NewAwaiter(sandbox.Workdir) 60830- ss := lsprpc.NewStreamServer(cache, false, hooks.Options) 60831- server := servertest.NewPipeServer(ss, jsonrpc2.NewRawStream) 60832- const skipApplyEdits = true // capture edits but don't apply them 60833- editor, err := fake.NewEditor(sandbox, config).Connect(ctx, server, awaiter.Hooks(), skipApplyEdits) 60834- if err != nil { 60835- sandbox.Close() // ignore error 60836- t.Fatal(err) 60837- } 60838- if err := awaiter.Await(ctx, InitialWorkspaceLoad); err != nil { 60839- sandbox.Close() // ignore error 60840- t.Fatal(err) 60841- } 60842- return &Env{ 60843- T: t, 60844- Ctx: ctx, 60845- Editor: editor, 60846- Sandbox: sandbox, 60847- Awaiter: awaiter, 60848- } 60849-} 60850- 60851-// A markerFunc is a reflectively callable @mark implementation function. 60852-type markerFunc struct { 60853- fn reflect.Value // the func to invoke 60854- paramTypes []reflect.Type // parameter types, for zero values 60855- converters []converter // to convert non-blank arguments 60856-} 60857- 60858-// A markerTestRun holds the state of one run of a marker test archive. 60859-type markerTestRun struct { 60860- test *markerTest 60861- env *Env 60862- 60863- // Collected information. 60864- // Each @diag/@suggestedfix marker eliminates an entry from diags. 60865- locations map[expect.Identifier]protocol.Location 60866- diags map[protocol.Location][]protocol.Diagnostic 60867-} 60868- 60869-// fmtLoc formats the given pos in the context of the test, using 60870-// archive-relative paths for files and including the line number in the full 60871-// archive file. 60872-func (run *markerTestRun) fmtPos(pos token.Pos) string { 60873- file := run.test.fset.File(pos) 60874- if file == nil { 60875- run.env.T.Errorf("position %d not in test fileset", pos) 60876- return "<invalid location>" 60877- } 60878- m, err := run.env.Editor.Mapper(file.Name()) 60879- if err != nil { 60880- run.env.T.Errorf("%s", err) 60881- return "<invalid location>" 60882- } 60883- loc, err := m.PosLocation(file, pos, pos) 60884- if err != nil { 60885- run.env.T.Errorf("Mapper(%s).PosLocation failed: %v", file.Name(), err) 60886- } 60887- return run.fmtLoc(loc) 60888-} 60889- 60890-// fmtLoc formats the given location in the context of the test, using 60891-// archive-relative paths for files and including the line number in the full 60892-// archive file. 60893-func (run *markerTestRun) fmtLoc(loc protocol.Location) string { 60894- if loc == (protocol.Location{}) { 60895- return "<missing location>" 60896- } 60897- lines := bytes.Count(run.test.archive.Comment, []byte("\n")) 60898- var name string 60899- for _, f := range run.test.archive.Files { 60900- lines++ // -- separator -- 60901- uri := run.env.Sandbox.Workdir.URI(f.Name) 60902- if uri == loc.URI { 60903- name = f.Name 60904- break 60905- } 60906- lines += bytes.Count(f.Data, []byte("\n")) 60907- } 60908- if name == "" { 60909- run.env.T.Errorf("unable to find %s in test archive", loc) 60910- return "<invalid location>" 60911- } 60912- m, err := run.env.Editor.Mapper(name) 60913- if err != nil { 60914- run.env.T.Errorf("internal error: %v", err) 60915- return "<invalid location>" 60916- } 60917- s, err := m.LocationSpan(loc) 60918- if err != nil { 60919- run.env.T.Errorf("error formatting location %s: %v", loc, err) 60920- return "<invalid location>" 60921- } 60922- 60923- innerSpan := fmt.Sprintf("%d:%d", s.Start().Line(), s.Start().Column()) // relative to the embedded file 60924- outerSpan := fmt.Sprintf("%d:%d", lines+s.Start().Line(), s.Start().Column()) // relative to the archive file 60925- if s.Start() != s.End() { 60926- if s.End().Line() == s.Start().Line() { 60927- innerSpan += fmt.Sprintf("-%d", s.End().Column()) 60928- outerSpan += fmt.Sprintf("-%d", s.End().Column()) 60929- } else { 60930- innerSpan += fmt.Sprintf("-%d:%d", s.End().Line(), s.End().Column()) 60931- innerSpan += fmt.Sprintf("-%d:%d", lines+s.End().Line(), s.End().Column()) 60932- } 60933- } 60934- 60935- return fmt.Sprintf("%s:%s (%s:%s)", name, innerSpan, run.test.name, outerSpan) 60936-} 60937- 60938-// makeMarkerFunc uses reflection to create a markerFunc for the given func value. 60939-func makeMarkerFunc(fn interface{}) markerFunc { 60940- mi := markerFunc{ 60941- fn: reflect.ValueOf(fn), 60942- } 60943- mtyp := mi.fn.Type() 60944- if mtyp.NumIn() == 0 || mtyp.In(0) != markerType { 60945- panic(fmt.Sprintf("marker function %#v must accept marker as its first argument", mi.fn)) 60946- } 60947- if mtyp.NumOut() != 0 { 60948- panic(fmt.Sprintf("marker function %#v must not have results", mi.fn)) 60949- } 60950- for a := 1; a < mtyp.NumIn(); a++ { 60951- in := mtyp.In(a) 60952- mi.paramTypes = append(mi.paramTypes, in) 60953- c := makeConverter(in) 60954- mi.converters = append(mi.converters, c) 60955- } 60956- return mi 60957-} 60958- 60959-// ---- converters ---- 60960- 60961-// converter is the signature of argument converters. 60962-// A converter should return an error rather than calling marker.errorf(). 60963-type converter func(marker, interface{}) (interface{}, error) 60964- 60965-// Types with special conversions. 60966-var ( 60967- goldenType = reflect.TypeOf(&Golden{}) 60968- locationType = reflect.TypeOf(protocol.Location{}) 60969- markerType = reflect.TypeOf(marker{}) 60970- regexpType = reflect.TypeOf(®exp.Regexp{}) 60971- wantErrorType = reflect.TypeOf(wantError{}) 60972-) 60973- 60974-func makeConverter(paramType reflect.Type) converter { 60975- switch paramType { 60976- case goldenType: 60977- return goldenConverter 60978- case locationType: 60979- return locationConverter 60980- case wantErrorType: 60981- return wantErrorConverter 60982- default: 60983- return func(_ marker, arg interface{}) (interface{}, error) { 60984- if argType := reflect.TypeOf(arg); argType != paramType { 60985- return nil, fmt.Errorf("cannot convert type %s to %s", argType, paramType) 60986- } 60987- return arg, nil 60988- } 60989- } 60990-} 60991- 60992-// locationConverter converts a string argument into the protocol location 60993-// corresponding to the first position of the string in the line preceding the 60994-// note. 60995-func locationConverter(mark marker, arg interface{}) (interface{}, error) { 60996- switch arg := arg.(type) { 60997- case string: 60998- startOff, preceding, m, err := linePreceding(mark.run, mark.note.Pos) 60999- if err != nil { 61000- return protocol.Location{}, err 61001- } 61002- idx := bytes.Index(preceding, []byte(arg)) 61003- if idx < 0 { 61004- return nil, fmt.Errorf("substring %q not found in %q", arg, preceding) 61005- } 61006- off := startOff + idx 61007- return m.OffsetLocation(off, off+len(arg)) 61008- case *regexp.Regexp: 61009- return findRegexpInLine(mark.run, mark.note.Pos, arg) 61010- case expect.Identifier: 61011- loc, ok := mark.run.locations[arg] 61012- if !ok { 61013- return nil, fmt.Errorf("no location named %q", arg) 61014- } 61015- return loc, nil 61016- default: 61017- return nil, fmt.Errorf("cannot convert argument type %T to location (must be a string to match the preceding line)", arg) 61018- } 61019-} 61020- 61021-// findRegexpInLine searches the partial line preceding pos for a match for the 61022-// regular expression re, returning a location spanning the first match. If re 61023-// contains exactly one subgroup, the position of this subgroup match is 61024-// returned rather than the position of the full match. 61025-func findRegexpInLine(run *markerTestRun, pos token.Pos, re *regexp.Regexp) (protocol.Location, error) { 61026- startOff, preceding, m, err := linePreceding(run, pos) 61027- if err != nil { 61028- return protocol.Location{}, err 61029- } 61030- 61031- matches := re.FindSubmatchIndex(preceding) 61032- if len(matches) == 0 { 61033- return protocol.Location{}, fmt.Errorf("no match for regexp %q found in %q", re, string(preceding)) 61034- } 61035- var start, end int 61036- switch len(matches) { 61037- case 2: 61038- // no subgroups: return the range of the regexp expression 61039- start, end = matches[0], matches[1] 61040- case 4: 61041- // one subgroup: return its range 61042- start, end = matches[2], matches[3] 61043- default: 61044- return protocol.Location{}, fmt.Errorf("invalid location regexp %q: expect either 0 or 1 subgroups, got %d", re, len(matches)/2-1) 61045- } 61046- 61047- return m.OffsetLocation(start+startOff, end+startOff) 61048-} 61049- 61050-func linePreceding(run *markerTestRun, pos token.Pos) (int, []byte, *protocol.Mapper, error) { 61051- file := run.test.fset.File(pos) 61052- posn := safetoken.Position(file, pos) 61053- lineStart := file.LineStart(posn.Line) 61054- startOff, endOff, err := safetoken.Offsets(file, lineStart, pos) 61055- if err != nil { 61056- return 0, nil, nil, err 61057- } 61058- m, err := run.env.Editor.Mapper(file.Name()) 61059- if err != nil { 61060- return 0, nil, nil, err 61061- } 61062- return startOff, m.Content[startOff:endOff], m, nil 61063-} 61064- 61065-// wantErrorConverter converts a string, regexp, or identifier 61066-// argument into a wantError. The string is a substring of the 61067-// expected error, the regexp is a pattern than matches the expected 61068-// error, and the identifier is a golden file containing the expected 61069-// error. 61070-func wantErrorConverter(mark marker, arg interface{}) (interface{}, error) { 61071- switch arg := arg.(type) { 61072- case string: 61073- return wantError{substr: arg}, nil 61074- case *regexp.Regexp: 61075- return wantError{pattern: arg}, nil 61076- case expect.Identifier: 61077- golden := mark.run.test.getGolden(string(arg)) 61078- return wantError{golden: golden}, nil 61079- default: 61080- return nil, fmt.Errorf("cannot convert %T to wantError (want: string, regexp, or identifier)", arg) 61081- } 61082-} 61083- 61084-// A wantError represents an expectation of a specific error message. 61085-// 61086-// It may be indicated in one of three ways, in 'expect' notation: 61087-// - an identifier 'foo', to compare with the contents of the golden section @foo; 61088-// - a pattern expression re"ab.*c", to match against a regular expression; 61089-// - a string literal "abc", to check for a substring. 61090-type wantError struct { 61091- golden *Golden 61092- pattern *regexp.Regexp 61093- substr string 61094-} 61095- 61096-func (we wantError) String() string { 61097- if we.golden != nil { 61098- return fmt.Sprintf("error from @%s entry", we.golden.id) 61099- } else if we.pattern != nil { 61100- return fmt.Sprintf("error matching %#q", we.pattern) 61101- } else { 61102- return fmt.Sprintf("error with substring %q", we.substr) 61103- } 61104-} 61105- 61106-// check asserts that 'err' matches the wantError's expectations. 61107-func (we wantError) check(mark marker, err error) { 61108- if err == nil { 61109- mark.errorf("@%s succeeded unexpectedly, want %v", mark.note.Name, we) 61110- return 61111- } 61112- got := err.Error() 61113- 61114- if we.golden != nil { 61115- // Error message must match @id golden file. 61116- wantBytes, ok := we.golden.Get(mark.run.env.T, "", []byte(got)) 61117- if !ok { 61118- mark.errorf("@%s: missing @%s entry", mark.note.Name, we.golden.id) 61119- return 61120- } 61121- want := strings.TrimSpace(string(wantBytes)) 61122- if got != want { 61123- // (ignore leading/trailing space) 61124- mark.errorf("@%s failed with wrong error: got:\n%s\nwant:\n%s\ndiff:\n%s", 61125- mark.note.Name, got, want, compare.Text(want, got)) 61126- } 61127- 61128- } else if we.pattern != nil { 61129- // Error message must match regular expression pattern. 61130- if !we.pattern.MatchString(got) { 61131- mark.errorf("got error %q, does not match pattern %#q", got, we.pattern) 61132- } 61133- 61134- } else if !strings.Contains(got, we.substr) { 61135- // Error message must contain expected substring. 61136- mark.errorf("got error %q, want substring %q", got, we.substr) 61137- } 61138-} 61139- 61140-// goldenConverter converts an identifier into the Golden directory of content 61141-// prefixed by @<ident> in the test archive file. 61142-func goldenConverter(mark marker, arg interface{}) (interface{}, error) { 61143- switch arg := arg.(type) { 61144- case expect.Identifier: 61145- return mark.run.test.getGolden(string(arg)), nil 61146- default: 61147- return nil, fmt.Errorf("invalid input type %T: golden key must be an identifier", arg) 61148- } 61149-} 61150- 61151-// checkChangedFiles compares the files changed by an operation with their expected (golden) state. 61152-func checkChangedFiles(mark marker, changed map[string][]byte, golden *Golden) { 61153- // Check changed files match expectations. 61154- for filename, got := range changed { 61155- if want, ok := golden.Get(mark.run.env.T, filename, got); !ok { 61156- mark.errorf("%s: unexpected change to file %s; got:\n%s", 61157- mark.note.Name, filename, got) 61158- 61159- } else if string(got) != string(want) { 61160- mark.errorf("%s: wrong file content for %s: got:\n%s\nwant:\n%s\ndiff:\n%s", 61161- mark.note.Name, filename, got, want, 61162- compare.Bytes(want, got)) 61163- } 61164- } 61165- 61166- // Report unmet expectations. 61167- for filename := range golden.data { 61168- if _, ok := changed[filename]; !ok { 61169- want, _ := golden.Get(mark.run.env.T, filename, nil) 61170- mark.errorf("%s: missing change to file %s; want:\n%s", 61171- mark.note.Name, filename, want) 61172- } 61173- } 61174-} 61175- 61176-// ---- marker functions ---- 61177- 61178-// defMarker implements the @godef marker, running textDocument/definition at 61179-// the given src location and asserting that there is exactly one resulting 61180-// location, matching dst. 61181-// 61182-// TODO(rfindley): support a variadic destination set. 61183-func defMarker(mark marker, src, dst protocol.Location) { 61184- got := mark.run.env.GoToDefinition(src) 61185- if got != dst { 61186- mark.errorf("definition location does not match:\n\tgot: %s\n\twant %s", 61187- mark.run.fmtLoc(got), mark.run.fmtLoc(dst)) 61188- } 61189-} 61190- 61191-// hoverMarker implements the @hover marker, running textDocument/hover at the 61192-// given src location and asserting that the resulting hover is over the dst 61193-// location (typically a span surrounding src), and that the markdown content 61194-// matches the golden content. 61195-func hoverMarker(mark marker, src, dst protocol.Location, golden *Golden) { 61196- content, gotDst := mark.run.env.Hover(src) 61197- if gotDst != dst { 61198- mark.errorf("hover location does not match:\n\tgot: %s\n\twant %s)", mark.run.fmtLoc(gotDst), mark.run.fmtLoc(dst)) 61199- } 61200- gotMD := "" 61201- if content != nil { 61202- gotMD = content.Value 61203- } 61204- wantMD := "" 61205- if golden != nil { 61206- wantBytes, _ := golden.Get(mark.run.env.T, "hover.md", []byte(gotMD)) 61207- wantMD = string(wantBytes) 61208- } 61209- // Normalize newline termination: archive files can't express non-newline 61210- // terminated files. 61211- if strings.HasSuffix(wantMD, "\n") && !strings.HasSuffix(gotMD, "\n") { 61212- gotMD += "\n" 61213- } 61214- if diff := tests.DiffMarkdown(wantMD, gotMD); diff != "" { 61215- mark.errorf("hover markdown mismatch (-want +got):\n%s", diff) 61216- } 61217-} 61218- 61219-// locMarker implements the @loc marker. It is executed before other 61220-// markers, so that locations are available. 61221-func locMarker(mark marker, name expect.Identifier, loc protocol.Location) { 61222- mark.run.locations[name] = loc 61223-} 61224- 61225-// diagMarker implements the @diag marker. It eliminates diagnostics from 61226-// the observed set in mark.test. 61227-func diagMarker(mark marker, loc protocol.Location, re *regexp.Regexp) { 61228- if _, err := removeDiagnostic(mark, loc, re); err != nil { 61229- mark.errorf("%v", err) 61230- } 61231-} 61232- 61233-func removeDiagnostic(mark marker, loc protocol.Location, re *regexp.Regexp) (protocol.Diagnostic, error) { 61234- diags := mark.run.diags[loc] 61235- for i, diag := range diags { 61236- if re.MatchString(diag.Message) { 61237- mark.run.diags[loc] = append(diags[:i], diags[i+1:]...) 61238- return diag, nil 61239- } 61240- } 61241- return protocol.Diagnostic{}, fmt.Errorf("no diagnostic matches %q", re) 61242-} 61243- 61244-// renameMarker implements the @rename(location, new, golden) marker. 61245-func renameMarker(mark marker, loc protocol.Location, newName expect.Identifier, golden *Golden) { 61246- changed, err := rename(mark.run.env, loc, string(newName)) 61247- if err != nil { 61248- mark.errorf("rename failed: %v. (Use @renameerr for expected errors.)", err) 61249- return 61250- } 61251- checkChangedFiles(mark, changed, golden) 61252-} 61253- 61254-// renameErrMarker implements the @renamererr(location, new, error) marker. 61255-func renameErrMarker(mark marker, loc protocol.Location, newName expect.Identifier, wantErr wantError) { 61256- _, err := rename(mark.run.env, loc, string(newName)) 61257- wantErr.check(mark, err) 61258-} 61259- 61260-// rename returns the new contents of the files that would be modified 61261-// by renaming the identifier at loc to newName. 61262-func rename(env *Env, loc protocol.Location, newName string) (map[string][]byte, error) { 61263- // We call Server.Rename directly, instead of 61264- // env.Editor.Rename(env.Ctx, loc, newName) 61265- // to isolate Rename from PrepareRename, and because we don't 61266- // want to modify the file system in a scenario with multiple 61267- // @rename markers. 61268- 61269- editMap, err := env.Editor.Server.Rename(env.Ctx, &protocol.RenameParams{ 61270- TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, 61271- Position: loc.Range.Start, 61272- NewName: string(newName), 61273- }) 61274- if err != nil { 61275- return nil, err 61276- } 61277- 61278- return applyDocumentChanges(env, editMap.DocumentChanges) 61279-} 61280- 61281-// applyDocumentChanges returns the effect of applying the document 61282-// changes to the contents of the Editor buffers. The actual editor 61283-// buffers are unchanged. 61284-func applyDocumentChanges(env *Env, changes []protocol.DocumentChanges) (map[string][]byte, error) { 61285- result := make(map[string][]byte) 61286- for _, change := range changes { 61287- if change.RenameFile != nil { 61288- // rename 61289- oldFile := env.Sandbox.Workdir.URIToPath(change.RenameFile.OldURI) 61290- newFile := env.Sandbox.Workdir.URIToPath(change.RenameFile.NewURI) 61291- mapper, err := env.Editor.Mapper(oldFile) 61292- if err != nil { 61293- return nil, err 61294- } 61295- result[newFile] = mapper.Content 61296- 61297- } else { 61298- // edit 61299- filename := env.Sandbox.Workdir.URIToPath(change.TextDocumentEdit.TextDocument.URI) 61300- mapper, err := env.Editor.Mapper(filename) 61301- if err != nil { 61302- return nil, err 61303- } 61304- patched, _, err := source.ApplyProtocolEdits(mapper, change.TextDocumentEdit.Edits) 61305- if err != nil { 61306- return nil, err 61307- } 61308- result[filename] = patched 61309- } 61310- } 61311- 61312- return result, nil 61313-} 61314- 61315-// suggestedfixMarker implements the @suggestedfix(location, regexp, 61316-// kind, golden) marker. It acts like @diag(location, regexp), to set 61317-// the expectation of a diagnostic, but then it applies the first code 61318-// action of the specified kind suggested by the matched diagnostic. 61319-func suggestedfixMarker(mark marker, loc protocol.Location, re *regexp.Regexp, actionKind string, golden *Golden) { 61320- // Find and remove the matching diagnostic. 61321- diag, err := removeDiagnostic(mark, loc, re) 61322- if err != nil { 61323- mark.errorf("%v", err) 61324- return 61325- } 61326- 61327- // Apply the fix it suggests. 61328- changed, err := suggestedfix(mark.run.env, loc, diag, actionKind) 61329- if err != nil { 61330- mark.errorf("suggestedfix failed: %v. (Use @suggestedfixerr for expected errors.)", err) 61331- return 61332- } 61333- 61334- // Check the file state. 61335- checkChangedFiles(mark, changed, golden) 61336-} 61337- 61338-func suggestedfix(env *Env, loc protocol.Location, diag protocol.Diagnostic, actionKind string) (map[string][]byte, error) { 61339- 61340- // Request all code actions that apply to the diagnostic. 61341- // (The protocol supports filtering using Context.Only={actionKind} 61342- // but we can give a better error if we don't filter.) 61343- actions, err := env.Editor.Server.CodeAction(env.Ctx, &protocol.CodeActionParams{ 61344- TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, 61345- Range: diag.Range, 61346- Context: protocol.CodeActionContext{ 61347- Only: nil, // => all kinds 61348- Diagnostics: []protocol.Diagnostic{diag}, 61349- }, 61350- }) 61351- if err != nil { 61352- return nil, err 61353- } 61354- 61355- // Find the sole candidates CodeAction of the specified kind (e.g. refactor.rewrite). 61356- var candidates []protocol.CodeAction 61357- for _, act := range actions { 61358- if act.Kind == protocol.CodeActionKind(actionKind) { 61359- candidates = append(candidates, act) 61360- } 61361- } 61362- if len(candidates) != 1 { 61363- for _, act := range actions { 61364- env.T.Logf("found CodeAction Kind=%s Title=%q", act.Kind, act.Title) 61365- } 61366- return nil, fmt.Errorf("found %d CodeActions of kind %s for this diagnostic, want 1", len(candidates), actionKind) 61367- } 61368- action := candidates[0] 61369- 61370- // An action may specify an edit and/or a command, to be 61371- // applied in that order. But since applyDocumentChanges(env, 61372- // action.Edit.DocumentChanges) doesn't compose, for now we 61373- // assert that all commands used in the @suggestedfix tests 61374- // return only a command. 61375- if action.Edit.DocumentChanges != nil { 61376- env.T.Errorf("internal error: discarding unexpected CodeAction{Kind=%s, Title=%q}.Edit.DocumentChanges", action.Kind, action.Title) 61377- } 61378- if action.Command == nil { 61379- return nil, fmt.Errorf("missing CodeAction{Kind=%s, Title=%q}.Command", action.Kind, action.Title) 61380- } 61381- 61382- // This is a typical CodeAction command: 61383- // 61384- // Title: "Implement error" 61385- // Command: gopls.apply_fix 61386- // Arguments: [{"Fix":"stub_methods","URI":".../a.go","Range":...}}] 61387- // 61388- // The client makes an ExecuteCommand RPC to the server, 61389- // which dispatches it to the ApplyFix handler. 61390- // ApplyFix dispatches to the "stub_methods" suggestedfix hook (the meat). 61391- // The server then makes an ApplyEdit RPC to the client, 61392- // whose Awaiter hook gathers the edits instead of applying them. 61393- 61394- _ = env.Awaiter.takeDocumentChanges() // reset (assuming Env is confined to this thread) 61395- 61396- if _, err := env.Editor.Server.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{ 61397- Command: action.Command.Command, 61398- Arguments: action.Command.Arguments, 61399- }); err != nil { 61400- env.T.Fatalf("error converting command %q to edits: %v", action.Command.Command, err) 61401- } 61402- 61403- return applyDocumentChanges(env, env.Awaiter.takeDocumentChanges()) 61404-} 61405- 61406-// TODO(adonovan): suggestedfixerr 61407diff -urN a/gopls/internal/lsp/regtest/options.go b/gopls/internal/lsp/regtest/options.go 61408--- a/gopls/internal/lsp/regtest/options.go 2000-01-01 00:00:00.000000000 -0000 61409+++ b/gopls/internal/lsp/regtest/options.go 1970-01-01 00:00:00.000000000 +0000 61410@@ -1,105 +0,0 @@ 61411-// Copyright 2022 The Go Authors. All rights reserved. 61412-// Use of this source code is governed by a BSD-style 61413-// license that can be found in the LICENSE file. 61414- 61415-package regtest 61416- 61417-import "golang.org/x/tools/gopls/internal/lsp/fake" 61418- 61419-type runConfig struct { 61420- editor fake.EditorConfig 61421- sandbox fake.SandboxConfig 61422- modes Mode 61423- skipHooks bool 61424-} 61425- 61426-// A RunOption augments the behavior of the test runner. 61427-type RunOption interface { 61428- set(*runConfig) 61429-} 61430- 61431-type optionSetter func(*runConfig) 61432- 61433-func (f optionSetter) set(opts *runConfig) { 61434- f(opts) 61435-} 61436- 61437-// ProxyFiles configures a file proxy using the given txtar-encoded string. 61438-func ProxyFiles(txt string) RunOption { 61439- return optionSetter(func(opts *runConfig) { 61440- opts.sandbox.ProxyFiles = fake.UnpackTxt(txt) 61441- }) 61442-} 61443- 61444-// Modes configures the execution modes that the test should run in. 61445-// 61446-// By default, modes are configured by the test runner. If this option is set, 61447-// it overrides the set of default modes and the test runs in exactly these 61448-// modes. 61449-func Modes(modes Mode) RunOption { 61450- return optionSetter(func(opts *runConfig) { 61451- if opts.modes != 0 { 61452- panic("modes set more than once") 61453- } 61454- opts.modes = modes 61455- }) 61456-} 61457- 61458-// WindowsLineEndings configures the editor to use windows line endings. 61459-func WindowsLineEndings() RunOption { 61460- return optionSetter(func(opts *runConfig) { 61461- opts.editor.WindowsLineEndings = true 61462- }) 61463-} 61464- 61465-// Settings is a RunOption that sets user-provided configuration for the LSP 61466-// server. 61467-// 61468-// As a special case, the env setting must not be provided via Settings: use 61469-// EnvVars instead. 61470-type Settings map[string]interface{} 61471- 61472-func (s Settings) set(opts *runConfig) { 61473- if opts.editor.Settings == nil { 61474- opts.editor.Settings = make(map[string]interface{}) 61475- } 61476- for k, v := range s { 61477- opts.editor.Settings[k] = v 61478- } 61479-} 61480- 61481-// WorkspaceFolders configures the workdir-relative workspace folders to send 61482-// to the LSP server. By default the editor sends a single workspace folder 61483-// corresponding to the workdir root. To explicitly configure no workspace 61484-// folders, use WorkspaceFolders with no arguments. 61485-func WorkspaceFolders(relFolders ...string) RunOption { 61486- if len(relFolders) == 0 { 61487- // Use an empty non-nil slice to signal explicitly no folders. 61488- relFolders = []string{} 61489- } 61490- return optionSetter(func(opts *runConfig) { 61491- opts.editor.WorkspaceFolders = relFolders 61492- }) 61493-} 61494- 61495-// EnvVars sets environment variables for the LSP session. When applying these 61496-// variables to the session, the special string $SANDBOX_WORKDIR is replaced by 61497-// the absolute path to the sandbox working directory. 61498-type EnvVars map[string]string 61499- 61500-func (e EnvVars) set(opts *runConfig) { 61501- if opts.editor.Env == nil { 61502- opts.editor.Env = make(map[string]string) 61503- } 61504- for k, v := range e { 61505- opts.editor.Env[k] = v 61506- } 61507-} 61508- 61509-// InGOPATH configures the workspace working directory to be GOPATH, rather 61510-// than a separate working directory for use with modules. 61511-func InGOPATH() RunOption { 61512- return optionSetter(func(opts *runConfig) { 61513- opts.sandbox.InGoPath = true 61514- }) 61515-} 61516diff -urN a/gopls/internal/lsp/regtest/regtest.go b/gopls/internal/lsp/regtest/regtest.go 61517--- a/gopls/internal/lsp/regtest/regtest.go 2000-01-01 00:00:00.000000000 -0000 61518+++ b/gopls/internal/lsp/regtest/regtest.go 1970-01-01 00:00:00.000000000 +0000 61519@@ -1,153 +0,0 @@ 61520-// Copyright 2020 The Go Authors. All rights reserved. 61521-// Use of this source code is governed by a BSD-style 61522-// license that can be found in the LICENSE file. 61523- 61524-package regtest 61525- 61526-import ( 61527- "context" 61528- "flag" 61529- "fmt" 61530- "io/ioutil" 61531- "os" 61532- "runtime" 61533- "testing" 61534- "time" 61535- 61536- "golang.org/x/tools/gopls/internal/lsp/cmd" 61537- "golang.org/x/tools/gopls/internal/lsp/source" 61538- "golang.org/x/tools/internal/gocommand" 61539- "golang.org/x/tools/internal/memoize" 61540- "golang.org/x/tools/internal/testenv" 61541- "golang.org/x/tools/internal/tool" 61542-) 61543- 61544-var ( 61545- runSubprocessTests = flag.Bool("enable_gopls_subprocess_tests", false, "run regtests against a gopls subprocess") 61546- goplsBinaryPath = flag.String("gopls_test_binary", "", "path to the gopls binary for use as a remote, for use with the -enable_gopls_subprocess_tests flag") 61547- regtestTimeout = flag.Duration("regtest_timeout", defaultRegtestTimeout(), "if nonzero, default timeout for each regtest; defaults to GOPLS_REGTEST_TIMEOUT") 61548- skipCleanup = flag.Bool("regtest_skip_cleanup", false, "whether to skip cleaning up temp directories") 61549- printGoroutinesOnFailure = flag.Bool("regtest_print_goroutines", false, "whether to print goroutines info on failure") 61550- printLogs = flag.Bool("regtest_print_logs", false, "whether to print LSP logs") 61551-) 61552- 61553-func defaultRegtestTimeout() time.Duration { 61554- s := os.Getenv("GOPLS_REGTEST_TIMEOUT") 61555- if s == "" { 61556- return 0 61557- } 61558- d, err := time.ParseDuration(s) 61559- if err != nil { 61560- fmt.Fprintf(os.Stderr, "invalid GOPLS_REGTEST_TIMEOUT %q: %v\n", s, err) 61561- os.Exit(2) 61562- } 61563- return d 61564-} 61565- 61566-var runner *Runner 61567- 61568-type regtestRunner interface { 61569- Run(t *testing.T, files string, f TestFunc) 61570-} 61571- 61572-func Run(t *testing.T, files string, f TestFunc) { 61573- runner.Run(t, files, f) 61574-} 61575- 61576-func WithOptions(opts ...RunOption) configuredRunner { 61577- return configuredRunner{opts: opts} 61578-} 61579- 61580-type configuredRunner struct { 61581- opts []RunOption 61582-} 61583- 61584-func (r configuredRunner) Run(t *testing.T, files string, f TestFunc) { 61585- runner.Run(t, files, f, r.opts...) 61586-} 61587- 61588-type RunMultiple []struct { 61589- Name string 61590- Runner regtestRunner 61591-} 61592- 61593-func (r RunMultiple) Run(t *testing.T, files string, f TestFunc) { 61594- for _, runner := range r { 61595- t.Run(runner.Name, func(t *testing.T) { 61596- runner.Runner.Run(t, files, f) 61597- }) 61598- } 61599-} 61600- 61601-// DefaultModes returns the default modes to run for each regression test (they 61602-// may be reconfigured by the tests themselves). 61603-func DefaultModes() Mode { 61604- modes := Default 61605- if !testing.Short() { 61606- modes |= Experimental | Forwarded 61607- } 61608- if *runSubprocessTests { 61609- modes |= SeparateProcess 61610- } 61611- return modes 61612-} 61613- 61614-// Main sets up and tears down the shared regtest state. 61615-func Main(m *testing.M, hook func(*source.Options)) { 61616- // golang/go#54461: enable additional debugging around hanging Go commands. 61617- gocommand.DebugHangingGoCommands = true 61618- 61619- // If this magic environment variable is set, run gopls instead of the test 61620- // suite. See the documentation for runTestAsGoplsEnvvar for more details. 61621- if os.Getenv(runTestAsGoplsEnvvar) == "true" { 61622- tool.Main(context.Background(), cmd.New("gopls", "", nil, hook), os.Args[1:]) 61623- os.Exit(0) 61624- } 61625- 61626- testenv.ExitIfSmallMachine() 61627- 61628- // Disable GOPACKAGESDRIVER, as it can cause spurious test failures. 61629- os.Setenv("GOPACKAGESDRIVER", "off") 61630- 61631- flag.Parse() 61632- 61633- runner = &Runner{ 61634- DefaultModes: DefaultModes(), 61635- Timeout: *regtestTimeout, 61636- PrintGoroutinesOnFailure: *printGoroutinesOnFailure, 61637- SkipCleanup: *skipCleanup, 61638- OptionsHook: hook, 61639- store: memoize.NewStore(memoize.NeverEvict), 61640- } 61641- 61642- runner.goplsPath = *goplsBinaryPath 61643- if runner.goplsPath == "" { 61644- var err error 61645- runner.goplsPath, err = os.Executable() 61646- if err != nil { 61647- panic(fmt.Sprintf("finding test binary path: %v", err)) 61648- } 61649- } 61650- 61651- dir, err := ioutil.TempDir("", "gopls-regtest-") 61652- if err != nil { 61653- panic(fmt.Errorf("creating regtest temp directory: %v", err)) 61654- } 61655- runner.tempDir = dir 61656- 61657- var code int 61658- defer func() { 61659- if err := runner.Close(); err != nil { 61660- fmt.Fprintf(os.Stderr, "closing test runner: %v\n", err) 61661- // Regtest cleanup is broken in go1.12 and earlier, and sometimes flakes on 61662- // Windows due to file locking, but this is OK for our CI. 61663- // 61664- // Fail on go1.13+, except for windows and android which have shutdown problems. 61665- if testenv.Go1Point() >= 13 && runtime.GOOS != "windows" && runtime.GOOS != "android" { 61666- os.Exit(1) 61667- } 61668- } 61669- os.Exit(code) 61670- }() 61671- code = m.Run() 61672-} 61673diff -urN a/gopls/internal/lsp/regtest/runner.go b/gopls/internal/lsp/regtest/runner.go 61674--- a/gopls/internal/lsp/regtest/runner.go 2000-01-01 00:00:00.000000000 -0000 61675+++ b/gopls/internal/lsp/regtest/runner.go 1970-01-01 00:00:00.000000000 +0000 61676@@ -1,437 +0,0 @@ 61677-// Copyright 2020 The Go Authors. All rights reserved. 61678-// Use of this source code is governed by a BSD-style 61679-// license that can be found in the LICENSE file. 61680- 61681-package regtest 61682- 61683-import ( 61684- "bytes" 61685- "context" 61686- "fmt" 61687- "io" 61688- "io/ioutil" 61689- "net" 61690- "os" 61691- "path/filepath" 61692- "runtime" 61693- "runtime/pprof" 61694- "strings" 61695- "sync" 61696- "testing" 61697- "time" 61698- 61699- exec "golang.org/x/sys/execabs" 61700- 61701- "golang.org/x/tools/gopls/internal/lsp/cache" 61702- "golang.org/x/tools/gopls/internal/lsp/debug" 61703- "golang.org/x/tools/gopls/internal/lsp/fake" 61704- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 61705- "golang.org/x/tools/gopls/internal/lsp/protocol" 61706- "golang.org/x/tools/gopls/internal/lsp/source" 61707- "golang.org/x/tools/internal/jsonrpc2" 61708- "golang.org/x/tools/internal/jsonrpc2/servertest" 61709- "golang.org/x/tools/internal/memoize" 61710- "golang.org/x/tools/internal/testenv" 61711- "golang.org/x/tools/internal/xcontext" 61712-) 61713- 61714-// Mode is a bitmask that defines for which execution modes a test should run. 61715-// 61716-// Each mode controls several aspects of gopls' configuration: 61717-// - Which server options to use for gopls sessions 61718-// - Whether to use a shared cache 61719-// - Whether to use a shared server 61720-// - Whether to run the server in-process or in a separate process 61721-// 61722-// The behavior of each mode with respect to these aspects is summarized below. 61723-// TODO(rfindley, cleanup): rather than using arbitrary names for these modes, 61724-// we can compose them explicitly out of the features described here, allowing 61725-// individual tests more freedom in constructing problematic execution modes. 61726-// For example, a test could assert on a certain behavior when running with 61727-// experimental options on a separate process. Moreover, we could unify 'Modes' 61728-// with 'Options', and use RunMultiple rather than a hard-coded loop through 61729-// modes. 61730-// 61731-// Mode | Options | Shared Cache? | Shared Server? | In-process? 61732-// --------------------------------------------------------------------------- 61733-// Default | Default | Y | N | Y 61734-// Forwarded | Default | Y | Y | Y 61735-// SeparateProcess | Default | Y | Y | N 61736-// Experimental | Experimental | N | N | Y 61737-type Mode int 61738- 61739-const ( 61740- // Default mode runs gopls with the default options, communicating over pipes 61741- // to emulate the lsp sidecar execution mode, which communicates over 61742- // stdin/stdout. 61743- // 61744- // It uses separate servers for each test, but a shared cache, to avoid 61745- // duplicating work when processing GOROOT. 61746- Default Mode = 1 << iota 61747- 61748- // Forwarded uses the default options, but forwards connections to a shared 61749- // in-process gopls server. 61750- Forwarded 61751- 61752- // SeparateProcess uses the default options, but forwards connection to an 61753- // external gopls daemon. 61754- // 61755- // Only supported on GOOS=linux. 61756- SeparateProcess 61757- 61758- // Experimental enables all of the experimental configurations that are 61759- // being developed, and runs gopls in sidecar mode. 61760- // 61761- // It uses a separate cache for each test, to exercise races that may only 61762- // appear with cache misses. 61763- Experimental 61764-) 61765- 61766-func (m Mode) String() string { 61767- switch m { 61768- case Default: 61769- return "default" 61770- case Forwarded: 61771- return "forwarded" 61772- case SeparateProcess: 61773- return "separate process" 61774- case Experimental: 61775- return "experimental" 61776- default: 61777- return "unknown mode" 61778- } 61779-} 61780- 61781-// A Runner runs tests in gopls execution environments, as specified by its 61782-// modes. For modes that share state (for example, a shared cache or common 61783-// remote), any tests that execute on the same Runner will share the same 61784-// state. 61785-type Runner struct { 61786- // Configuration 61787- DefaultModes Mode // modes to run for each test 61788- Timeout time.Duration // per-test timeout, if set 61789- PrintGoroutinesOnFailure bool // whether to dump goroutines on test failure 61790- SkipCleanup bool // if set, don't delete test data directories when the test exits 61791- OptionsHook func(*source.Options) // if set, use these options when creating gopls sessions 61792- 61793- // Immutable state shared across test invocations 61794- goplsPath string // path to the gopls executable (for SeparateProcess mode) 61795- tempDir string // shared parent temp directory 61796- store *memoize.Store // shared store 61797- 61798- // Lazily allocated resources 61799- tsOnce sync.Once 61800- ts *servertest.TCPServer // shared in-process test server ("forwarded" mode) 61801- 61802- startRemoteOnce sync.Once 61803- remoteSocket string // unix domain socket for shared daemon ("separate process" mode) 61804- remoteErr error 61805- cancelRemote func() 61806-} 61807- 61808-type TestFunc func(t *testing.T, env *Env) 61809- 61810-// Run executes the test function in the default configured gopls execution 61811-// modes. For each a test run, a new workspace is created containing the 61812-// un-txtared files specified by filedata. 61813-func (r *Runner) Run(t *testing.T, files string, test TestFunc, opts ...RunOption) { 61814- // TODO(rfindley): this function has gotten overly complicated, and warrants 61815- // refactoring. 61816- t.Helper() 61817- checkBuilder(t) 61818- testenv.NeedsGoPackages(t) 61819- 61820- tests := []struct { 61821- name string 61822- mode Mode 61823- getServer func(func(*source.Options)) jsonrpc2.StreamServer 61824- }{ 61825- {"default", Default, r.defaultServer}, 61826- {"forwarded", Forwarded, r.forwardedServer}, 61827- {"separate_process", SeparateProcess, r.separateProcessServer}, 61828- {"experimental", Experimental, r.experimentalServer}, 61829- } 61830- 61831- for _, tc := range tests { 61832- tc := tc 61833- var config runConfig 61834- for _, opt := range opts { 61835- opt.set(&config) 61836- } 61837- modes := r.DefaultModes 61838- if config.modes != 0 { 61839- modes = config.modes 61840- } 61841- if modes&tc.mode == 0 { 61842- continue 61843- } 61844- 61845- t.Run(tc.name, func(t *testing.T) { 61846- // TODO(rfindley): once jsonrpc2 shutdown is fixed, we should not leak 61847- // goroutines in this test function. 61848- // stacktest.NoLeak(t) 61849- 61850- ctx := context.Background() 61851- if r.Timeout != 0 { 61852- var cancel context.CancelFunc 61853- ctx, cancel = context.WithTimeout(ctx, r.Timeout) 61854- defer cancel() 61855- } else if d, ok := testenv.Deadline(t); ok { 61856- timeout := time.Until(d) * 19 / 20 // Leave an arbitrary 5% for cleanup. 61857- var cancel context.CancelFunc 61858- ctx, cancel = context.WithTimeout(ctx, timeout) 61859- defer cancel() 61860- } 61861- 61862- // TODO(rfindley): do we need an instance at all? Can it be removed? 61863- ctx = debug.WithInstance(ctx, "", "off") 61864- 61865- rootDir := filepath.Join(r.tempDir, filepath.FromSlash(t.Name())) 61866- if err := os.MkdirAll(rootDir, 0755); err != nil { 61867- t.Fatal(err) 61868- } 61869- 61870- files := fake.UnpackTxt(files) 61871- if config.editor.WindowsLineEndings { 61872- for name, data := range files { 61873- files[name] = bytes.ReplaceAll(data, []byte("\n"), []byte("\r\n")) 61874- } 61875- } 61876- config.sandbox.Files = files 61877- config.sandbox.RootDir = rootDir 61878- sandbox, err := fake.NewSandbox(&config.sandbox) 61879- if err != nil { 61880- t.Fatal(err) 61881- } 61882- defer func() { 61883- if !r.SkipCleanup { 61884- if err := sandbox.Close(); err != nil { 61885- pprof.Lookup("goroutine").WriteTo(os.Stderr, 1) 61886- t.Errorf("closing the sandbox: %v", err) 61887- } 61888- } 61889- }() 61890- 61891- ss := tc.getServer(r.OptionsHook) 61892- 61893- framer := jsonrpc2.NewRawStream 61894- ls := &loggingFramer{} 61895- framer = ls.framer(jsonrpc2.NewRawStream) 61896- ts := servertest.NewPipeServer(ss, framer) 61897- 61898- awaiter := NewAwaiter(sandbox.Workdir) 61899- const skipApplyEdits = false 61900- editor, err := fake.NewEditor(sandbox, config.editor).Connect(ctx, ts, awaiter.Hooks(), skipApplyEdits) 61901- if err != nil { 61902- t.Fatal(err) 61903- } 61904- env := &Env{ 61905- T: t, 61906- Ctx: ctx, 61907- Sandbox: sandbox, 61908- Editor: editor, 61909- Server: ts, 61910- Awaiter: awaiter, 61911- } 61912- defer func() { 61913- if t.Failed() && r.PrintGoroutinesOnFailure { 61914- pprof.Lookup("goroutine").WriteTo(os.Stderr, 1) 61915- } 61916- if t.Failed() || *printLogs { 61917- ls.printBuffers(t.Name(), os.Stderr) 61918- } 61919- // For tests that failed due to a timeout, don't fail to shutdown 61920- // because ctx is done. 61921- // 61922- // There is little point to setting an arbitrary timeout for closing 61923- // the editor: in general we want to clean up before proceeding to the 61924- // next test, and if there is a deadlock preventing closing it will 61925- // eventually be handled by the `go test` timeout. 61926- if err := editor.Close(xcontext.Detach(ctx)); err != nil { 61927- t.Errorf("closing editor: %v", err) 61928- } 61929- }() 61930- // Always await the initial workspace load. 61931- env.Await(InitialWorkspaceLoad) 61932- test(t, env) 61933- }) 61934- } 61935-} 61936- 61937-// longBuilders maps builders that are skipped when -short is set to a 61938-// (possibly empty) justification. 61939-var longBuilders = map[string]string{ 61940- "openbsd-amd64-64": "golang.org/issues/42789", 61941- "openbsd-386-64": "golang.org/issues/42789", 61942- "openbsd-386-68": "golang.org/issues/42789", 61943- "openbsd-amd64-68": "golang.org/issues/42789", 61944- "darwin-amd64-10_12": "", 61945- "freebsd-amd64-race": "", 61946- "illumos-amd64": "", 61947- "netbsd-arm-bsiegert": "", 61948- "solaris-amd64-oraclerel": "", 61949- "windows-arm-zx2c4": "", 61950-} 61951- 61952-func checkBuilder(t *testing.T) { 61953- t.Helper() 61954- builder := os.Getenv("GO_BUILDER_NAME") 61955- if reason, ok := longBuilders[builder]; ok && testing.Short() { 61956- if reason != "" { 61957- t.Skipf("Skipping %s with -short due to %s", builder, reason) 61958- } else { 61959- t.Skipf("Skipping %s with -short", builder) 61960- } 61961- } 61962-} 61963- 61964-type loggingFramer struct { 61965- mu sync.Mutex 61966- buf *safeBuffer 61967-} 61968- 61969-// safeBuffer is a threadsafe buffer for logs. 61970-type safeBuffer struct { 61971- mu sync.Mutex 61972- buf bytes.Buffer 61973-} 61974- 61975-func (b *safeBuffer) Write(p []byte) (int, error) { 61976- b.mu.Lock() 61977- defer b.mu.Unlock() 61978- return b.buf.Write(p) 61979-} 61980- 61981-func (s *loggingFramer) framer(f jsonrpc2.Framer) jsonrpc2.Framer { 61982- return func(nc net.Conn) jsonrpc2.Stream { 61983- s.mu.Lock() 61984- framed := false 61985- if s.buf == nil { 61986- s.buf = &safeBuffer{buf: bytes.Buffer{}} 61987- framed = true 61988- } 61989- s.mu.Unlock() 61990- stream := f(nc) 61991- if framed { 61992- return protocol.LoggingStream(stream, s.buf) 61993- } 61994- return stream 61995- } 61996-} 61997- 61998-func (s *loggingFramer) printBuffers(testname string, w io.Writer) { 61999- s.mu.Lock() 62000- defer s.mu.Unlock() 62001- 62002- if s.buf == nil { 62003- return 62004- } 62005- fmt.Fprintf(os.Stderr, "#### Start Gopls Test Logs for %q\n", testname) 62006- s.buf.mu.Lock() 62007- io.Copy(w, &s.buf.buf) 62008- s.buf.mu.Unlock() 62009- fmt.Fprintf(os.Stderr, "#### End Gopls Test Logs for %q\n", testname) 62010-} 62011- 62012-// defaultServer handles the Default execution mode. 62013-func (r *Runner) defaultServer(optsHook func(*source.Options)) jsonrpc2.StreamServer { 62014- return lsprpc.NewStreamServer(cache.New(r.store), false, optsHook) 62015-} 62016- 62017-// experimentalServer handles the Experimental execution mode. 62018-func (r *Runner) experimentalServer(optsHook func(*source.Options)) jsonrpc2.StreamServer { 62019- options := func(o *source.Options) { 62020- optsHook(o) 62021- o.EnableAllExperiments() 62022- } 62023- return lsprpc.NewStreamServer(cache.New(nil), false, options) 62024-} 62025- 62026-// forwardedServer handles the Forwarded execution mode. 62027-func (r *Runner) forwardedServer(optsHook func(*source.Options)) jsonrpc2.StreamServer { 62028- r.tsOnce.Do(func() { 62029- ctx := context.Background() 62030- ctx = debug.WithInstance(ctx, "", "off") 62031- ss := lsprpc.NewStreamServer(cache.New(nil), false, optsHook) 62032- r.ts = servertest.NewTCPServer(ctx, ss, nil) 62033- }) 62034- return newForwarder("tcp", r.ts.Addr) 62035-} 62036- 62037-// runTestAsGoplsEnvvar triggers TestMain to run gopls instead of running 62038-// tests. It's a trick to allow tests to find a binary to use to start a gopls 62039-// subprocess. 62040-const runTestAsGoplsEnvvar = "_GOPLS_TEST_BINARY_RUN_AS_GOPLS" 62041- 62042-// separateProcessServer handles the SeparateProcess execution mode. 62043-func (r *Runner) separateProcessServer(optsHook func(*source.Options)) jsonrpc2.StreamServer { 62044- if runtime.GOOS != "linux" { 62045- panic("separate process execution mode is only supported on linux") 62046- } 62047- 62048- r.startRemoteOnce.Do(func() { 62049- socketDir, err := ioutil.TempDir(r.tempDir, "gopls-regtest-socket") 62050- if err != nil { 62051- r.remoteErr = err 62052- return 62053- } 62054- r.remoteSocket = filepath.Join(socketDir, "gopls-test-daemon") 62055- 62056- // The server should be killed by when the test runner exits, but to be 62057- // conservative also set a listen timeout. 62058- args := []string{"serve", "-listen", "unix;" + r.remoteSocket, "-listen.timeout", "1m"} 62059- 62060- ctx, cancel := context.WithCancel(context.Background()) 62061- cmd := exec.CommandContext(ctx, r.goplsPath, args...) 62062- cmd.Env = append(os.Environ(), runTestAsGoplsEnvvar+"=true") 62063- 62064- // Start the external gopls process. This is still somewhat racy, as we 62065- // don't know when gopls binds to the socket, but the gopls forwarder 62066- // client has built-in retry behavior that should mostly mitigate this 62067- // problem (and if it doesn't, we probably want to improve the retry 62068- // behavior). 62069- if err := cmd.Start(); err != nil { 62070- cancel() 62071- r.remoteSocket = "" 62072- r.remoteErr = err 62073- } else { 62074- r.cancelRemote = cancel 62075- // Spin off a goroutine to wait, so that we free up resources when the 62076- // server exits. 62077- go cmd.Wait() 62078- } 62079- }) 62080- 62081- return newForwarder("unix", r.remoteSocket) 62082-} 62083- 62084-func newForwarder(network, address string) *lsprpc.Forwarder { 62085- server, err := lsprpc.NewForwarder(network+";"+address, nil) 62086- if err != nil { 62087- // This should never happen, as we are passing an explicit address. 62088- panic(fmt.Sprintf("internal error: unable to create forwarder: %v", err)) 62089- } 62090- return server 62091-} 62092- 62093-// Close cleans up resource that have been allocated to this workspace. 62094-func (r *Runner) Close() error { 62095- var errmsgs []string 62096- if r.ts != nil { 62097- if err := r.ts.Close(); err != nil { 62098- errmsgs = append(errmsgs, err.Error()) 62099- } 62100- } 62101- if r.cancelRemote != nil { 62102- r.cancelRemote() 62103- } 62104- if !r.SkipCleanup { 62105- if err := os.RemoveAll(r.tempDir); err != nil { 62106- errmsgs = append(errmsgs, err.Error()) 62107- } 62108- } 62109- if len(errmsgs) > 0 { 62110- return fmt.Errorf("errors closing the test runner:\n\t%s", strings.Join(errmsgs, "\n\t")) 62111- } 62112- return nil 62113-} 62114diff -urN a/gopls/internal/lsp/regtest/wrappers.go b/gopls/internal/lsp/regtest/wrappers.go 62115--- a/gopls/internal/lsp/regtest/wrappers.go 2000-01-01 00:00:00.000000000 -0000 62116+++ b/gopls/internal/lsp/regtest/wrappers.go 1970-01-01 00:00:00.000000000 +0000 62117@@ -1,489 +0,0 @@ 62118-// Copyright 2020 The Go Authors. All rights reserved. 62119-// Use of this source code is governed by a BSD-style 62120-// license that can be found in the LICENSE file. 62121- 62122-package regtest 62123- 62124-import ( 62125- "encoding/json" 62126- "path" 62127- 62128- "golang.org/x/tools/gopls/internal/lsp/command" 62129- "golang.org/x/tools/gopls/internal/lsp/fake" 62130- "golang.org/x/tools/gopls/internal/lsp/protocol" 62131- "golang.org/x/tools/internal/xcontext" 62132-) 62133- 62134-// RemoveWorkspaceFile deletes a file on disk but does nothing in the 62135-// editor. It calls t.Fatal on any error. 62136-func (e *Env) RemoveWorkspaceFile(name string) { 62137- e.T.Helper() 62138- if err := e.Sandbox.Workdir.RemoveFile(e.Ctx, name); err != nil { 62139- e.T.Fatal(err) 62140- } 62141-} 62142- 62143-// ReadWorkspaceFile reads a file from the workspace, calling t.Fatal on any 62144-// error. 62145-func (e *Env) ReadWorkspaceFile(name string) string { 62146- e.T.Helper() 62147- content, err := e.Sandbox.Workdir.ReadFile(name) 62148- if err != nil { 62149- e.T.Fatal(err) 62150- } 62151- return string(content) 62152-} 62153- 62154-// WriteWorkspaceFile writes a file to disk but does nothing in the editor. 62155-// It calls t.Fatal on any error. 62156-func (e *Env) WriteWorkspaceFile(name, content string) { 62157- e.T.Helper() 62158- if err := e.Sandbox.Workdir.WriteFile(e.Ctx, name, content); err != nil { 62159- e.T.Fatal(err) 62160- } 62161-} 62162- 62163-// WriteWorkspaceFiles deletes a file on disk but does nothing in the 62164-// editor. It calls t.Fatal on any error. 62165-func (e *Env) WriteWorkspaceFiles(files map[string]string) { 62166- e.T.Helper() 62167- if err := e.Sandbox.Workdir.WriteFiles(e.Ctx, files); err != nil { 62168- e.T.Fatal(err) 62169- } 62170-} 62171- 62172-// ListFiles lists relative paths to files in the given directory. 62173-// It calls t.Fatal on any error. 62174-func (e *Env) ListFiles(dir string) []string { 62175- e.T.Helper() 62176- paths, err := e.Sandbox.Workdir.ListFiles(dir) 62177- if err != nil { 62178- e.T.Fatal(err) 62179- } 62180- return paths 62181-} 62182- 62183-// OpenFile opens a file in the editor, calling t.Fatal on any error. 62184-func (e *Env) OpenFile(name string) { 62185- e.T.Helper() 62186- if err := e.Editor.OpenFile(e.Ctx, name); err != nil { 62187- e.T.Fatal(err) 62188- } 62189-} 62190- 62191-// CreateBuffer creates a buffer in the editor, calling t.Fatal on any error. 62192-func (e *Env) CreateBuffer(name string, content string) { 62193- e.T.Helper() 62194- if err := e.Editor.CreateBuffer(e.Ctx, name, content); err != nil { 62195- e.T.Fatal(err) 62196- } 62197-} 62198- 62199-// BufferText returns the current buffer contents for the file with the given 62200-// relative path, calling t.Fatal if the file is not open in a buffer. 62201-func (e *Env) BufferText(name string) string { 62202- e.T.Helper() 62203- text, ok := e.Editor.BufferText(name) 62204- if !ok { 62205- e.T.Fatalf("buffer %q is not open", name) 62206- } 62207- return text 62208-} 62209- 62210-// CloseBuffer closes an editor buffer without saving, calling t.Fatal on any 62211-// error. 62212-func (e *Env) CloseBuffer(name string) { 62213- e.T.Helper() 62214- if err := e.Editor.CloseBuffer(e.Ctx, name); err != nil { 62215- e.T.Fatal(err) 62216- } 62217-} 62218- 62219-// EditBuffer applies edits to an editor buffer, calling t.Fatal on any error. 62220-func (e *Env) EditBuffer(name string, edits ...protocol.TextEdit) { 62221- e.T.Helper() 62222- if err := e.Editor.EditBuffer(e.Ctx, name, edits); err != nil { 62223- e.T.Fatal(err) 62224- } 62225-} 62226- 62227-func (e *Env) SetBufferContent(name string, content string) { 62228- e.T.Helper() 62229- if err := e.Editor.SetBufferContent(e.Ctx, name, content); err != nil { 62230- e.T.Fatal(err) 62231- } 62232-} 62233- 62234-// RegexpSearch returns the starting position of the first match for re in the 62235-// buffer specified by name, calling t.Fatal on any error. It first searches 62236-// for the position in open buffers, then in workspace files. 62237-func (e *Env) RegexpSearch(name, re string) protocol.Location { 62238- e.T.Helper() 62239- loc, err := e.Editor.RegexpSearch(name, re) 62240- if err == fake.ErrUnknownBuffer { 62241- loc, err = e.Sandbox.Workdir.RegexpSearch(name, re) 62242- } 62243- if err != nil { 62244- e.T.Fatalf("RegexpSearch: %v, %v for %q", name, err, re) 62245- } 62246- return loc 62247-} 62248- 62249-// RegexpReplace replaces the first group in the first match of regexpStr with 62250-// the replace text, calling t.Fatal on any error. 62251-func (e *Env) RegexpReplace(name, regexpStr, replace string) { 62252- e.T.Helper() 62253- if err := e.Editor.RegexpReplace(e.Ctx, name, regexpStr, replace); err != nil { 62254- e.T.Fatalf("RegexpReplace: %v", err) 62255- } 62256-} 62257- 62258-// SaveBuffer saves an editor buffer, calling t.Fatal on any error. 62259-func (e *Env) SaveBuffer(name string) { 62260- e.T.Helper() 62261- if err := e.Editor.SaveBuffer(e.Ctx, name); err != nil { 62262- e.T.Fatal(err) 62263- } 62264-} 62265- 62266-func (e *Env) SaveBufferWithoutActions(name string) { 62267- e.T.Helper() 62268- if err := e.Editor.SaveBufferWithoutActions(e.Ctx, name); err != nil { 62269- e.T.Fatal(err) 62270- } 62271-} 62272- 62273-// GoToDefinition goes to definition in the editor, calling t.Fatal on any 62274-// error. It returns the path and position of the resulting jump. 62275-func (e *Env) GoToDefinition(loc protocol.Location) protocol.Location { 62276- e.T.Helper() 62277- loc, err := e.Editor.GoToDefinition(e.Ctx, loc) 62278- if err != nil { 62279- e.T.Fatal(err) 62280- } 62281- return loc 62282-} 62283- 62284-// FormatBuffer formats the editor buffer, calling t.Fatal on any error. 62285-func (e *Env) FormatBuffer(name string) { 62286- e.T.Helper() 62287- if err := e.Editor.FormatBuffer(e.Ctx, name); err != nil { 62288- e.T.Fatal(err) 62289- } 62290-} 62291- 62292-// OrganizeImports processes the source.organizeImports codeAction, calling 62293-// t.Fatal on any error. 62294-func (e *Env) OrganizeImports(name string) { 62295- e.T.Helper() 62296- if err := e.Editor.OrganizeImports(e.Ctx, name); err != nil { 62297- e.T.Fatal(err) 62298- } 62299-} 62300- 62301-// ApplyQuickFixes processes the quickfix codeAction, calling t.Fatal on any error. 62302-func (e *Env) ApplyQuickFixes(path string, diagnostics []protocol.Diagnostic) { 62303- e.T.Helper() 62304- loc := protocol.Location{URI: e.Sandbox.Workdir.URI(path)} // zero Range => whole file 62305- if err := e.Editor.ApplyQuickFixes(e.Ctx, loc, diagnostics); err != nil { 62306- e.T.Fatal(err) 62307- } 62308-} 62309- 62310-// ApplyCodeAction applies the given code action. 62311-func (e *Env) ApplyCodeAction(action protocol.CodeAction) { 62312- e.T.Helper() 62313- if err := e.Editor.ApplyCodeAction(e.Ctx, action); err != nil { 62314- e.T.Fatal(err) 62315- } 62316-} 62317- 62318-// GetQuickFixes returns the available quick fix code actions. 62319-func (e *Env) GetQuickFixes(path string, diagnostics []protocol.Diagnostic) []protocol.CodeAction { 62320- e.T.Helper() 62321- loc := protocol.Location{URI: e.Sandbox.Workdir.URI(path)} // zero Range => whole file 62322- actions, err := e.Editor.GetQuickFixes(e.Ctx, loc, diagnostics) 62323- if err != nil { 62324- e.T.Fatal(err) 62325- } 62326- return actions 62327-} 62328- 62329-// Hover in the editor, calling t.Fatal on any error. 62330-func (e *Env) Hover(loc protocol.Location) (*protocol.MarkupContent, protocol.Location) { 62331- e.T.Helper() 62332- c, loc, err := e.Editor.Hover(e.Ctx, loc) 62333- if err != nil { 62334- e.T.Fatal(err) 62335- } 62336- return c, loc 62337-} 62338- 62339-func (e *Env) DocumentLink(name string) []protocol.DocumentLink { 62340- e.T.Helper() 62341- links, err := e.Editor.DocumentLink(e.Ctx, name) 62342- if err != nil { 62343- e.T.Fatal(err) 62344- } 62345- return links 62346-} 62347- 62348-func (e *Env) DocumentHighlight(loc protocol.Location) []protocol.DocumentHighlight { 62349- e.T.Helper() 62350- highlights, err := e.Editor.DocumentHighlight(e.Ctx, loc) 62351- if err != nil { 62352- e.T.Fatal(err) 62353- } 62354- return highlights 62355-} 62356- 62357-// RunGenerate runs "go generate" in the given dir, calling t.Fatal on any error. 62358-// It waits for the generate command to complete and checks for file changes 62359-// before returning. 62360-func (e *Env) RunGenerate(dir string) { 62361- e.T.Helper() 62362- if err := e.Editor.RunGenerate(e.Ctx, dir); err != nil { 62363- e.T.Fatal(err) 62364- } 62365- e.Await(NoOutstandingWork()) 62366- // Ideally the fake.Workspace would handle all synthetic file watching, but 62367- // we help it out here as we need to wait for the generate command to 62368- // complete before checking the filesystem. 62369- e.CheckForFileChanges() 62370-} 62371- 62372-// RunGoCommand runs the given command in the sandbox's default working 62373-// directory. 62374-func (e *Env) RunGoCommand(verb string, args ...string) { 62375- e.T.Helper() 62376- if err := e.Sandbox.RunGoCommand(e.Ctx, "", verb, args, true); err != nil { 62377- e.T.Fatal(err) 62378- } 62379-} 62380- 62381-// RunGoCommandInDir is like RunGoCommand, but executes in the given 62382-// relative directory of the sandbox. 62383-func (e *Env) RunGoCommandInDir(dir, verb string, args ...string) { 62384- e.T.Helper() 62385- if err := e.Sandbox.RunGoCommand(e.Ctx, dir, verb, args, true); err != nil { 62386- e.T.Fatal(err) 62387- } 62388-} 62389- 62390-// GoVersion checks the version of the go command. 62391-// It returns the X in Go 1.X. 62392-func (e *Env) GoVersion() int { 62393- e.T.Helper() 62394- v, err := e.Sandbox.GoVersion(e.Ctx) 62395- if err != nil { 62396- e.T.Fatal(err) 62397- } 62398- return v 62399-} 62400- 62401-// DumpGoSum prints the correct go.sum contents for dir in txtar format, 62402-// for use in creating regtests. 62403-func (e *Env) DumpGoSum(dir string) { 62404- e.T.Helper() 62405- 62406- if err := e.Sandbox.RunGoCommand(e.Ctx, dir, "list", []string{"-mod=mod", "..."}, true); err != nil { 62407- e.T.Fatal(err) 62408- } 62409- sumFile := path.Join(dir, "/go.sum") 62410- e.T.Log("\n\n-- " + sumFile + " --\n" + e.ReadWorkspaceFile(sumFile)) 62411- e.T.Fatal("see contents above") 62412-} 62413- 62414-// CheckForFileChanges triggers a manual poll of the workspace for any file 62415-// changes since creation, or since last polling. It is a workaround for the 62416-// lack of true file watching support in the fake workspace. 62417-func (e *Env) CheckForFileChanges() { 62418- e.T.Helper() 62419- if err := e.Sandbox.Workdir.CheckForFileChanges(e.Ctx); err != nil { 62420- e.T.Fatal(err) 62421- } 62422-} 62423- 62424-// CodeLens calls textDocument/codeLens for the given path, calling t.Fatal on 62425-// any error. 62426-func (e *Env) CodeLens(path string) []protocol.CodeLens { 62427- e.T.Helper() 62428- lens, err := e.Editor.CodeLens(e.Ctx, path) 62429- if err != nil { 62430- e.T.Fatal(err) 62431- } 62432- return lens 62433-} 62434- 62435-// ExecuteCodeLensCommand executes the command for the code lens matching the 62436-// given command name. 62437-func (e *Env) ExecuteCodeLensCommand(path string, cmd command.Command, result interface{}) { 62438- e.T.Helper() 62439- lenses := e.CodeLens(path) 62440- var lens protocol.CodeLens 62441- var found bool 62442- for _, l := range lenses { 62443- if l.Command.Command == cmd.ID() { 62444- lens = l 62445- found = true 62446- } 62447- } 62448- if !found { 62449- e.T.Fatalf("found no command with the ID %s", cmd.ID()) 62450- } 62451- e.ExecuteCommand(&protocol.ExecuteCommandParams{ 62452- Command: lens.Command.Command, 62453- Arguments: lens.Command.Arguments, 62454- }, result) 62455-} 62456- 62457-func (e *Env) ExecuteCommand(params *protocol.ExecuteCommandParams, result interface{}) { 62458- e.T.Helper() 62459- response, err := e.Editor.ExecuteCommand(e.Ctx, params) 62460- if err != nil { 62461- e.T.Fatal(err) 62462- } 62463- if result == nil { 62464- return 62465- } 62466- // Hack: The result of an executeCommand request will be unmarshaled into 62467- // maps. Re-marshal and unmarshal into the type we expect. 62468- // 62469- // This could be improved by generating a jsonrpc2 command client from the 62470- // command.Interface, but that should only be done if we're consolidating 62471- // this part of the tsprotocol generation. 62472- data, err := json.Marshal(response) 62473- if err != nil { 62474- e.T.Fatal(err) 62475- } 62476- if err := json.Unmarshal(data, result); err != nil { 62477- e.T.Fatal(err) 62478- } 62479-} 62480- 62481-// InlayHints calls textDocument/inlayHints for the given path, calling t.Fatal on 62482-// any error. 62483-func (e *Env) InlayHints(path string) []protocol.InlayHint { 62484- e.T.Helper() 62485- hints, err := e.Editor.InlayHint(e.Ctx, path) 62486- if err != nil { 62487- e.T.Fatal(err) 62488- } 62489- return hints 62490-} 62491- 62492-// Symbol calls workspace/symbol 62493-func (e *Env) Symbol(query string) []protocol.SymbolInformation { 62494- e.T.Helper() 62495- ans, err := e.Editor.Symbols(e.Ctx, query) 62496- if err != nil { 62497- e.T.Fatal(err) 62498- } 62499- return ans 62500-} 62501- 62502-// References wraps Editor.References, calling t.Fatal on any error. 62503-func (e *Env) References(loc protocol.Location) []protocol.Location { 62504- e.T.Helper() 62505- locations, err := e.Editor.References(e.Ctx, loc) 62506- if err != nil { 62507- e.T.Fatal(err) 62508- } 62509- return locations 62510-} 62511- 62512-// Rename wraps Editor.Rename, calling t.Fatal on any error. 62513-func (e *Env) Rename(loc protocol.Location, newName string) { 62514- e.T.Helper() 62515- if err := e.Editor.Rename(e.Ctx, loc, newName); err != nil { 62516- e.T.Fatal(err) 62517- } 62518-} 62519- 62520-// Implementations wraps Editor.Implementations, calling t.Fatal on any error. 62521-func (e *Env) Implementations(loc protocol.Location) []protocol.Location { 62522- e.T.Helper() 62523- locations, err := e.Editor.Implementations(e.Ctx, loc) 62524- if err != nil { 62525- e.T.Fatal(err) 62526- } 62527- return locations 62528-} 62529- 62530-// RenameFile wraps Editor.RenameFile, calling t.Fatal on any error. 62531-func (e *Env) RenameFile(oldPath, newPath string) { 62532- e.T.Helper() 62533- if err := e.Editor.RenameFile(e.Ctx, oldPath, newPath); err != nil { 62534- e.T.Fatal(err) 62535- } 62536-} 62537- 62538-// SignatureHelp wraps Editor.SignatureHelp, calling t.Fatal on error 62539-func (e *Env) SignatureHelp(loc protocol.Location) *protocol.SignatureHelp { 62540- e.T.Helper() 62541- sighelp, err := e.Editor.SignatureHelp(e.Ctx, loc) 62542- if err != nil { 62543- e.T.Fatal(err) 62544- } 62545- return sighelp 62546-} 62547- 62548-// Completion executes a completion request on the server. 62549-func (e *Env) Completion(loc protocol.Location) *protocol.CompletionList { 62550- e.T.Helper() 62551- completions, err := e.Editor.Completion(e.Ctx, loc) 62552- if err != nil { 62553- e.T.Fatal(err) 62554- } 62555- return completions 62556-} 62557- 62558-// AcceptCompletion accepts a completion for the given item at the given 62559-// position. 62560-func (e *Env) AcceptCompletion(loc protocol.Location, item protocol.CompletionItem) { 62561- e.T.Helper() 62562- if err := e.Editor.AcceptCompletion(e.Ctx, loc, item); err != nil { 62563- e.T.Fatal(err) 62564- } 62565-} 62566- 62567-// CodeAction calls testDocument/codeAction for the given path, and calls 62568-// t.Fatal if there are errors. 62569-func (e *Env) CodeAction(path string, diagnostics []protocol.Diagnostic) []protocol.CodeAction { 62570- e.T.Helper() 62571- loc := protocol.Location{URI: e.Sandbox.Workdir.URI(path)} // no Range => whole file 62572- actions, err := e.Editor.CodeAction(e.Ctx, loc, diagnostics) 62573- if err != nil { 62574- e.T.Fatal(err) 62575- } 62576- return actions 62577-} 62578- 62579-// ChangeConfiguration updates the editor config, calling t.Fatal on any error. 62580-func (e *Env) ChangeConfiguration(newConfig fake.EditorConfig) { 62581- e.T.Helper() 62582- if err := e.Editor.ChangeConfiguration(e.Ctx, newConfig); err != nil { 62583- e.T.Fatal(err) 62584- } 62585-} 62586- 62587-// ChangeWorkspaceFolders updates the editor workspace folders, calling t.Fatal 62588-// on any error. 62589-func (e *Env) ChangeWorkspaceFolders(newFolders ...string) { 62590- e.T.Helper() 62591- if err := e.Editor.ChangeWorkspaceFolders(e.Ctx, newFolders); err != nil { 62592- e.T.Fatal(err) 62593- } 62594-} 62595- 62596-// Close shuts down the editor session and cleans up the sandbox directory, 62597-// calling t.Error on any error. 62598-func (e *Env) Close() { 62599- ctx := xcontext.Detach(e.Ctx) 62600- if err := e.Editor.Close(ctx); err != nil { 62601- e.T.Errorf("closing editor: %v", err) 62602- } 62603- if err := e.Sandbox.Close(); err != nil { 62604- e.T.Errorf("cleaning up sandbox: %v", err) 62605- } 62606-} 62607diff -urN a/gopls/internal/lsp/rename.go b/gopls/internal/lsp/rename.go 62608--- a/gopls/internal/lsp/rename.go 2000-01-01 00:00:00.000000000 -0000 62609+++ b/gopls/internal/lsp/rename.go 1970-01-01 00:00:00.000000000 +0000 62610@@ -1,78 +0,0 @@ 62611-// Copyright 2019 The Go Authors. All rights reserved. 62612-// Use of this source code is governed by a BSD-style 62613-// license that can be found in the LICENSE file. 62614- 62615-package lsp 62616- 62617-import ( 62618- "context" 62619- "path/filepath" 62620- 62621- "golang.org/x/tools/gopls/internal/lsp/protocol" 62622- "golang.org/x/tools/gopls/internal/lsp/source" 62623-) 62624- 62625-func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) { 62626- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 62627- defer release() 62628- if !ok { 62629- return nil, err 62630- } 62631- // Because we don't handle directory renaming within source.Rename, source.Rename returns 62632- // boolean value isPkgRenaming to determine whether an DocumentChanges of type RenameFile should 62633- // be added to the return protocol.WorkspaceEdit value. 62634- edits, isPkgRenaming, err := source.Rename(ctx, snapshot, fh, params.Position, params.NewName) 62635- if err != nil { 62636- return nil, err 62637- } 62638- 62639- var docChanges []protocol.DocumentChanges 62640- for uri, e := range edits { 62641- fh, err := snapshot.GetFile(ctx, uri) 62642- if err != nil { 62643- return nil, err 62644- } 62645- docChanges = append(docChanges, documentChanges(fh, e)...) 62646- } 62647- if isPkgRenaming { 62648- // Update the last component of the file's enclosing directory. 62649- oldBase := filepath.Dir(fh.URI().Filename()) 62650- newURI := filepath.Join(filepath.Dir(oldBase), params.NewName) 62651- docChanges = append(docChanges, protocol.DocumentChanges{ 62652- RenameFile: &protocol.RenameFile{ 62653- Kind: "rename", 62654- OldURI: protocol.URIFromPath(oldBase), 62655- NewURI: protocol.URIFromPath(newURI), 62656- }, 62657- }) 62658- } 62659- return &protocol.WorkspaceEdit{ 62660- DocumentChanges: docChanges, 62661- }, nil 62662-} 62663- 62664-// prepareRename implements the textDocument/prepareRename handler. It may 62665-// return (nil, nil) if there is no rename at the cursor position, but it is 62666-// not desirable to display an error to the user. 62667-// 62668-// TODO(rfindley): why wouldn't we want to show an error to the user, if the 62669-// user initiated a rename request at the cursor? 62670-func (s *Server) prepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.PrepareRename2Gn, error) { 62671- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 62672- defer release() 62673- if !ok { 62674- return nil, err 62675- } 62676- // Do not return errors here, as it adds clutter. 62677- // Returning a nil result means there is not a valid rename. 62678- item, usererr, err := source.PrepareRename(ctx, snapshot, fh, params.Position) 62679- if err != nil { 62680- // Return usererr here rather than err, to avoid cluttering the UI with 62681- // internal error details. 62682- return nil, usererr 62683- } 62684- return &protocol.PrepareRename2Gn{ 62685- Range: item.Range, 62686- Placeholder: item.Text, 62687- }, nil 62688-} 62689diff -urN a/gopls/internal/lsp/reset_golden.sh b/gopls/internal/lsp/reset_golden.sh 62690--- a/gopls/internal/lsp/reset_golden.sh 2000-01-01 00:00:00.000000000 -0000 62691+++ b/gopls/internal/lsp/reset_golden.sh 1970-01-01 00:00:00.000000000 +0000 62692@@ -1,30 +0,0 @@ 62693-#!/bin/bash 62694-# 62695-# Copyright 2022 The Go Authors. All rights reserved. 62696-# Use of this source code is governed by a BSD-style 62697-# license that can be found in the LICENSE file. 62698-# 62699-# Updates the *.golden files ... to match the tests' current behavior. 62700- 62701-set -eu 62702- 62703-GO117BIN="go1.17.9" 62704- 62705-command -v $GO117BIN >/dev/null 2>&1 || { 62706- go install golang.org/dl/$GO117BIN@latest 62707- $GO117BIN download 62708-} 62709- 62710-find ./internal/lsp/testdata -name *.golden ! -name summary*.txt.golden -delete 62711-# Here we intentionally do not run the ./internal/lsp/source tests with 62712-# -golden. Eventually these tests will be deleted, and in the meantime they are 62713-# redundant with the ./internal/lsp tests. 62714-# 62715-# Note: go1.17.9 tests must be run *before* go tests, as by convention the 62716-# golden output should match the output of gopls built with the most recent 62717-# version of Go. If output differs at 1.17, tests must be tolerant of the 1.17 62718-# output. 62719-$GO117BIN test ./internal/lsp -golden 62720-go test ./internal/lsp -golden 62721-$GO117BIN test ./test -golden 62722-go test ./test -golden 62723diff -urN a/gopls/internal/lsp/safetoken/safetoken.go b/gopls/internal/lsp/safetoken/safetoken.go 62724--- a/gopls/internal/lsp/safetoken/safetoken.go 2000-01-01 00:00:00.000000000 -0000 62725+++ b/gopls/internal/lsp/safetoken/safetoken.go 1970-01-01 00:00:00.000000000 +0000 62726@@ -1,122 +0,0 @@ 62727-// Copyright 2022 The Go Authors. All rights reserved. 62728-// Use of this source code is governed by a BSD-style 62729-// license that can be found in the LICENSE file. 62730- 62731-// Package safetoken provides wrappers around methods in go/token, 62732-// that return errors rather than panicking. 62733-// 62734-// It also provides a central place for workarounds in the underlying 62735-// packages. The use of this package's functions instead of methods of 62736-// token.File (such as Offset, Position, and PositionFor) is mandatory 62737-// throughout the gopls codebase and enforced by a static check. 62738-package safetoken 62739- 62740-import ( 62741- "fmt" 62742- "go/token" 62743-) 62744- 62745-// Offset returns f.Offset(pos), but first checks that the file 62746-// contains the pos. 62747-// 62748-// The definition of "contains" here differs from that of token.File 62749-// in order to work around a bug in the parser (issue #57490): during 62750-// error recovery, the parser may create syntax nodes whose computed 62751-// End position is 1 byte beyond EOF, which would cause 62752-// token.File.Offset to panic. The workaround is that this function 62753-// accepts a Pos that is exactly 1 byte beyond EOF and maps it to the 62754-// EOF offset. 62755-func Offset(f *token.File, pos token.Pos) (int, error) { 62756- if !inRange(f, pos) { 62757- // Accept a Pos that is 1 byte beyond EOF, 62758- // and map it to the EOF offset. 62759- // (Workaround for #57490.) 62760- if int(pos) == f.Base()+f.Size()+1 { 62761- return f.Size(), nil 62762- } 62763- 62764- return -1, fmt.Errorf("pos %d is not in range [%d:%d] of file %s", 62765- pos, f.Base(), f.Base()+f.Size(), f.Name()) 62766- } 62767- return int(pos) - f.Base(), nil 62768-} 62769- 62770-// Offsets returns Offset(start) and Offset(end). 62771-func Offsets(f *token.File, start, end token.Pos) (int, int, error) { 62772- startOffset, err := Offset(f, start) 62773- if err != nil { 62774- return 0, 0, fmt.Errorf("start: %v", err) 62775- } 62776- endOffset, err := Offset(f, end) 62777- if err != nil { 62778- return 0, 0, fmt.Errorf("end: %v", err) 62779- } 62780- return startOffset, endOffset, nil 62781-} 62782- 62783-// Pos returns f.Pos(offset), but first checks that the offset is 62784-// non-negative and not larger than the size of the file. 62785-func Pos(f *token.File, offset int) (token.Pos, error) { 62786- if !(0 <= offset && offset <= f.Size()) { 62787- return token.NoPos, fmt.Errorf("offset %d is not in range for file %s of size %d", offset, f.Name(), f.Size()) 62788- } 62789- return token.Pos(f.Base() + offset), nil 62790-} 62791- 62792-// inRange reports whether file f contains position pos, 62793-// according to the invariants of token.File. 62794-// 62795-// This function is not public because of the ambiguity it would 62796-// create w.r.t. the definition of "contains". Use Offset instead. 62797-func inRange(f *token.File, pos token.Pos) bool { 62798- return token.Pos(f.Base()) <= pos && pos <= token.Pos(f.Base()+f.Size()) 62799-} 62800- 62801-// Position returns the Position for the pos value in the given file. 62802-// 62803-// p must be NoPos, a valid Pos in the range of f, or exactly 1 byte 62804-// beyond the end of f. (See [Offset] for explanation.) 62805-// Any other value causes a panic. 62806-// 62807-// Line directives (//line comments) are ignored. 62808-func Position(f *token.File, pos token.Pos) token.Position { 62809- // Work around issue #57490. 62810- if int(pos) == f.Base()+f.Size()+1 { 62811- pos-- 62812- } 62813- 62814- // TODO(adonovan): centralize the workaround for 62815- // golang/go#41029 (newline at EOF) here too. 62816- 62817- return f.PositionFor(pos, false) 62818-} 62819- 62820-// StartPosition converts a start Pos in the FileSet into a Position. 62821-// 62822-// Call this function only if start represents the start of a token or 62823-// parse tree, such as the result of Node.Pos(). If start is the end of 62824-// an interval, such as Node.End(), call EndPosition instead, as it 62825-// may need the correction described at [Position]. 62826-func StartPosition(fset *token.FileSet, start token.Pos) (_ token.Position) { 62827- if f := fset.File(start); f != nil { 62828- return Position(f, start) 62829- } 62830- return 62831-} 62832- 62833-// EndPosition converts an end Pos in the FileSet into a Position. 62834-// 62835-// Call this function only if pos represents the end of 62836-// a non-empty interval, such as the result of Node.End(). 62837-func EndPosition(fset *token.FileSet, end token.Pos) (_ token.Position) { 62838- if f := fset.File(end); f != nil && int(end) > f.Base() { 62839- return Position(f, end) 62840- } 62841- 62842- // Work around issue #57490. 62843- if f := fset.File(end - 1); f != nil { 62844- return Position(f, end) 62845- } 62846- 62847- return 62848-} 62849diff -urN a/gopls/internal/lsp/safetoken/safetoken_test.go b/gopls/internal/lsp/safetoken/safetoken_test.go 62850--- a/gopls/internal/lsp/safetoken/safetoken_test.go 2000-01-01 00:00:00.000000000 -0000 62851+++ b/gopls/internal/lsp/safetoken/safetoken_test.go 1970-01-01 00:00:00.000000000 +0000 62852@@ -1,121 +0,0 @@ 62853-// Copyright 2021 The Go Authors. All rights reserved. 62854-// Use of this source code is governed by a BSD-style 62855-// license that can be found in the LICENSE file. 62856- 62857-package safetoken_test 62858- 62859-import ( 62860- "fmt" 62861- "go/parser" 62862- "go/token" 62863- "go/types" 62864- "os" 62865- "testing" 62866- 62867- "golang.org/x/tools/go/packages" 62868- "golang.org/x/tools/gopls/internal/lsp/safetoken" 62869- "golang.org/x/tools/internal/testenv" 62870-) 62871- 62872-func TestWorkaroundIssue57490(t *testing.T) { 62873- // During error recovery the parser synthesizes various close 62874- // tokens at EOF, causing the End position of incomplete 62875- // syntax nodes, computed as Rbrace+len("}"), to be beyond EOF. 62876- src := `package p; func f() { var x struct` 62877- fset := token.NewFileSet() 62878- file, _ := parser.ParseFile(fset, "a.go", src, 0) 62879- tf := fset.File(file.Pos()) 62880- 62881- // Add another file to the FileSet. 62882- file2, _ := parser.ParseFile(fset, "b.go", "package q", 0) 62883- 62884- // This is the ambiguity of #57490... 62885- if file.End() != file2.Pos() { 62886- t.Errorf("file.End() %d != %d file2.Pos()", file.End(), file2.Pos()) 62887- } 62888- // ...which causes these statements to panic. 62889- if false { 62890- tf.Offset(file.End()) // panic: invalid Pos value 36 (should be in [1, 35]) 62891- tf.Position(file.End()) // panic: invalid Pos value 36 (should be in [1, 35]) 62892- } 62893- 62894- // The offset of the EOF position is the file size. 62895- offset, err := safetoken.Offset(tf, file.End()-1) 62896- if err != nil || offset != tf.Size() { 62897- t.Errorf("Offset(EOF) = (%d, %v), want token.File.Size %d", offset, err, tf.Size()) 62898- } 62899- 62900- // The offset of the file.End() position, 1 byte beyond EOF, 62901- // is also the size of the file. 62902- offset, err = safetoken.Offset(tf, file.End()) 62903- if err != nil || offset != tf.Size() { 62904- t.Errorf("Offset(ast.File.End()) = (%d, %v), want token.File.Size %d", offset, err, tf.Size()) 62905- } 62906- 62907- if got, want := safetoken.Position(tf, file.End()).String(), "a.go:1:35"; got != want { 62908- t.Errorf("Position(ast.File.End()) = %s, want %s", got, want) 62909- } 62910- 62911- if got, want := safetoken.EndPosition(fset, file.End()).String(), "a.go:1:35"; got != want { 62912- t.Errorf("EndPosition(ast.File.End()) = %s, want %s", got, want) 62913- } 62914- 62915- // Note that calling StartPosition on an end may yield the wrong file: 62916- if got, want := safetoken.StartPosition(fset, file.End()).String(), "b.go:1:1"; got != want { 62917- t.Errorf("StartPosition(ast.File.End()) = %s, want %s", got, want) 62918- } 62919-} 62920- 62921-// To reduce the risk of panic, or bugs for which this package 62922-// provides a workaround, this test statically reports references to 62923-// forbidden methods of token.File or FileSet throughout gopls and 62924-// suggests alternatives. 62925-func TestGoplsSourceDoesNotCallTokenFileMethods(t *testing.T) { 62926- testenv.NeedsGoPackages(t) 62927- 62928- pkgs, err := packages.Load(&packages.Config{ 62929- Mode: packages.NeedName | packages.NeedModule | packages.NeedCompiledGoFiles | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedImports | packages.NeedDeps, 62930- }, "go/token", "golang.org/x/tools/gopls/...") 62931- if err != nil { 62932- t.Fatal(err) 62933- } 62934- var tokenPkg *packages.Package 62935- for _, pkg := range pkgs { 62936- if pkg.PkgPath == "go/token" { 62937- tokenPkg = pkg 62938- break 62939- } 62940- } 62941- if tokenPkg == nil { 62942- t.Fatal("missing package go/token") 62943- } 62944- 62945- File := tokenPkg.Types.Scope().Lookup("File") 62946- FileSet := tokenPkg.Types.Scope().Lookup("FileSet") 62947- 62948- alternative := make(map[types.Object]string) 62949- setAlternative := func(recv types.Object, old, new string) { 62950- oldMethod, _, _ := types.LookupFieldOrMethod(recv.Type(), true, recv.Pkg(), old) 62951- alternative[oldMethod] = new 62952- } 62953- setAlternative(File, "Offset", "safetoken.Offset") 62954- setAlternative(File, "Position", "safetoken.Position") 62955- setAlternative(File, "PositionFor", "safetoken.Position") 62956- setAlternative(FileSet, "Position", "safetoken.StartPosition or EndPosition") 62957- setAlternative(FileSet, "PositionFor", "safetoken.StartPosition or EndPosition") 62958- 62959- for _, pkg := range pkgs { 62960- switch pkg.PkgPath { 62961- case "go/token", "golang.org/x/tools/gopls/internal/lsp/safetoken": 62962- continue // allow calls within these packages 62963- } 62964- 62965- for ident, obj := range pkg.TypesInfo.Uses { 62966- if alt, ok := alternative[obj]; ok { 62967- posn := safetoken.StartPosition(pkg.Fset, ident.Pos()) 62968- fmt.Fprintf(os.Stderr, "%s: forbidden use of %v; use %s instead.\n", posn, obj, alt) 62969- t.Fail() 62970- } 62971- } 62972- } 62973-} 62974diff -urN a/gopls/internal/lsp/selection_range.go b/gopls/internal/lsp/selection_range.go 62975--- a/gopls/internal/lsp/selection_range.go 2000-01-01 00:00:00.000000000 -0000 62976+++ b/gopls/internal/lsp/selection_range.go 1970-01-01 00:00:00.000000000 +0000 62977@@ -1,69 +0,0 @@ 62978-// Copyright 2022 The Go Authors. All rights reserved. 62979-// Use of this source code is governed by a BSD-style 62980-// license that can be found in the LICENSE file. 62981- 62982-package lsp 62983- 62984-import ( 62985- "context" 62986- 62987- "golang.org/x/tools/go/ast/astutil" 62988- "golang.org/x/tools/gopls/internal/lsp/protocol" 62989- "golang.org/x/tools/gopls/internal/lsp/source" 62990- "golang.org/x/tools/internal/event" 62991-) 62992- 62993-// selectionRange defines the textDocument/selectionRange feature, 62994-// which, given a list of positions within a file, 62995-// reports a linked list of enclosing syntactic blocks, innermost first. 62996-// 62997-// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_selectionRange. 62998-// 62999-// This feature can be used by a client to implement "expand selection" in a 63000-// language-aware fashion. Multiple input positions are supported to allow 63001-// for multiple cursors, and the entire path up to the whole document is 63002-// returned for each cursor to avoid multiple round-trips when the user is 63003-// likely to issue this command multiple times in quick succession. 63004-func (s *Server) selectionRange(ctx context.Context, params *protocol.SelectionRangeParams) ([]protocol.SelectionRange, error) { 63005- ctx, done := event.Start(ctx, "lsp.Server.documentSymbol") 63006- defer done() 63007- 63008- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 63009- defer release() 63010- if !ok { 63011- return nil, err 63012- } 63013- 63014- pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull) 63015- if err != nil { 63016- return nil, err 63017- } 63018- 63019- result := make([]protocol.SelectionRange, len(params.Positions)) 63020- for i, protocolPos := range params.Positions { 63021- pos, err := pgf.PositionPos(protocolPos) 63022- if err != nil { 63023- return nil, err 63024- } 63025- 63026- path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos) 63027- 63028- tail := &result[i] // tail of the Parent linked list, built head first 63029- 63030- for j, node := range path { 63031- rng, err := pgf.NodeRange(node) 63032- if err != nil { 63033- return nil, err 63034- } 63035- 63036- // Add node to tail. 63037- if j > 0 { 63038- tail.Parent = &protocol.SelectionRange{} 63039- tail = tail.Parent 63040- } 63041- tail.Range = rng 63042- } 63043- } 63044- 63045- return result, nil 63046-} 63047diff -urN a/gopls/internal/lsp/semantic.go b/gopls/internal/lsp/semantic.go 63048--- a/gopls/internal/lsp/semantic.go 2000-01-01 00:00:00.000000000 -0000 63049+++ b/gopls/internal/lsp/semantic.go 1970-01-01 00:00:00.000000000 +0000 63050@@ -1,1003 +0,0 @@ 63051-// Copyright 2020 The Go Authors. All rights reserved. 63052-// Use of this source code is governed by a BSD-style 63053-// license that can be found in the LICENSE file. 63054- 63055-package lsp 63056- 63057-import ( 63058- "bytes" 63059- "context" 63060- "errors" 63061- "fmt" 63062- "go/ast" 63063- "go/token" 63064- "go/types" 63065- "log" 63066- "path/filepath" 63067- "sort" 63068- "strings" 63069- "time" 63070- 63071- "golang.org/x/tools/gopls/internal/lsp/protocol" 63072- "golang.org/x/tools/gopls/internal/lsp/safetoken" 63073- "golang.org/x/tools/gopls/internal/lsp/source" 63074- "golang.org/x/tools/gopls/internal/lsp/template" 63075- "golang.org/x/tools/internal/event" 63076- "golang.org/x/tools/internal/typeparams" 63077-) 63078- 63079-// The LSP says that errors for the semantic token requests should only be returned 63080-// for exceptions (a word not otherwise defined). This code treats a too-large file 63081-// as an exception. On parse errors, the code does what it can. 63082- 63083-// reject full semantic token requests for large files 63084-const maxFullFileSize int = 100000 63085- 63086-// to control comprehensive logging of decisions (gopls semtok foo.go > /dev/null shows log output) 63087-// semDebug should NEVER be true in checked-in code 63088-const semDebug = false 63089- 63090-func (s *Server) semanticTokensFull(ctx context.Context, p *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) { 63091- ret, err := s.computeSemanticTokens(ctx, p.TextDocument, nil) 63092- return ret, err 63093-} 63094- 63095-func (s *Server) semanticTokensFullDelta(ctx context.Context, p *protocol.SemanticTokensDeltaParams) (interface{}, error) { 63096- return nil, fmt.Errorf("implement SemanticTokensFullDelta") 63097-} 63098- 63099-func (s *Server) semanticTokensRange(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) { 63100- ret, err := s.computeSemanticTokens(ctx, p.TextDocument, &p.Range) 63101- return ret, err 63102-} 63103- 63104-func (s *Server) semanticTokensRefresh(ctx context.Context) error { 63105- // in the code, but not in the protocol spec 63106- return fmt.Errorf("implement SemanticTokensRefresh") 63107-} 63108- 63109-func (s *Server) computeSemanticTokens(ctx context.Context, td protocol.TextDocumentIdentifier, rng *protocol.Range) (*protocol.SemanticTokens, error) { 63110- ans := protocol.SemanticTokens{ 63111- Data: []uint32{}, 63112- } 63113- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, td.URI, source.UnknownKind) 63114- defer release() 63115- if !ok { 63116- return nil, err 63117- } 63118- vv := snapshot.View() 63119- if !vv.Options().SemanticTokens { 63120- // return an error, so if the option changes 63121- // the client won't remember the wrong answer 63122- return nil, fmt.Errorf("semantictokens are disabled") 63123- } 63124- kind := snapshot.View().FileKind(fh) 63125- if kind == source.Tmpl { 63126- // this is a little cumbersome to avoid both exporting 'encoded' and its methods 63127- // and to avoid import cycles 63128- e := &encoded{ 63129- ctx: ctx, 63130- metadataSource: snapshot, 63131- rng: rng, 63132- tokTypes: s.session.Options().SemanticTypes, 63133- tokMods: s.session.Options().SemanticMods, 63134- } 63135- add := func(line, start uint32, len uint32) { 63136- e.add(line, start, len, tokMacro, nil) 63137- } 63138- data := func() []uint32 { 63139- return e.Data() 63140- } 63141- return template.SemanticTokens(ctx, snapshot, fh.URI(), add, data) 63142- } 63143- if kind != source.Go { 63144- return nil, nil 63145- } 63146- pkg, pgf, err := source.PackageForFile(ctx, snapshot, fh.URI(), source.NarrowestPackage) 63147- if err != nil { 63148- return nil, err 63149- } 63150- 63151- if rng == nil && len(pgf.Src) > maxFullFileSize { 63152- err := fmt.Errorf("semantic tokens: file %s too large for full (%d>%d)", 63153- fh.URI().Filename(), len(pgf.Src), maxFullFileSize) 63154- return nil, err 63155- } 63156- e := &encoded{ 63157- ctx: ctx, 63158- metadataSource: snapshot, 63159- pgf: pgf, 63160- rng: rng, 63161- ti: pkg.GetTypesInfo(), 63162- pkg: pkg, 63163- fset: pkg.FileSet(), 63164- tokTypes: s.session.Options().SemanticTypes, 63165- tokMods: s.session.Options().SemanticMods, 63166- noStrings: vv.Options().NoSemanticString, 63167- noNumbers: vv.Options().NoSemanticNumber, 63168- } 63169- if err := e.init(); err != nil { 63170- // e.init should never return an error, unless there's some 63171- // seemingly impossible race condition 63172- return nil, err 63173- } 63174- e.semantics() 63175- ans.Data = e.Data() 63176- // For delta requests, but we've never seen any. 63177- ans.ResultID = fmt.Sprintf("%v", time.Now()) 63178- return &ans, nil 63179-} 63180- 63181-func (e *encoded) semantics() { 63182- f := e.pgf.File 63183- // may not be in range, but harmless 63184- e.token(f.Package, len("package"), tokKeyword, nil) 63185- e.token(f.Name.NamePos, len(f.Name.Name), tokNamespace, nil) 63186- inspect := func(n ast.Node) bool { 63187- return e.inspector(n) 63188- } 63189- for _, d := range f.Decls { 63190- // only look at the decls that overlap the range 63191- start, end := d.Pos(), d.End() 63192- if end <= e.start || start >= e.end { 63193- continue 63194- } 63195- ast.Inspect(d, inspect) 63196- } 63197- for _, cg := range f.Comments { 63198- for _, c := range cg.List { 63199- if !strings.Contains(c.Text, "\n") { 63200- e.token(c.Pos(), len(c.Text), tokComment, nil) 63201- continue 63202- } 63203- e.multiline(c.Pos(), c.End(), c.Text, tokComment) 63204- } 63205- } 63206-} 63207- 63208-type tokenType string 63209- 63210-const ( 63211- tokNamespace tokenType = "namespace" 63212- tokType tokenType = "type" 63213- tokInterface tokenType = "interface" 63214- tokTypeParam tokenType = "typeParameter" 63215- tokParameter tokenType = "parameter" 63216- tokVariable tokenType = "variable" 63217- tokMethod tokenType = "method" 63218- tokFunction tokenType = "function" 63219- tokKeyword tokenType = "keyword" 63220- tokComment tokenType = "comment" 63221- tokString tokenType = "string" 63222- tokNumber tokenType = "number" 63223- tokOperator tokenType = "operator" 63224- 63225- tokMacro tokenType = "macro" // for templates 63226-) 63227- 63228-func (e *encoded) token(start token.Pos, leng int, typ tokenType, mods []string) { 63229- if !start.IsValid() { 63230- // This is not worth reporting. TODO(pjw): does it still happen? 63231- return 63232- } 63233- if start >= e.end || start+token.Pos(leng) <= e.start { 63234- return 63235- } 63236- // want a line and column from start (in LSP coordinates). Ignore line directives. 63237- lspRange, err := e.pgf.PosRange(start, start+token.Pos(leng)) 63238- if err != nil { 63239- event.Error(e.ctx, "failed to convert to range", err) 63240- return 63241- } 63242- if lspRange.End.Line != lspRange.Start.Line { 63243- // this happens if users are typing at the end of the file, but report nothing 63244- return 63245- } 63246- // token is all on one line 63247- length := lspRange.End.Character - lspRange.Start.Character 63248- e.add(lspRange.Start.Line, lspRange.Start.Character, length, typ, mods) 63249-} 63250- 63251-func (e *encoded) add(line, start uint32, len uint32, tok tokenType, mod []string) { 63252- x := semItem{line, start, len, tok, mod} 63253- e.items = append(e.items, x) 63254-} 63255- 63256-// semItem represents a token found walking the parse tree 63257-type semItem struct { 63258- line, start uint32 63259- len uint32 63260- typeStr tokenType 63261- mods []string 63262-} 63263- 63264-type encoded struct { 63265- // the generated data 63266- items []semItem 63267- 63268- noStrings bool 63269- noNumbers bool 63270- 63271- ctx context.Context 63272- // metadataSource is used to resolve imports 63273- metadataSource source.MetadataSource 63274- tokTypes, tokMods []string 63275- pgf *source.ParsedGoFile 63276- rng *protocol.Range 63277- ti *types.Info 63278- pkg source.Package 63279- fset *token.FileSet 63280- // allowed starting and ending token.Pos, set by init 63281- // used to avoid looking at declarations not in range 63282- start, end token.Pos 63283- // path from the root of the parse tree, used for debugging 63284- stack []ast.Node 63285-} 63286- 63287-// convert the stack to a string, for debugging 63288-func (e *encoded) strStack() string { 63289- msg := []string{"["} 63290- for i := len(e.stack) - 1; i >= 0; i-- { 63291- s := e.stack[i] 63292- msg = append(msg, fmt.Sprintf("%T", s)[5:]) 63293- } 63294- if len(e.stack) > 0 { 63295- loc := e.stack[len(e.stack)-1].Pos() 63296- if _, err := safetoken.Offset(e.pgf.Tok, loc); err != nil { 63297- msg = append(msg, fmt.Sprintf("invalid position %v for %s", loc, e.pgf.URI)) 63298- } else { 63299- add := safetoken.Position(e.pgf.Tok, loc) 63300- nm := filepath.Base(add.Filename) 63301- msg = append(msg, fmt.Sprintf("(%s:%d,col:%d)", nm, add.Line, add.Column)) 63302- } 63303- } 63304- msg = append(msg, "]") 63305- return strings.Join(msg, " ") 63306-} 63307- 63308-// find the line in the source 63309-func (e *encoded) srcLine(x ast.Node) string { 63310- file := e.pgf.Tok 63311- line := file.Line(x.Pos()) 63312- start, err := safetoken.Offset(file, file.LineStart(line)) 63313- if err != nil { 63314- return "" 63315- } 63316- end := start 63317- for ; end < len(e.pgf.Src) && e.pgf.Src[end] != '\n'; end++ { 63318- 63319- } 63320- ans := e.pgf.Src[start:end] 63321- return string(ans) 63322-} 63323- 63324-func (e *encoded) inspector(n ast.Node) bool { 63325- pop := func() { 63326- e.stack = e.stack[:len(e.stack)-1] 63327- } 63328- if n == nil { 63329- pop() 63330- return true 63331- } 63332- e.stack = append(e.stack, n) 63333- switch x := n.(type) { 63334- case *ast.ArrayType: 63335- case *ast.AssignStmt: 63336- e.token(x.TokPos, len(x.Tok.String()), tokOperator, nil) 63337- case *ast.BasicLit: 63338- if strings.Contains(x.Value, "\n") { 63339- // has to be a string. 63340- e.multiline(x.Pos(), x.End(), x.Value, tokString) 63341- break 63342- } 63343- ln := len(x.Value) 63344- what := tokNumber 63345- if x.Kind == token.STRING { 63346- what = tokString 63347- } 63348- e.token(x.Pos(), ln, what, nil) 63349- case *ast.BinaryExpr: 63350- e.token(x.OpPos, len(x.Op.String()), tokOperator, nil) 63351- case *ast.BlockStmt: 63352- case *ast.BranchStmt: 63353- e.token(x.TokPos, len(x.Tok.String()), tokKeyword, nil) 63354- // There's no semantic encoding for labels 63355- case *ast.CallExpr: 63356- if x.Ellipsis != token.NoPos { 63357- e.token(x.Ellipsis, len("..."), tokOperator, nil) 63358- } 63359- case *ast.CaseClause: 63360- iam := "case" 63361- if x.List == nil { 63362- iam = "default" 63363- } 63364- e.token(x.Case, len(iam), tokKeyword, nil) 63365- case *ast.ChanType: 63366- // chan | chan <- | <- chan 63367- switch { 63368- case x.Arrow == token.NoPos: 63369- e.token(x.Begin, len("chan"), tokKeyword, nil) 63370- case x.Arrow == x.Begin: 63371- e.token(x.Arrow, 2, tokOperator, nil) 63372- pos := e.findKeyword("chan", x.Begin+2, x.Value.Pos()) 63373- e.token(pos, len("chan"), tokKeyword, nil) 63374- case x.Arrow != x.Begin: 63375- e.token(x.Begin, len("chan"), tokKeyword, nil) 63376- e.token(x.Arrow, 2, tokOperator, nil) 63377- } 63378- case *ast.CommClause: 63379- iam := len("case") 63380- if x.Comm == nil { 63381- iam = len("default") 63382- } 63383- e.token(x.Case, iam, tokKeyword, nil) 63384- case *ast.CompositeLit: 63385- case *ast.DeclStmt: 63386- case *ast.DeferStmt: 63387- e.token(x.Defer, len("defer"), tokKeyword, nil) 63388- case *ast.Ellipsis: 63389- e.token(x.Ellipsis, len("..."), tokOperator, nil) 63390- case *ast.EmptyStmt: 63391- case *ast.ExprStmt: 63392- case *ast.Field: 63393- case *ast.FieldList: 63394- case *ast.ForStmt: 63395- e.token(x.For, len("for"), tokKeyword, nil) 63396- case *ast.FuncDecl: 63397- case *ast.FuncLit: 63398- case *ast.FuncType: 63399- if x.Func != token.NoPos { 63400- e.token(x.Func, len("func"), tokKeyword, nil) 63401- } 63402- case *ast.GenDecl: 63403- e.token(x.TokPos, len(x.Tok.String()), tokKeyword, nil) 63404- case *ast.GoStmt: 63405- e.token(x.Go, len("go"), tokKeyword, nil) 63406- case *ast.Ident: 63407- e.ident(x) 63408- case *ast.IfStmt: 63409- e.token(x.If, len("if"), tokKeyword, nil) 63410- if x.Else != nil { 63411- // x.Body.End() or x.Body.End()+1, not that it matters 63412- pos := e.findKeyword("else", x.Body.End(), x.Else.Pos()) 63413- e.token(pos, len("else"), tokKeyword, nil) 63414- } 63415- case *ast.ImportSpec: 63416- e.importSpec(x) 63417- pop() 63418- return false 63419- case *ast.IncDecStmt: 63420- e.token(x.TokPos, len(x.Tok.String()), tokOperator, nil) 63421- case *ast.IndexExpr: 63422- case *typeparams.IndexListExpr: 63423- case *ast.InterfaceType: 63424- e.token(x.Interface, len("interface"), tokKeyword, nil) 63425- case *ast.KeyValueExpr: 63426- case *ast.LabeledStmt: 63427- case *ast.MapType: 63428- e.token(x.Map, len("map"), tokKeyword, nil) 63429- case *ast.ParenExpr: 63430- case *ast.RangeStmt: 63431- e.token(x.For, len("for"), tokKeyword, nil) 63432- // x.TokPos == token.NoPos is legal (for range foo {}) 63433- offset := x.TokPos 63434- if offset == token.NoPos { 63435- offset = x.For 63436- } 63437- pos := e.findKeyword("range", offset, x.X.Pos()) 63438- e.token(pos, len("range"), tokKeyword, nil) 63439- case *ast.ReturnStmt: 63440- e.token(x.Return, len("return"), tokKeyword, nil) 63441- case *ast.SelectStmt: 63442- e.token(x.Select, len("select"), tokKeyword, nil) 63443- case *ast.SelectorExpr: 63444- case *ast.SendStmt: 63445- e.token(x.Arrow, len("<-"), tokOperator, nil) 63446- case *ast.SliceExpr: 63447- case *ast.StarExpr: 63448- e.token(x.Star, len("*"), tokOperator, nil) 63449- case *ast.StructType: 63450- e.token(x.Struct, len("struct"), tokKeyword, nil) 63451- case *ast.SwitchStmt: 63452- e.token(x.Switch, len("switch"), tokKeyword, nil) 63453- case *ast.TypeAssertExpr: 63454- if x.Type == nil { 63455- pos := e.findKeyword("type", x.Lparen, x.Rparen) 63456- e.token(pos, len("type"), tokKeyword, nil) 63457- } 63458- case *ast.TypeSpec: 63459- case *ast.TypeSwitchStmt: 63460- e.token(x.Switch, len("switch"), tokKeyword, nil) 63461- case *ast.UnaryExpr: 63462- e.token(x.OpPos, len(x.Op.String()), tokOperator, nil) 63463- case *ast.ValueSpec: 63464- // things only seen with parsing or type errors, so ignore them 63465- case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt: 63466- return true 63467- // not going to see these 63468- case *ast.File, *ast.Package: 63469- e.unexpected(fmt.Sprintf("implement %T %s", x, safetoken.Position(e.pgf.Tok, x.Pos()))) 63470- // other things we knowingly ignore 63471- case *ast.Comment, *ast.CommentGroup: 63472- pop() 63473- return false 63474- default: 63475- e.unexpected(fmt.Sprintf("failed to implement %T", x)) 63476- } 63477- return true 63478-} 63479- 63480-func (e *encoded) ident(x *ast.Ident) { 63481- if e.ti == nil { 63482- what, mods := e.unkIdent(x) 63483- if what != "" { 63484- e.token(x.Pos(), len(x.String()), what, mods) 63485- } 63486- if semDebug { 63487- log.Printf(" nil %s/nil/nil %q %v %s", x.String(), what, mods, e.strStack()) 63488- } 63489- return 63490- } 63491- def := e.ti.Defs[x] 63492- if def != nil { 63493- what, mods := e.definitionFor(x, def) 63494- if what != "" { 63495- e.token(x.Pos(), len(x.String()), what, mods) 63496- } 63497- if semDebug { 63498- log.Printf(" for %s/%T/%T got %s %v (%s)", x.String(), def, def.Type(), what, mods, e.strStack()) 63499- } 63500- return 63501- } 63502- use := e.ti.Uses[x] 63503- tok := func(pos token.Pos, lng int, tok tokenType, mods []string) { 63504- e.token(pos, lng, tok, mods) 63505- q := "nil" 63506- if use != nil { 63507- q = fmt.Sprintf("%T", use.Type()) 63508- } 63509- if semDebug { 63510- log.Printf(" use %s/%T/%s got %s %v (%s)", x.String(), use, q, tok, mods, e.strStack()) 63511- } 63512- } 63513- 63514- switch y := use.(type) { 63515- case nil: 63516- what, mods := e.unkIdent(x) 63517- if what != "" { 63518- tok(x.Pos(), len(x.String()), what, mods) 63519- } else if semDebug { 63520- // tok() wasn't called, so didn't log 63521- log.Printf(" nil %s/%T/nil %q %v (%s)", x.String(), use, what, mods, e.strStack()) 63522- } 63523- return 63524- case *types.Builtin: 63525- tok(x.NamePos, len(x.Name), tokFunction, []string{"defaultLibrary"}) 63526- case *types.Const: 63527- mods := []string{"readonly"} 63528- tt := y.Type() 63529- if _, ok := tt.(*types.Basic); ok { 63530- tok(x.Pos(), len(x.String()), tokVariable, mods) 63531- break 63532- } 63533- if ttx, ok := tt.(*types.Named); ok { 63534- if x.String() == "iota" { 63535- e.unexpected(fmt.Sprintf("iota:%T", ttx)) 63536- } 63537- if _, ok := ttx.Underlying().(*types.Basic); ok { 63538- tok(x.Pos(), len(x.String()), tokVariable, mods) 63539- break 63540- } 63541- e.unexpected(fmt.Sprintf("%q/%T", x.String(), tt)) 63542- } 63543- // can this happen? Don't think so 63544- e.unexpected(fmt.Sprintf("%s %T %#v", x.String(), tt, tt)) 63545- case *types.Func: 63546- tok(x.Pos(), len(x.Name), tokFunction, nil) 63547- case *types.Label: 63548- // nothing to map it to 63549- case *types.Nil: 63550- // nil is a predeclared identifier 63551- tok(x.Pos(), len("nil"), tokVariable, []string{"readonly", "defaultLibrary"}) 63552- case *types.PkgName: 63553- tok(x.Pos(), len(x.Name), tokNamespace, nil) 63554- case *types.TypeName: // could be a tokTpeParam 63555- var mods []string 63556- if _, ok := y.Type().(*types.Basic); ok { 63557- mods = []string{"defaultLibrary"} 63558- } else if _, ok := y.Type().(*typeparams.TypeParam); ok { 63559- tok(x.Pos(), len(x.String()), tokTypeParam, mods) 63560- break 63561- } 63562- tok(x.Pos(), len(x.String()), tokType, mods) 63563- case *types.Var: 63564- if isSignature(y) { 63565- tok(x.Pos(), len(x.Name), tokFunction, nil) 63566- } else if e.isParam(use.Pos()) { 63567- // variable, unless use.pos is the pos of a Field in an ancestor FuncDecl 63568- // or FuncLit and then it's a parameter 63569- tok(x.Pos(), len(x.Name), tokParameter, nil) 63570- } else { 63571- tok(x.Pos(), len(x.Name), tokVariable, nil) 63572- } 63573- 63574- default: 63575- // can't happen 63576- if use == nil { 63577- msg := fmt.Sprintf("%#v %#v %#v", x, e.ti.Defs[x], e.ti.Uses[x]) 63578- e.unexpected(msg) 63579- } 63580- if use.Type() != nil { 63581- e.unexpected(fmt.Sprintf("%s %T/%T,%#v", x.String(), use, use.Type(), use)) 63582- } else { 63583- e.unexpected(fmt.Sprintf("%s %T", x.String(), use)) 63584- } 63585- } 63586-} 63587- 63588-func (e *encoded) isParam(pos token.Pos) bool { 63589- for i := len(e.stack) - 1; i >= 0; i-- { 63590- switch n := e.stack[i].(type) { 63591- case *ast.FuncDecl: 63592- for _, f := range n.Type.Params.List { 63593- for _, id := range f.Names { 63594- if id.Pos() == pos { 63595- return true 63596- } 63597- } 63598- } 63599- case *ast.FuncLit: 63600- for _, f := range n.Type.Params.List { 63601- for _, id := range f.Names { 63602- if id.Pos() == pos { 63603- return true 63604- } 63605- } 63606- } 63607- } 63608- } 63609- return false 63610-} 63611- 63612-func isSignature(use types.Object) bool { 63613- if _, ok := use.(*types.Var); !ok { 63614- return false 63615- } 63616- v := use.Type() 63617- if v == nil { 63618- return false 63619- } 63620- if _, ok := v.(*types.Signature); ok { 63621- return true 63622- } 63623- return false 63624-} 63625- 63626-// both e.ti.Defs and e.ti.Uses are nil. use the parse stack. 63627-// a lot of these only happen when the package doesn't compile 63628-// but in that case it is all best-effort from the parse tree 63629-func (e *encoded) unkIdent(x *ast.Ident) (tokenType, []string) { 63630- def := []string{"definition"} 63631- n := len(e.stack) - 2 // parent of Ident 63632- if n < 0 { 63633- e.unexpected("no stack?") 63634- return "", nil 63635- } 63636- switch nd := e.stack[n].(type) { 63637- case *ast.BinaryExpr, *ast.UnaryExpr, *ast.ParenExpr, *ast.StarExpr, 63638- *ast.IncDecStmt, *ast.SliceExpr, *ast.ExprStmt, *ast.IndexExpr, 63639- *ast.ReturnStmt, *ast.ChanType, *ast.SendStmt, 63640- *ast.ForStmt, // possibly incomplete 63641- *ast.IfStmt, /* condition */ 63642- *ast.KeyValueExpr: // either key or value 63643- return tokVariable, nil 63644- case *typeparams.IndexListExpr: 63645- return tokVariable, nil 63646- case *ast.Ellipsis: 63647- return tokType, nil 63648- case *ast.CaseClause: 63649- if n-2 >= 0 { 63650- if _, ok := e.stack[n-2].(*ast.TypeSwitchStmt); ok { 63651- return tokType, nil 63652- } 63653- } 63654- return tokVariable, nil 63655- case *ast.ArrayType: 63656- if x == nd.Len { 63657- // or maybe a Type Param, but we can't just from the parse tree 63658- return tokVariable, nil 63659- } else { 63660- return tokType, nil 63661- } 63662- case *ast.MapType: 63663- return tokType, nil 63664- case *ast.CallExpr: 63665- if x == nd.Fun { 63666- return tokFunction, nil 63667- } 63668- return tokVariable, nil 63669- case *ast.SwitchStmt: 63670- return tokVariable, nil 63671- case *ast.TypeAssertExpr: 63672- if x == nd.X { 63673- return tokVariable, nil 63674- } else if x == nd.Type { 63675- return tokType, nil 63676- } 63677- case *ast.ValueSpec: 63678- for _, p := range nd.Names { 63679- if p == x { 63680- return tokVariable, def 63681- } 63682- } 63683- for _, p := range nd.Values { 63684- if p == x { 63685- return tokVariable, nil 63686- } 63687- } 63688- return tokType, nil 63689- case *ast.SelectorExpr: // e.ti.Selections[nd] is nil, so no help 63690- if n-1 >= 0 { 63691- if ce, ok := e.stack[n-1].(*ast.CallExpr); ok { 63692- // ... CallExpr SelectorExpr Ident (_.x()) 63693- if ce.Fun == nd && nd.Sel == x { 63694- return tokFunction, nil 63695- } 63696- } 63697- } 63698- return tokVariable, nil 63699- case *ast.AssignStmt: 63700- for _, p := range nd.Lhs { 63701- // x := ..., or x = ... 63702- if p == x { 63703- if nd.Tok != token.DEFINE { 63704- def = nil 63705- } 63706- return tokVariable, def // '_' in _ = ... 63707- } 63708- } 63709- // RHS, = x 63710- return tokVariable, nil 63711- case *ast.TypeSpec: // it's a type if it is either the Name or the Type 63712- if x == nd.Type { 63713- def = nil 63714- } 63715- return tokType, def 63716- case *ast.Field: 63717- // ident could be type in a field, or a method in an interface type, or a variable 63718- if x == nd.Type { 63719- return tokType, nil 63720- } 63721- if n-2 >= 0 { 63722- _, okit := e.stack[n-2].(*ast.InterfaceType) 63723- _, okfl := e.stack[n-1].(*ast.FieldList) 63724- if okit && okfl { 63725- return tokMethod, def 63726- } 63727- } 63728- return tokVariable, nil 63729- case *ast.LabeledStmt, *ast.BranchStmt: 63730- // nothing to report 63731- case *ast.CompositeLit: 63732- if nd.Type == x { 63733- return tokType, nil 63734- } 63735- return tokVariable, nil 63736- case *ast.RangeStmt: 63737- if nd.Tok != token.DEFINE { 63738- def = nil 63739- } 63740- return tokVariable, def 63741- case *ast.FuncDecl: 63742- return tokFunction, def 63743- default: 63744- msg := fmt.Sprintf("%T undexpected: %s %s%q", nd, x.Name, e.strStack(), e.srcLine(x)) 63745- e.unexpected(msg) 63746- } 63747- return "", nil 63748-} 63749- 63750-func isDeprecated(n *ast.CommentGroup) bool { 63751- if n == nil { 63752- return false 63753- } 63754- for _, c := range n.List { 63755- if strings.HasPrefix(c.Text, "// Deprecated") { 63756- return true 63757- } 63758- } 63759- return false 63760-} 63761- 63762-func (e *encoded) definitionFor(x *ast.Ident, def types.Object) (tokenType, []string) { 63763- // PJW: def == types.Label? probably a nothing 63764- // PJW: look into replacing these syntactic tests with types more generally 63765- mods := []string{"definition"} 63766- for i := len(e.stack) - 1; i >= 0; i-- { 63767- s := e.stack[i] 63768- switch y := s.(type) { 63769- case *ast.AssignStmt, *ast.RangeStmt: 63770- if x.Name == "_" { 63771- return "", nil // not really a variable 63772- } 63773- return tokVariable, mods 63774- case *ast.GenDecl: 63775- if isDeprecated(y.Doc) { 63776- mods = append(mods, "deprecated") 63777- } 63778- if y.Tok == token.CONST { 63779- mods = append(mods, "readonly") 63780- } 63781- return tokVariable, mods 63782- case *ast.FuncDecl: 63783- // If x is immediately under a FuncDecl, it is a function or method 63784- if i == len(e.stack)-2 { 63785- if isDeprecated(y.Doc) { 63786- mods = append(mods, "deprecated") 63787- } 63788- if y.Recv != nil { 63789- return tokMethod, mods 63790- } 63791- return tokFunction, mods 63792- } 63793- // if x < ... < FieldList < FuncDecl, this is the receiver, a variable 63794- // PJW: maybe not. it might be a typeparameter in the type of the receiver 63795- if _, ok := e.stack[i+1].(*ast.FieldList); ok { 63796- if _, ok := def.(*types.TypeName); ok { 63797- return tokTypeParam, mods 63798- } 63799- return tokVariable, nil 63800- } 63801- // if x < ... < FieldList < FuncType < FuncDecl, this is a param 63802- return tokParameter, mods 63803- case *ast.FuncType: // is it in the TypeParams? 63804- if isTypeParam(x, y) { 63805- return tokTypeParam, mods 63806- } 63807- return tokParameter, mods 63808- case *ast.InterfaceType: 63809- return tokMethod, mods 63810- case *ast.TypeSpec: 63811- // GenDecl/Typespec/FuncType/FieldList/Field/Ident 63812- // (type A func(b uint64)) (err error) 63813- // b and err should not be tokType, but tokVaraible 63814- // and in GenDecl/TpeSpec/StructType/FieldList/Field/Ident 63815- // (type A struct{b uint64} 63816- // but on type B struct{C}), C is a type, but is not being defined. 63817- // GenDecl/TypeSpec/FieldList/Field/Ident is a typeParam 63818- if _, ok := e.stack[i+1].(*ast.FieldList); ok { 63819- return tokTypeParam, mods 63820- } 63821- fldm := e.stack[len(e.stack)-2] 63822- if fld, ok := fldm.(*ast.Field); ok { 63823- // if len(fld.names) == 0 this is a tokType, being used 63824- if len(fld.Names) == 0 { 63825- return tokType, nil 63826- } 63827- return tokVariable, mods 63828- } 63829- return tokType, mods 63830- } 63831- } 63832- // can't happen 63833- msg := fmt.Sprintf("failed to find the decl for %s", safetoken.Position(e.pgf.Tok, x.Pos())) 63834- e.unexpected(msg) 63835- return "", []string{""} 63836-} 63837- 63838-func isTypeParam(x *ast.Ident, y *ast.FuncType) bool { 63839- tp := typeparams.ForFuncType(y) 63840- if tp == nil { 63841- return false 63842- } 63843- for _, p := range tp.List { 63844- for _, n := range p.Names { 63845- if x == n { 63846- return true 63847- } 63848- } 63849- } 63850- return false 63851-} 63852- 63853-func (e *encoded) multiline(start, end token.Pos, val string, tok tokenType) { 63854- f := e.fset.File(start) 63855- // the hard part is finding the lengths of lines. include the \n 63856- leng := func(line int) int { 63857- n := f.LineStart(line) 63858- if line >= f.LineCount() { 63859- return f.Size() - int(n) 63860- } 63861- return int(f.LineStart(line+1) - n) 63862- } 63863- spos := safetoken.StartPosition(e.fset, start) 63864- epos := safetoken.EndPosition(e.fset, end) 63865- sline := spos.Line 63866- eline := epos.Line 63867- // first line is from spos.Column to end 63868- e.token(start, leng(sline)-spos.Column, tok, nil) // leng(sline)-1 - (spos.Column-1) 63869- for i := sline + 1; i < eline; i++ { 63870- // intermediate lines are from 1 to end 63871- e.token(f.LineStart(i), leng(i)-1, tok, nil) // avoid the newline 63872- } 63873- // last line is from 1 to epos.Column 63874- e.token(f.LineStart(eline), epos.Column-1, tok, nil) // columns are 1-based 63875-} 63876- 63877-// findKeyword finds a keyword rather than guessing its location 63878-func (e *encoded) findKeyword(keyword string, start, end token.Pos) token.Pos { 63879- offset := int(start) - e.pgf.Tok.Base() 63880- last := int(end) - e.pgf.Tok.Base() 63881- buf := e.pgf.Src 63882- idx := bytes.Index(buf[offset:last], []byte(keyword)) 63883- if idx != -1 { 63884- return start + token.Pos(idx) 63885- } 63886- //(in unparsable programs: type _ <-<-chan int) 63887- e.unexpected(fmt.Sprintf("not found:%s %v", keyword, safetoken.StartPosition(e.fset, start))) 63888- return token.NoPos 63889-} 63890- 63891-func (e *encoded) init() error { 63892- e.start = token.Pos(e.pgf.Tok.Base()) 63893- e.end = e.start + token.Pos(e.pgf.Tok.Size()) 63894- if e.rng == nil { 63895- return nil 63896- } 63897- span, err := e.pgf.Mapper.RangeSpan(*e.rng) 63898- if err != nil { 63899- return fmt.Errorf("range span (%w) error for %s", err, e.pgf.File.Name) 63900- } 63901- e.end = e.start + token.Pos(span.End().Offset()) 63902- e.start += token.Pos(span.Start().Offset()) 63903- return nil 63904-} 63905- 63906-func (e *encoded) Data() []uint32 { 63907- // binary operators, at least, will be out of order 63908- sort.Slice(e.items, func(i, j int) bool { 63909- if e.items[i].line != e.items[j].line { 63910- return e.items[i].line < e.items[j].line 63911- } 63912- return e.items[i].start < e.items[j].start 63913- }) 63914- typeMap, modMap := e.maps() 63915- // each semantic token needs five values 63916- // (see Integer Encoding for Tokens in the LSP spec) 63917- x := make([]uint32, 5*len(e.items)) 63918- var j int 63919- var last semItem 63920- for i := 0; i < len(e.items); i++ { 63921- item := e.items[i] 63922- typ, ok := typeMap[item.typeStr] 63923- if !ok { 63924- continue // client doesn't want typeStr 63925- } 63926- if item.typeStr == tokString && e.noStrings { 63927- continue 63928- } 63929- if item.typeStr == tokNumber && e.noNumbers { 63930- continue 63931- } 63932- if j == 0 { 63933- x[0] = e.items[0].line 63934- } else { 63935- x[j] = item.line - last.line 63936- } 63937- x[j+1] = item.start 63938- if j > 0 && x[j] == 0 { 63939- x[j+1] = item.start - last.start 63940- } 63941- x[j+2] = item.len 63942- x[j+3] = uint32(typ) 63943- mask := 0 63944- for _, s := range item.mods { 63945- // modMap[s] is 0 if the client doesn't want this modifier 63946- mask |= modMap[s] 63947- } 63948- x[j+4] = uint32(mask) 63949- j += 5 63950- last = item 63951- } 63952- return x[:j] 63953-} 63954- 63955-func (e *encoded) importSpec(d *ast.ImportSpec) { 63956- // a local package name or the last component of the Path 63957- if d.Name != nil { 63958- nm := d.Name.String() 63959- if nm != "_" && nm != "." { 63960- e.token(d.Name.Pos(), len(nm), tokNamespace, nil) 63961- } 63962- return // don't mark anything for . or _ 63963- } 63964- importPath := source.UnquoteImportPath(d) 63965- if importPath == "" { 63966- return 63967- } 63968- // Import strings are implementation defined. Try to match with parse information. 63969- depID := e.pkg.Metadata().DepsByImpPath[importPath] 63970- if depID == "" { 63971- return 63972- } 63973- depMD := e.metadataSource.Metadata(depID) 63974- if depMD == nil { 63975- // unexpected, but impact is that maybe some import is not colored 63976- return 63977- } 63978- // Check whether the original literal contains the package's declared name. 63979- j := strings.LastIndex(d.Path.Value, string(depMD.Name)) 63980- if j == -1 { 63981- // Package name does not match import path, so there is nothing to report. 63982- return 63983- } 63984- // Report virtual declaration at the position of the substring. 63985- start := d.Path.Pos() + token.Pos(j) 63986- e.token(start, len(depMD.Name), tokNamespace, nil) 63987-} 63988- 63989-// log unexpected state 63990-func (e *encoded) unexpected(msg string) { 63991- if semDebug { 63992- panic(msg) 63993- } 63994- event.Error(e.ctx, e.strStack(), errors.New(msg)) 63995-} 63996- 63997-// SemType returns a string equivalent of the type, for gopls semtok 63998-func SemType(n int) string { 63999- tokTypes := SemanticTypes() 64000- tokMods := SemanticModifiers() 64001- if n >= 0 && n < len(tokTypes) { 64002- return tokTypes[n] 64003- } 64004- // not found for some reason 64005- return fmt.Sprintf("?%d[%d,%d]?", n, len(tokTypes), len(tokMods)) 64006-} 64007- 64008-// SemMods returns the []string equivalent of the mods, for gopls semtok. 64009-func SemMods(n int) []string { 64010- tokMods := SemanticModifiers() 64011- mods := []string{} 64012- for i := 0; i < len(tokMods); i++ { 64013- if (n & (1 << uint(i))) != 0 { 64014- mods = append(mods, tokMods[i]) 64015- } 64016- } 64017- return mods 64018-} 64019- 64020-func (e *encoded) maps() (map[tokenType]int, map[string]int) { 64021- tmap := make(map[tokenType]int) 64022- mmap := make(map[string]int) 64023- for i, t := range e.tokTypes { 64024- tmap[tokenType(t)] = i 64025- } 64026- for i, m := range e.tokMods { 64027- mmap[m] = 1 << uint(i) // go 1.12 compatibility 64028- } 64029- return tmap, mmap 64030-} 64031- 64032-// SemanticTypes to use in case there is no client, as in the command line, or tests 64033-func SemanticTypes() []string { 64034- return semanticTypes[:] 64035-} 64036- 64037-// SemanticModifiers to use in case there is no client. 64038-func SemanticModifiers() []string { 64039- return semanticModifiers[:] 64040-} 64041- 64042-var ( 64043- semanticTypes = [...]string{ 64044- "namespace", "type", "class", "enum", "interface", 64045- "struct", "typeParameter", "parameter", "variable", "property", "enumMember", 64046- "event", "function", "method", "macro", "keyword", "modifier", "comment", 64047- "string", "number", "regexp", "operator", 64048- } 64049- semanticModifiers = [...]string{ 64050- "declaration", "definition", "readonly", "static", 64051- "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary", 64052- } 64053-) 64054diff -urN a/gopls/internal/lsp/server_gen.go b/gopls/internal/lsp/server_gen.go 64055--- a/gopls/internal/lsp/server_gen.go 2000-01-01 00:00:00.000000000 -0000 64056+++ b/gopls/internal/lsp/server_gen.go 1970-01-01 00:00:00.000000000 +0000 64057@@ -1,301 +0,0 @@ 64058-// Copyright 2021 The Go Authors. All rights reserved. 64059-// Use of this source code is governed by a BSD-style 64060-// license that can be found in the LICENSE file. 64061- 64062-package lsp 64063- 64064-// code generated by helper. DO NOT EDIT. 64065- 64066-import ( 64067- "context" 64068- 64069- "golang.org/x/tools/gopls/internal/lsp/protocol" 64070-) 64071- 64072-func (s *Server) CodeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) { 64073- return s.codeAction(ctx, params) 64074-} 64075- 64076-func (s *Server) CodeLens(ctx context.Context, params *protocol.CodeLensParams) ([]protocol.CodeLens, error) { 64077- return s.codeLens(ctx, params) 64078-} 64079- 64080-func (s *Server) ColorPresentation(context.Context, *protocol.ColorPresentationParams) ([]protocol.ColorPresentation, error) { 64081- return nil, notImplemented("ColorPresentation") 64082-} 64083- 64084-func (s *Server) Completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) { 64085- return s.completion(ctx, params) 64086-} 64087- 64088-func (s *Server) Declaration(context.Context, *protocol.DeclarationParams) (*protocol.Or_textDocument_declaration, error) { 64089- return nil, notImplemented("Declaration") 64090-} 64091- 64092-func (s *Server) Definition(ctx context.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) { 64093- return s.definition(ctx, params) 64094-} 64095- 64096-func (s *Server) Diagnostic(context.Context, *string) (*string, error) { 64097- return nil, notImplemented("Diagnostic") 64098-} 64099- 64100-func (s *Server) DiagnosticWorkspace(context.Context, *protocol.WorkspaceDiagnosticParams) (*protocol.WorkspaceDiagnosticReport, error) { 64101- return nil, notImplemented("DiagnosticWorkspace") 64102-} 64103- 64104-func (s *Server) DidChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error { 64105- return s.didChange(ctx, params) 64106-} 64107- 64108-func (s *Server) DidChangeConfiguration(ctx context.Context, _gen *protocol.DidChangeConfigurationParams) error { 64109- return s.didChangeConfiguration(ctx, _gen) 64110-} 64111- 64112-func (s *Server) DidChangeNotebookDocument(context.Context, *protocol.DidChangeNotebookDocumentParams) error { 64113- return notImplemented("DidChangeNotebookDocument") 64114-} 64115- 64116-func (s *Server) DidChangeWatchedFiles(ctx context.Context, params *protocol.DidChangeWatchedFilesParams) error { 64117- return s.didChangeWatchedFiles(ctx, params) 64118-} 64119- 64120-func (s *Server) DidChangeWorkspaceFolders(ctx context.Context, params *protocol.DidChangeWorkspaceFoldersParams) error { 64121- return s.didChangeWorkspaceFolders(ctx, params) 64122-} 64123- 64124-func (s *Server) DidClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error { 64125- return s.didClose(ctx, params) 64126-} 64127- 64128-func (s *Server) DidCloseNotebookDocument(context.Context, *protocol.DidCloseNotebookDocumentParams) error { 64129- return notImplemented("DidCloseNotebookDocument") 64130-} 64131- 64132-func (s *Server) DidCreateFiles(context.Context, *protocol.CreateFilesParams) error { 64133- return notImplemented("DidCreateFiles") 64134-} 64135- 64136-func (s *Server) DidDeleteFiles(context.Context, *protocol.DeleteFilesParams) error { 64137- return notImplemented("DidDeleteFiles") 64138-} 64139- 64140-func (s *Server) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { 64141- return s.didOpen(ctx, params) 64142-} 64143- 64144-func (s *Server) DidOpenNotebookDocument(context.Context, *protocol.DidOpenNotebookDocumentParams) error { 64145- return notImplemented("DidOpenNotebookDocument") 64146-} 64147- 64148-func (s *Server) DidRenameFiles(context.Context, *protocol.RenameFilesParams) error { 64149- return notImplemented("DidRenameFiles") 64150-} 64151- 64152-func (s *Server) DidSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) error { 64153- return s.didSave(ctx, params) 64154-} 64155- 64156-func (s *Server) DidSaveNotebookDocument(context.Context, *protocol.DidSaveNotebookDocumentParams) error { 64157- return notImplemented("DidSaveNotebookDocument") 64158-} 64159- 64160-func (s *Server) DocumentColor(context.Context, *protocol.DocumentColorParams) ([]protocol.ColorInformation, error) { 64161- return nil, notImplemented("DocumentColor") 64162-} 64163- 64164-func (s *Server) DocumentHighlight(ctx context.Context, params *protocol.DocumentHighlightParams) ([]protocol.DocumentHighlight, error) { 64165- return s.documentHighlight(ctx, params) 64166-} 64167- 64168-func (s *Server) DocumentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) { 64169- return s.documentLink(ctx, params) 64170-} 64171- 64172-func (s *Server) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]interface{}, error) { 64173- return s.documentSymbol(ctx, params) 64174-} 64175- 64176-func (s *Server) ExecuteCommand(ctx context.Context, params *protocol.ExecuteCommandParams) (interface{}, error) { 64177- return s.executeCommand(ctx, params) 64178-} 64179- 64180-func (s *Server) Exit(ctx context.Context) error { 64181- return s.exit(ctx) 64182-} 64183- 64184-func (s *Server) FoldingRange(ctx context.Context, params *protocol.FoldingRangeParams) ([]protocol.FoldingRange, error) { 64185- return s.foldingRange(ctx, params) 64186-} 64187- 64188-func (s *Server) Formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) { 64189- return s.formatting(ctx, params) 64190-} 64191- 64192-func (s *Server) Hover(ctx context.Context, params *protocol.HoverParams) (*protocol.Hover, error) { 64193- return s.hover(ctx, params) 64194-} 64195- 64196-func (s *Server) Implementation(ctx context.Context, params *protocol.ImplementationParams) ([]protocol.Location, error) { 64197- return s.implementation(ctx, params) 64198-} 64199- 64200-func (s *Server) IncomingCalls(ctx context.Context, params *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) { 64201- return s.incomingCalls(ctx, params) 64202-} 64203- 64204-func (s *Server) Initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) { 64205- return s.initialize(ctx, params) 64206-} 64207- 64208-func (s *Server) Initialized(ctx context.Context, params *protocol.InitializedParams) error { 64209- return s.initialized(ctx, params) 64210-} 64211- 64212-func (s *Server) InlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) { 64213- return s.inlayHint(ctx, params) 64214-} 64215- 64216-func (s *Server) InlineValue(context.Context, *protocol.InlineValueParams) ([]protocol.InlineValue, error) { 64217- return nil, notImplemented("InlineValue") 64218-} 64219- 64220-func (s *Server) LinkedEditingRange(context.Context, *protocol.LinkedEditingRangeParams) (*protocol.LinkedEditingRanges, error) { 64221- return nil, notImplemented("LinkedEditingRange") 64222-} 64223- 64224-func (s *Server) Moniker(context.Context, *protocol.MonikerParams) ([]protocol.Moniker, error) { 64225- return nil, notImplemented("Moniker") 64226-} 64227- 64228-func (s *Server) NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) { 64229- return s.nonstandardRequest(ctx, method, params) 64230-} 64231- 64232-func (s *Server) OnTypeFormatting(context.Context, *protocol.DocumentOnTypeFormattingParams) ([]protocol.TextEdit, error) { 64233- return nil, notImplemented("OnTypeFormatting") 64234-} 64235- 64236-func (s *Server) OutgoingCalls(ctx context.Context, params *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) { 64237- return s.outgoingCalls(ctx, params) 64238-} 64239- 64240-func (s *Server) PrepareCallHierarchy(ctx context.Context, params *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) { 64241- return s.prepareCallHierarchy(ctx, params) 64242-} 64243- 64244-func (s *Server) PrepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.PrepareRename2Gn, error) { 64245- return s.prepareRename(ctx, params) 64246-} 64247- 64248-func (s *Server) PrepareTypeHierarchy(context.Context, *protocol.TypeHierarchyPrepareParams) ([]protocol.TypeHierarchyItem, error) { 64249- return nil, notImplemented("PrepareTypeHierarchy") 64250-} 64251- 64252-func (s *Server) Progress(context.Context, *protocol.ProgressParams) error { 64253- return notImplemented("Progress") 64254-} 64255- 64256-func (s *Server) RangeFormatting(context.Context, *protocol.DocumentRangeFormattingParams) ([]protocol.TextEdit, error) { 64257- return nil, notImplemented("RangeFormatting") 64258-} 64259- 64260-func (s *Server) References(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) { 64261- return s.references(ctx, params) 64262-} 64263- 64264-func (s *Server) Rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) { 64265- return s.rename(ctx, params) 64266-} 64267- 64268-func (s *Server) Resolve(context.Context, *protocol.InlayHint) (*protocol.InlayHint, error) { 64269- return nil, notImplemented("Resolve") 64270-} 64271- 64272-func (s *Server) ResolveCodeAction(context.Context, *protocol.CodeAction) (*protocol.CodeAction, error) { 64273- return nil, notImplemented("ResolveCodeAction") 64274-} 64275- 64276-func (s *Server) ResolveCodeLens(context.Context, *protocol.CodeLens) (*protocol.CodeLens, error) { 64277- return nil, notImplemented("ResolveCodeLens") 64278-} 64279- 64280-func (s *Server) ResolveCompletionItem(context.Context, *protocol.CompletionItem) (*protocol.CompletionItem, error) { 64281- return nil, notImplemented("ResolveCompletionItem") 64282-} 64283- 64284-func (s *Server) ResolveDocumentLink(context.Context, *protocol.DocumentLink) (*protocol.DocumentLink, error) { 64285- return nil, notImplemented("ResolveDocumentLink") 64286-} 64287- 64288-func (s *Server) ResolveWorkspaceSymbol(context.Context, *protocol.WorkspaceSymbol) (*protocol.WorkspaceSymbol, error) { 64289- return nil, notImplemented("ResolveWorkspaceSymbol") 64290-} 64291- 64292-func (s *Server) SelectionRange(ctx context.Context, params *protocol.SelectionRangeParams) ([]protocol.SelectionRange, error) { 64293- return s.selectionRange(ctx, params) 64294-} 64295- 64296-func (s *Server) SemanticTokensFull(ctx context.Context, p *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) { 64297- return s.semanticTokensFull(ctx, p) 64298-} 64299- 64300-func (s *Server) SemanticTokensFullDelta(ctx context.Context, p *protocol.SemanticTokensDeltaParams) (interface{}, error) { 64301- return s.semanticTokensFullDelta(ctx, p) 64302-} 64303- 64304-func (s *Server) SemanticTokensRange(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) { 64305- return s.semanticTokensRange(ctx, p) 64306-} 64307- 64308-func (s *Server) SetTrace(context.Context, *protocol.SetTraceParams) error { 64309- return notImplemented("SetTrace") 64310-} 64311- 64312-func (s *Server) Shutdown(ctx context.Context) error { 64313- return s.shutdown(ctx) 64314-} 64315- 64316-func (s *Server) SignatureHelp(ctx context.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) { 64317- return s.signatureHelp(ctx, params) 64318-} 64319- 64320-func (s *Server) Subtypes(context.Context, *protocol.TypeHierarchySubtypesParams) ([]protocol.TypeHierarchyItem, error) { 64321- return nil, notImplemented("Subtypes") 64322-} 64323- 64324-func (s *Server) Supertypes(context.Context, *protocol.TypeHierarchySupertypesParams) ([]protocol.TypeHierarchyItem, error) { 64325- return nil, notImplemented("Supertypes") 64326-} 64327- 64328-func (s *Server) Symbol(ctx context.Context, params *protocol.WorkspaceSymbolParams) ([]protocol.SymbolInformation, error) { 64329- return s.symbol(ctx, params) 64330-} 64331- 64332-func (s *Server) TypeDefinition(ctx context.Context, params *protocol.TypeDefinitionParams) ([]protocol.Location, error) { 64333- return s.typeDefinition(ctx, params) 64334-} 64335- 64336-func (s *Server) WillCreateFiles(context.Context, *protocol.CreateFilesParams) (*protocol.WorkspaceEdit, error) { 64337- return nil, notImplemented("WillCreateFiles") 64338-} 64339- 64340-func (s *Server) WillDeleteFiles(context.Context, *protocol.DeleteFilesParams) (*protocol.WorkspaceEdit, error) { 64341- return nil, notImplemented("WillDeleteFiles") 64342-} 64343- 64344-func (s *Server) WillRenameFiles(context.Context, *protocol.RenameFilesParams) (*protocol.WorkspaceEdit, error) { 64345- return nil, notImplemented("WillRenameFiles") 64346-} 64347- 64348-func (s *Server) WillSave(context.Context, *protocol.WillSaveTextDocumentParams) error { 64349- return notImplemented("WillSave") 64350-} 64351- 64352-func (s *Server) WillSaveWaitUntil(context.Context, *protocol.WillSaveTextDocumentParams) ([]protocol.TextEdit, error) { 64353- return nil, notImplemented("WillSaveWaitUntil") 64354-} 64355- 64356-func (s *Server) WorkDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error { 64357- return s.workDoneProgressCancel(ctx, params) 64358-} 64359diff -urN a/gopls/internal/lsp/server.go b/gopls/internal/lsp/server.go 64360--- a/gopls/internal/lsp/server.go 2000-01-01 00:00:00.000000000 -0000 64361+++ b/gopls/internal/lsp/server.go 1970-01-01 00:00:00.000000000 +0000 64362@@ -1,158 +0,0 @@ 64363-// Copyright 2018 The Go Authors. All rights reserved. 64364-// Use of this source code is governed by a BSD-style 64365-// license that can be found in the LICENSE file. 64366- 64367-//go:generate go run ./helper -d protocol/tsserver.go -o server_gen.go -u . 64368- 64369-// Package lsp implements LSP for gopls. 64370-package lsp 64371- 64372-import ( 64373- "context" 64374- "fmt" 64375- "sync" 64376- 64377- "golang.org/x/tools/gopls/internal/lsp/cache" 64378- "golang.org/x/tools/gopls/internal/lsp/progress" 64379- "golang.org/x/tools/gopls/internal/lsp/protocol" 64380- "golang.org/x/tools/gopls/internal/lsp/source" 64381- "golang.org/x/tools/gopls/internal/span" 64382- "golang.org/x/tools/internal/jsonrpc2" 64383-) 64384- 64385-const concurrentAnalyses = 1 64386- 64387-// NewServer creates an LSP server and binds it to handle incoming client 64388-// messages on on the supplied stream. 64389-func NewServer(session *cache.Session, client protocol.ClientCloser) *Server { 64390- return &Server{ 64391- diagnostics: map[span.URI]*fileReports{}, 64392- gcOptimizationDetails: make(map[source.PackageID]struct{}), 64393- watchedGlobPatterns: make(map[string]struct{}), 64394- changedFiles: make(map[span.URI]struct{}), 64395- session: session, 64396- client: client, 64397- diagnosticsSema: make(chan struct{}, concurrentAnalyses), 64398- progress: progress.NewTracker(client), 64399- diagDebouncer: newDebouncer(), 64400- } 64401-} 64402- 64403-type serverState int 64404- 64405-const ( 64406- serverCreated = serverState(iota) 64407- serverInitializing // set once the server has received "initialize" request 64408- serverInitialized // set once the server has received "initialized" request 64409- serverShutDown 64410-) 64411- 64412-func (s serverState) String() string { 64413- switch s { 64414- case serverCreated: 64415- return "created" 64416- case serverInitializing: 64417- return "initializing" 64418- case serverInitialized: 64419- return "initialized" 64420- case serverShutDown: 64421- return "shutDown" 64422- } 64423- return fmt.Sprintf("(unknown state: %d)", int(s)) 64424-} 64425- 64426-// Server implements the protocol.Server interface. 64427-type Server struct { 64428- client protocol.ClientCloser 64429- 64430- stateMu sync.Mutex 64431- state serverState 64432- // notifications generated before serverInitialized 64433- notifications []*protocol.ShowMessageParams 64434- 64435- session *cache.Session 64436- 64437- tempDir string 64438- 64439- // changedFiles tracks files for which there has been a textDocument/didChange. 64440- changedFilesMu sync.Mutex 64441- changedFiles map[span.URI]struct{} 64442- 64443- // folders is only valid between initialize and initialized, and holds the 64444- // set of folders to build views for when we are ready 64445- pendingFolders []protocol.WorkspaceFolder 64446- 64447- // watchedGlobPatterns is the set of glob patterns that we have requested 64448- // the client watch on disk. It will be updated as the set of directories 64449- // that the server should watch changes. 64450- watchedGlobPatternsMu sync.Mutex 64451- watchedGlobPatterns map[string]struct{} 64452- watchRegistrationCount int 64453- 64454- diagnosticsMu sync.Mutex 64455- diagnostics map[span.URI]*fileReports 64456- 64457- // gcOptimizationDetails describes the packages for which we want 64458- // optimization details to be included in the diagnostics. The key is the 64459- // ID of the package. 64460- gcOptimizationDetailsMu sync.Mutex 64461- gcOptimizationDetails map[source.PackageID]struct{} 64462- 64463- // diagnosticsSema limits the concurrency of diagnostics runs, which can be 64464- // expensive. 64465- diagnosticsSema chan struct{} 64466- 64467- progress *progress.Tracker 64468- 64469- // diagDebouncer is used for debouncing diagnostics. 64470- diagDebouncer *debouncer 64471- 64472- // When the workspace fails to load, we show its status through a progress 64473- // report with an error message. 64474- criticalErrorStatusMu sync.Mutex 64475- criticalErrorStatus *progress.WorkDone 64476-} 64477- 64478-func (s *Server) workDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error { 64479- return s.progress.Cancel(params.Token) 64480-} 64481- 64482-func (s *Server) nonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) { 64483- switch method { 64484- case "gopls/diagnoseFiles": 64485- paramMap := params.(map[string]interface{}) 64486- // TODO(adonovan): opt: parallelize FileDiagnostics(URI...), either 64487- // by calling it in multiple goroutines or, better, by making 64488- // the relevant APIs accept a set of URIs/packages. 64489- for _, file := range paramMap["files"].([]interface{}) { 64490- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, protocol.DocumentURI(file.(string)), source.UnknownKind) 64491- defer release() 64492- if !ok { 64493- return nil, err 64494- } 64495- 64496- fileID, diagnostics, err := source.FileDiagnostics(ctx, snapshot, fh.URI()) 64497- if err != nil { 64498- return nil, err 64499- } 64500- if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{ 64501- URI: protocol.URIFromSpanURI(fh.URI()), 64502- Diagnostics: toProtocolDiagnostics(diagnostics), 64503- Version: fileID.Version(), 64504- }); err != nil { 64505- return nil, err 64506- } 64507- } 64508- if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{ 64509- URI: "gopls://diagnostics-done", 64510- }); err != nil { 64511- return nil, err 64512- } 64513- return struct{}{}, nil 64514- } 64515- return nil, notImplemented(method) 64516-} 64517- 64518-func notImplemented(method string) error { 64519- return fmt.Errorf("%w: %q not yet implemented", jsonrpc2.ErrMethodNotFound, method) 64520-} 64521diff -urN a/gopls/internal/lsp/signature_help.go b/gopls/internal/lsp/signature_help.go 64522--- a/gopls/internal/lsp/signature_help.go 2000-01-01 00:00:00.000000000 -0000 64523+++ b/gopls/internal/lsp/signature_help.go 1970-01-01 00:00:00.000000000 +0000 64524@@ -1,31 +0,0 @@ 64525-// Copyright 2018 The Go Authors. All rights reserved. 64526-// Use of this source code is governed by a BSD-style 64527-// license that can be found in the LICENSE file. 64528- 64529-package lsp 64530- 64531-import ( 64532- "context" 64533- 64534- "golang.org/x/tools/gopls/internal/lsp/protocol" 64535- "golang.org/x/tools/gopls/internal/lsp/source" 64536- "golang.org/x/tools/internal/event" 64537- "golang.org/x/tools/internal/event/tag" 64538-) 64539- 64540-func (s *Server) signatureHelp(ctx context.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) { 64541- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) 64542- defer release() 64543- if !ok { 64544- return nil, err 64545- } 64546- info, activeParameter, err := source.SignatureHelp(ctx, snapshot, fh, params.Position) 64547- if err != nil { 64548- event.Error(ctx, "no signature help", err, tag.Position.Of(params.Position)) 64549- return nil, nil // sic? There could be many reasons for failure. 64550- } 64551- return &protocol.SignatureHelp{ 64552- Signatures: []protocol.SignatureInformation{*info}, 64553- ActiveParameter: uint32(activeParameter), 64554- }, nil 64555-} 64556diff -urN a/gopls/internal/lsp/snippet/snippet_builder.go b/gopls/internal/lsp/snippet/snippet_builder.go 64557--- a/gopls/internal/lsp/snippet/snippet_builder.go 2000-01-01 00:00:00.000000000 -0000 64558+++ b/gopls/internal/lsp/snippet/snippet_builder.go 1970-01-01 00:00:00.000000000 +0000 64559@@ -1,111 +0,0 @@ 64560-// Copyright 2019 The Go Authors. All rights reserved. 64561-// Use of this source code is governed by a BSD-style 64562-// license that can be found in the LICENSE file. 64563- 64564-// Package snippet implements the specification for the LSP snippet format. 64565-// 64566-// Snippets are "tab stop" templates returned as an optional attribute of LSP 64567-// completion candidates. As the user presses tab, they cycle through a series of 64568-// tab stops defined in the snippet. Each tab stop can optionally have placeholder 64569-// text, which can be pre-selected by editors. For a full description of syntax 64570-// and features, see "Snippet Syntax" at 64571-// https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_completion. 64572-// 64573-// A typical snippet looks like "foo(${1:i int}, ${2:s string})". 64574-package snippet 64575- 64576-import ( 64577- "fmt" 64578- "strings" 64579-) 64580- 64581-// A Builder is used to build an LSP snippet piecemeal. 64582-// The zero value is ready to use. Do not copy a non-zero Builder. 64583-type Builder struct { 64584- // currentTabStop is the index of the previous tab stop. The 64585- // next tab stop will be currentTabStop+1. 64586- currentTabStop int 64587- sb strings.Builder 64588-} 64589- 64590-// Escape characters defined in https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_completion under "Grammar". 64591-var replacer = strings.NewReplacer( 64592- `\`, `\\`, 64593- `}`, `\}`, 64594- `$`, `\$`, 64595-) 64596- 64597-func (b *Builder) WriteText(s string) { 64598- replacer.WriteString(&b.sb, s) 64599-} 64600- 64601-func (b *Builder) PrependText(s string) { 64602- rawSnip := b.String() 64603- b.sb.Reset() 64604- b.WriteText(s) 64605- b.sb.WriteString(rawSnip) 64606-} 64607- 64608-func (b *Builder) Write(data []byte) (int, error) { 64609- return b.sb.Write(data) 64610-} 64611- 64612-// WritePlaceholder writes a tab stop and placeholder value to the Builder. 64613-// The callback style allows for creating nested placeholders. To write an 64614-// empty tab stop, provide a nil callback. 64615-func (b *Builder) WritePlaceholder(fn func(*Builder)) { 64616- fmt.Fprintf(&b.sb, "${%d:", b.nextTabStop()) 64617- if fn != nil { 64618- fn(b) 64619- } 64620- b.sb.WriteByte('}') 64621-} 64622- 64623-// WriteFinalTabstop marks where cursor ends up after the user has 64624-// cycled through all the normal tab stops. It defaults to the 64625-// character after the snippet. 64626-func (b *Builder) WriteFinalTabstop() { 64627- fmt.Fprint(&b.sb, "$0") 64628-} 64629- 64630-// In addition to '\', '}', and '$', snippet choices also use '|' and ',' as 64631-// meta characters, so they must be escaped within the choices. 64632-var choiceReplacer = strings.NewReplacer( 64633- `\`, `\\`, 64634- `}`, `\}`, 64635- `$`, `\$`, 64636- `|`, `\|`, 64637- `,`, `\,`, 64638-) 64639- 64640-// WriteChoice writes a tab stop and list of text choices to the Builder. 64641-// The user's editor will prompt the user to choose one of the choices. 64642-func (b *Builder) WriteChoice(choices []string) { 64643- fmt.Fprintf(&b.sb, "${%d|", b.nextTabStop()) 64644- for i, c := range choices { 64645- if i != 0 { 64646- b.sb.WriteByte(',') 64647- } 64648- choiceReplacer.WriteString(&b.sb, c) 64649- } 64650- b.sb.WriteString("|}") 64651-} 64652- 64653-// String returns the built snippet string. 64654-func (b *Builder) String() string { 64655- return b.sb.String() 64656-} 64657- 64658-// Clone returns a copy of b. 64659-func (b *Builder) Clone() *Builder { 64660- var clone Builder 64661- clone.sb.WriteString(b.String()) 64662- return &clone 64663-} 64664- 64665-// nextTabStop returns the next tab stop index for a new placeholder. 64666-func (b *Builder) nextTabStop() int { 64667- // Tab stops start from 1, so increment before returning. 64668- b.currentTabStop++ 64669- return b.currentTabStop 64670-} 64671diff -urN a/gopls/internal/lsp/snippet/snippet_builder_test.go b/gopls/internal/lsp/snippet/snippet_builder_test.go 64672--- a/gopls/internal/lsp/snippet/snippet_builder_test.go 2000-01-01 00:00:00.000000000 -0000 64673+++ b/gopls/internal/lsp/snippet/snippet_builder_test.go 1970-01-01 00:00:00.000000000 +0000 64674@@ -1,62 +0,0 @@ 64675-// Copyright 2019 The Go Authors. All rights reserved. 64676-// Use of this source code is governed by a BSD-style 64677-// license that can be found in the LICENSE file. 64678- 64679-package snippet 64680- 64681-import ( 64682- "testing" 64683-) 64684- 64685-func TestSnippetBuilder(t *testing.T) { 64686- expect := func(expected string, fn func(*Builder)) { 64687- t.Helper() 64688- 64689- var b Builder 64690- fn(&b) 64691- if got := b.String(); got != expected { 64692- t.Errorf("got %q, expected %q", got, expected) 64693- } 64694- } 64695- 64696- expect("", func(b *Builder) {}) 64697- 64698- expect(`hi { \} \$ | " , / \\`, func(b *Builder) { 64699- b.WriteText(`hi { } $ | " , / \`) 64700- }) 64701- 64702- expect("${1:}", func(b *Builder) { 64703- b.WritePlaceholder(nil) 64704- }) 64705- 64706- expect("hi ${1:there}", func(b *Builder) { 64707- b.WriteText("hi ") 64708- b.WritePlaceholder(func(b *Builder) { 64709- b.WriteText("there") 64710- }) 64711- }) 64712- 64713- expect(`${1:id=${2:{your id\}}}`, func(b *Builder) { 64714- b.WritePlaceholder(func(b *Builder) { 64715- b.WriteText("id=") 64716- b.WritePlaceholder(func(b *Builder) { 64717- b.WriteText("{your id}") 64718- }) 64719- }) 64720- }) 64721- 64722- expect(`${1|one,{ \} \$ \| " \, / \\,three|}`, func(b *Builder) { 64723- b.WriteChoice([]string{"one", `{ } $ | " , / \`, "three"}) 64724- }) 64725- 64726- expect("$0 hello", func(b *Builder) { 64727- b.WriteFinalTabstop() 64728- b.WriteText(" hello") 64729- }) 64730- 64731- expect(`prepended \$5 ${1:} hello`, func(b *Builder) { 64732- b.WritePlaceholder(nil) 64733- b.WriteText(" hello") 64734- b.PrependText("prepended $5 ") 64735- }) 64736-} 64737diff -urN a/gopls/internal/lsp/source/add_import.go b/gopls/internal/lsp/source/add_import.go 64738--- a/gopls/internal/lsp/source/add_import.go 2000-01-01 00:00:00.000000000 -0000 64739+++ b/gopls/internal/lsp/source/add_import.go 1970-01-01 00:00:00.000000000 +0000 64740@@ -1,26 +0,0 @@ 64741-// Copyright 2020 The Go Authors. All rights reserved. 64742-// Use of this source code is governed by a BSD-style 64743-// license that can be found in the LICENSE file. 64744- 64745-package source 64746- 64747-import ( 64748- "context" 64749- 64750- "golang.org/x/tools/gopls/internal/lsp/protocol" 64751- "golang.org/x/tools/internal/imports" 64752-) 64753- 64754-// AddImport adds a single import statement to the given file 64755-func AddImport(ctx context.Context, snapshot Snapshot, fh FileHandle, importPath string) ([]protocol.TextEdit, error) { 64756- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 64757- if err != nil { 64758- return nil, err 64759- } 64760- return ComputeOneImportFixEdits(snapshot, pgf, &imports.ImportFix{ 64761- StmtInfo: imports.ImportInfo{ 64762- ImportPath: importPath, 64763- }, 64764- FixType: imports.AddImport, 64765- }) 64766-} 64767diff -urN a/gopls/internal/lsp/source/api_json.go b/gopls/internal/lsp/source/api_json.go 64768--- a/gopls/internal/lsp/source/api_json.go 2000-01-01 00:00:00.000000000 -0000 64769+++ b/gopls/internal/lsp/source/api_json.go 1970-01-01 00:00:00.000000000 +0000 64770@@ -1,1118 +0,0 @@ 64771-// Code generated by "golang.org/x/tools/gopls/doc/generate"; DO NOT EDIT. 64772- 64773-package source 64774- 64775-var GeneratedAPIJSON = &APIJSON{ 64776- Options: map[string][]*OptionJSON{ 64777- "User": { 64778- { 64779- Name: "buildFlags", 64780- Type: "[]string", 64781- Doc: "buildFlags is the set of flags passed on to the build system when invoked.\nIt is applied to queries like `go list`, which is used when discovering files.\nThe most common use is to set `-tags`.\n", 64782- Default: "[]", 64783- Hierarchy: "build", 64784- }, 64785- { 64786- Name: "env", 64787- Type: "map[string]string", 64788- Doc: "env adds environment variables to external commands run by `gopls`, most notably `go list`.\n", 64789- Default: "{}", 64790- Hierarchy: "build", 64791- }, 64792- { 64793- Name: "directoryFilters", 64794- Type: "[]string", 64795- Doc: "directoryFilters can be used to exclude unwanted directories from the\nworkspace. By default, all directories are included. Filters are an\noperator, `+` to include and `-` to exclude, followed by a path prefix\nrelative to the workspace folder. They are evaluated in order, and\nthe last filter that applies to a path controls whether it is included.\nThe path prefix can be empty, so an initial `-` excludes everything.\n\nDirectoryFilters also supports the `**` operator to match 0 or more directories.\n\nExamples:\n\nExclude node_modules at current depth: `-node_modules`\n\nExclude node_modules at any depth: `-**/node_modules`\n\nInclude only project_a: `-` (exclude everything), `+project_a`\n\nInclude only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules`\n", 64796- Default: "[\"-**/node_modules\"]", 64797- Hierarchy: "build", 64798- }, 64799- { 64800- Name: "templateExtensions", 64801- Type: "[]string", 64802- Doc: "templateExtensions gives the extensions of file names that are treateed\nas template files. (The extension\nis the part of the file name after the final dot.)\n", 64803- Default: "[]", 64804- Hierarchy: "build", 64805- }, 64806- { 64807- Name: "memoryMode", 64808- Type: "enum", 64809- Doc: "memoryMode controls the tradeoff `gopls` makes between memory usage and\ncorrectness.\n\nValues other than `Normal` are untested and may break in surprising ways.\n", 64810- EnumValues: []EnumValue{ 64811- { 64812- Value: "\"DegradeClosed\"", 64813- Doc: "`\"DegradeClosed\"`: In DegradeClosed mode, `gopls` will collect less information about\npackages without open files. As a result, features like Find\nReferences and Rename will miss results in such packages.\n", 64814- }, 64815- {Value: "\"Normal\""}, 64816- }, 64817- Default: "\"Normal\"", 64818- Status: "experimental", 64819- Hierarchy: "build", 64820- }, 64821- { 64822- Name: "expandWorkspaceToModule", 64823- Type: "bool", 64824- Doc: "expandWorkspaceToModule instructs `gopls` to adjust the scope of the\nworkspace to find the best available module root. `gopls` first looks for\na go.mod file in any parent directory of the workspace folder, expanding\nthe scope to that directory if it exists. If no viable parent directory is\nfound, gopls will check if there is exactly one child directory containing\na go.mod file, narrowing the scope to that directory if it exists.\n", 64825- Default: "true", 64826- Status: "experimental", 64827- Hierarchy: "build", 64828- }, 64829- { 64830- Name: "allowModfileModifications", 64831- Type: "bool", 64832- Doc: "allowModfileModifications disables -mod=readonly, allowing imports from\nout-of-scope modules. This option will eventually be removed.\n", 64833- Default: "false", 64834- Status: "experimental", 64835- Hierarchy: "build", 64836- }, 64837- { 64838- Name: "allowImplicitNetworkAccess", 64839- Type: "bool", 64840- Doc: "allowImplicitNetworkAccess disables GOPROXY=off, allowing implicit module\ndownloads rather than requiring user action. This option will eventually\nbe removed.\n", 64841- Default: "false", 64842- Status: "experimental", 64843- Hierarchy: "build", 64844- }, 64845- { 64846- Name: "standaloneTags", 64847- Type: "[]string", 64848- Doc: "standaloneTags specifies a set of build constraints that identify\nindividual Go source files that make up the entire main package of an\nexecutable.\n\nA common example of standalone main files is the convention of using the\ndirective `//go:build ignore` to denote files that are not intended to be\nincluded in any package, for example because they are invoked directly by\nthe developer using `go run`.\n\nGopls considers a file to be a standalone main file if and only if it has\npackage name \"main\" and has a build directive of the exact form\n\"//go:build tag\" or \"// +build tag\", where tag is among the list of tags\nconfigured by this setting. Notably, if the build constraint is more\ncomplicated than a simple tag (such as the composite constraint\n`//go:build tag && go1.18`), the file is not considered to be a standalone\nmain file.\n\nThis setting is only supported when gopls is built with Go 1.16 or later.\n", 64849- Default: "[\"ignore\"]", 64850- Hierarchy: "build", 64851- }, 64852- { 64853- Name: "hoverKind", 64854- Type: "enum", 64855- Doc: "hoverKind controls the information that appears in the hover text.\nSingleLine and Structured are intended for use only by authors of editor plugins.\n", 64856- EnumValues: []EnumValue{ 64857- {Value: "\"FullDocumentation\""}, 64858- {Value: "\"NoDocumentation\""}, 64859- {Value: "\"SingleLine\""}, 64860- { 64861- Value: "\"Structured\"", 64862- Doc: "`\"Structured\"` is an experimental setting that returns a structured hover format.\nThis format separates the signature from the documentation, so that the client\ncan do more manipulation of these fields.\n\nThis should only be used by clients that support this behavior.\n", 64863- }, 64864- {Value: "\"SynopsisDocumentation\""}, 64865- }, 64866- Default: "\"FullDocumentation\"", 64867- Hierarchy: "ui.documentation", 64868- }, 64869- { 64870- Name: "linkTarget", 64871- Type: "string", 64872- Doc: "linkTarget controls where documentation links go.\nIt might be one of:\n\n* `\"godoc.org\"`\n* `\"pkg.go.dev\"`\n\nIf company chooses to use its own `godoc.org`, its address can be used as well.\n\nModules matching the GOPRIVATE environment variable will not have\ndocumentation links in hover.\n", 64873- Default: "\"pkg.go.dev\"", 64874- Hierarchy: "ui.documentation", 64875- }, 64876- { 64877- Name: "linksInHover", 64878- Type: "bool", 64879- Doc: "linksInHover toggles the presence of links to documentation in hover.\n", 64880- Default: "true", 64881- Hierarchy: "ui.documentation", 64882- }, 64883- { 64884- Name: "usePlaceholders", 64885- Type: "bool", 64886- Doc: "placeholders enables placeholders for function parameters or struct\nfields in completion responses.\n", 64887- Default: "false", 64888- Hierarchy: "ui.completion", 64889- }, 64890- { 64891- Name: "completionBudget", 64892- Type: "time.Duration", 64893- Doc: "completionBudget is the soft latency goal for completion requests. Most\nrequests finish in a couple milliseconds, but in some cases deep\ncompletions can take much longer. As we use up our budget we\ndynamically reduce the search scope to ensure we return timely\nresults. Zero means unlimited.\n", 64894- Default: "\"100ms\"", 64895- Status: "debug", 64896- Hierarchy: "ui.completion", 64897- }, 64898- { 64899- Name: "matcher", 64900- Type: "enum", 64901- Doc: "matcher sets the algorithm that is used when calculating completion\ncandidates.\n", 64902- EnumValues: []EnumValue{ 64903- {Value: "\"CaseInsensitive\""}, 64904- {Value: "\"CaseSensitive\""}, 64905- {Value: "\"Fuzzy\""}, 64906- }, 64907- Default: "\"Fuzzy\"", 64908- Status: "advanced", 64909- Hierarchy: "ui.completion", 64910- }, 64911- { 64912- Name: "experimentalPostfixCompletions", 64913- Type: "bool", 64914- Doc: "experimentalPostfixCompletions enables artificial method snippets\nsuch as \"someSlice.sort!\".\n", 64915- Default: "true", 64916- Status: "experimental", 64917- Hierarchy: "ui.completion", 64918- }, 64919- { 64920- Name: "importShortcut", 64921- Type: "enum", 64922- Doc: "importShortcut specifies whether import statements should link to\ndocumentation or go to definitions.\n", 64923- EnumValues: []EnumValue{ 64924- {Value: "\"Both\""}, 64925- {Value: "\"Definition\""}, 64926- {Value: "\"Link\""}, 64927- }, 64928- Default: "\"Both\"", 64929- Hierarchy: "ui.navigation", 64930- }, 64931- { 64932- Name: "symbolMatcher", 64933- Type: "enum", 64934- Doc: "symbolMatcher sets the algorithm that is used when finding workspace symbols.\n", 64935- EnumValues: []EnumValue{ 64936- {Value: "\"CaseInsensitive\""}, 64937- {Value: "\"CaseSensitive\""}, 64938- {Value: "\"FastFuzzy\""}, 64939- {Value: "\"Fuzzy\""}, 64940- }, 64941- Default: "\"FastFuzzy\"", 64942- Status: "advanced", 64943- Hierarchy: "ui.navigation", 64944- }, 64945- { 64946- Name: "symbolStyle", 64947- Type: "enum", 64948- Doc: "symbolStyle controls how symbols are qualified in symbol responses.\n\nExample Usage:\n\n```json5\n\"gopls\": {\n...\n \"symbolStyle\": \"Dynamic\",\n...\n}\n```\n", 64949- EnumValues: []EnumValue{ 64950- { 64951- Value: "\"Dynamic\"", 64952- Doc: "`\"Dynamic\"` uses whichever qualifier results in the highest scoring\nmatch for the given symbol query. Here a \"qualifier\" is any \"/\" or \".\"\ndelimited suffix of the fully qualified symbol. i.e. \"to/pkg.Foo.Field\" or\njust \"Foo.Field\".\n", 64953- }, 64954- { 64955- Value: "\"Full\"", 64956- Doc: "`\"Full\"` is fully qualified symbols, i.e.\n\"path/to/pkg.Foo.Field\".\n", 64957- }, 64958- { 64959- Value: "\"Package\"", 64960- Doc: "`\"Package\"` is package qualified symbols i.e.\n\"pkg.Foo.Field\".\n", 64961- }, 64962- }, 64963- Default: "\"Dynamic\"", 64964- Status: "advanced", 64965- Hierarchy: "ui.navigation", 64966- }, 64967- { 64968- Name: "analyses", 64969- Type: "map[string]bool", 64970- Doc: "analyses specify analyses that the user would like to enable or disable.\nA map of the names of analysis passes that should be enabled/disabled.\nA full list of analyzers that gopls uses can be found in\n[analyzers.md](https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md).\n\nExample Usage:\n\n```json5\n...\n\"analyses\": {\n \"unreachable\": false, // Disable the unreachable analyzer.\n \"unusedparams\": true // Enable the unusedparams analyzer.\n}\n...\n```\n", 64971- EnumKeys: EnumKeys{ 64972- ValueType: "bool", 64973- Keys: []EnumKey{ 64974- { 64975- Name: "\"asmdecl\"", 64976- Doc: "report mismatches between assembly files and Go declarations", 64977- Default: "true", 64978- }, 64979- { 64980- Name: "\"assign\"", 64981- Doc: "check for useless assignments\n\nThis checker reports assignments of the form x = x or a[i] = a[i].\nThese are almost always useless, and even when they aren't they are\nusually a mistake.", 64982- Default: "true", 64983- }, 64984- { 64985- Name: "\"atomic\"", 64986- Doc: "check for common mistakes using the sync/atomic package\n\nThe atomic checker looks for assignment statements of the form:\n\n\tx = atomic.AddUint64(&x, 1)\n\nwhich are not atomic.", 64987- Default: "true", 64988- }, 64989- { 64990- Name: "\"atomicalign\"", 64991- Doc: "check for non-64-bits-aligned arguments to sync/atomic functions", 64992- Default: "true", 64993- }, 64994- { 64995- Name: "\"bools\"", 64996- Doc: "check for common mistakes involving boolean operators", 64997- Default: "true", 64998- }, 64999- { 65000- Name: "\"buildtag\"", 65001- Doc: "check //go:build and // +build directives", 65002- Default: "true", 65003- }, 65004- { 65005- Name: "\"cgocall\"", 65006- Doc: "detect some violations of the cgo pointer passing rules\n\nCheck for invalid cgo pointer passing.\nThis looks for code that uses cgo to call C code passing values\nwhose types are almost always invalid according to the cgo pointer\nsharing rules.\nSpecifically, it warns about attempts to pass a Go chan, map, func,\nor slice to C, either directly, or via a pointer, array, or struct.", 65007- Default: "true", 65008- }, 65009- { 65010- Name: "\"composites\"", 65011- Doc: "check for unkeyed composite literals\n\nThis analyzer reports a diagnostic for composite literals of struct\ntypes imported from another package that do not use the field-keyed\nsyntax. Such literals are fragile because the addition of a new field\n(even if unexported) to the struct will cause compilation to fail.\n\nAs an example,\n\n\terr = &net.DNSConfigError{err}\n\nshould be replaced by:\n\n\terr = &net.DNSConfigError{Err: err}\n", 65012- Default: "true", 65013- }, 65014- { 65015- Name: "\"copylocks\"", 65016- Doc: "check for locks erroneously passed by value\n\nInadvertently copying a value containing a lock, such as sync.Mutex or\nsync.WaitGroup, may cause both copies to malfunction. Generally such\nvalues should be referred to through a pointer.", 65017- Default: "true", 65018- }, 65019- { 65020- Name: "\"deepequalerrors\"", 65021- Doc: "check for calls of reflect.DeepEqual on error values\n\nThe deepequalerrors checker looks for calls of the form:\n\n reflect.DeepEqual(err1, err2)\n\nwhere err1 and err2 are errors. Using reflect.DeepEqual to compare\nerrors is discouraged.", 65022- Default: "true", 65023- }, 65024- { 65025- Name: "\"directive\"", 65026- Doc: "check Go toolchain directives such as //go:debug\n\nThis analyzer checks for problems with known Go toolchain directives\nin all Go source files in a package directory, even those excluded by\n//go:build constraints, and all non-Go source files too.\n\nFor //go:debug (see https://go.dev/doc/godebug), the analyzer checks\nthat the directives are placed only in Go source files, only above the\npackage comment, and only in package main or *_test.go files.\n\nSupport for other known directives may be added in the future.\n\nThis analyzer does not check //go:build, which is handled by the\nbuildtag analyzer.\n", 65027- Default: "true", 65028- }, 65029- { 65030- Name: "\"embed\"", 65031- Doc: "check for //go:embed directive import\n\nThis analyzer checks that the embed package is imported when source code contains //go:embed comment directives.\nThe embed package must be imported for //go:embed directives to function.import _ \"embed\".", 65032- Default: "true", 65033- }, 65034- { 65035- Name: "\"errorsas\"", 65036- Doc: "report passing non-pointer or non-error values to errors.As\n\nThe errorsas analysis reports calls to errors.As where the type\nof the second argument is not a pointer to a type implementing error.", 65037- Default: "true", 65038- }, 65039- { 65040- Name: "\"fieldalignment\"", 65041- Doc: "find structs that would use less memory if their fields were sorted\n\nThis analyzer find structs that can be rearranged to use less memory, and provides\na suggested edit with the most compact order.\n\nNote that there are two different diagnostics reported. One checks struct size,\nand the other reports \"pointer bytes\" used. Pointer bytes is how many bytes of the\nobject that the garbage collector has to potentially scan for pointers, for example:\n\n\tstruct { uint32; string }\n\nhave 16 pointer bytes because the garbage collector has to scan up through the string's\ninner pointer.\n\n\tstruct { string; *uint32 }\n\nhas 24 pointer bytes because it has to scan further through the *uint32.\n\n\tstruct { string; uint32 }\n\nhas 8 because it can stop immediately after the string pointer.\n\nBe aware that the most compact order is not always the most efficient.\nIn rare cases it may cause two variables each updated by its own goroutine\nto occupy the same CPU cache line, inducing a form of memory contention\nknown as \"false sharing\" that slows down both goroutines.\n", 65042- Default: "false", 65043- }, 65044- { 65045- Name: "\"httpresponse\"", 65046- Doc: "check for mistakes using HTTP responses\n\nA common mistake when using the net/http package is to defer a function\ncall to close the http.Response Body before checking the error that\ndetermines whether the response is valid:\n\n\tresp, err := http.Head(url)\n\tdefer resp.Body.Close()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// (defer statement belongs here)\n\nThis checker helps uncover latent nil dereference bugs by reporting a\ndiagnostic for such mistakes.", 65047- Default: "true", 65048- }, 65049- { 65050- Name: "\"ifaceassert\"", 65051- Doc: "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.\n", 65052- Default: "true", 65053- }, 65054- { 65055- Name: "\"infertypeargs\"", 65056- Doc: "check for unnecessary type arguments in call expressions\n\nExplicit type arguments may be omitted from call expressions if they can be\ninferred from function arguments, or from other type arguments:\n\n\tfunc f[T any](T) {}\n\t\n\tfunc _() {\n\t\tf[string](\"foo\") // string could be inferred\n\t}\n", 65057- Default: "true", 65058- }, 65059- { 65060- Name: "\"loopclosure\"", 65061- Doc: "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n for _, v := range list {\n defer func() {\n use(v) // incorrect\n }()\n }\n\nOne fix is to create a new variable for each iteration of the loop:\n\n for _, v := range list {\n v := v // new var per iteration\n defer func() {\n use(v) // ok\n }()\n }\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n for _, v := range elem {\n go func() {\n use(v) // incorrect, and a data race\n }()\n }\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n func Test(t *testing.T) {\n for _, test := range tests {\n t.Run(test.name, func(t *testing.T) {\n t.Parallel()\n use(test) // incorrect, and a data race\n })\n }\n }\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines", 65062- Default: "true", 65063- }, 65064- { 65065- Name: "\"lostcancel\"", 65066- Doc: "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nand WithDeadline must be called or the new context will remain live\nuntil its parent context is cancelled.\n(The background context is never cancelled.)", 65067- Default: "true", 65068- }, 65069- { 65070- Name: "\"nilfunc\"", 65071- Doc: "check for useless comparisons between functions and nil\n\nA useless comparison is one like f == nil as opposed to f() == nil.", 65072- Default: "true", 65073- }, 65074- { 65075- Name: "\"nilness\"", 65076- Doc: "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}\n", 65077- Default: "false", 65078- }, 65079- { 65080- Name: "\"printf\"", 65081- Doc: "check consistency of Printf format strings and arguments\n\nThe check applies to known functions (for example, those in package fmt)\nas well as any detected wrappers of known functions.\n\nA function that wants to avail itself of printf checking but is not\nfound by this analyzer's heuristics (for example, due to use of\ndynamic calls) can insert a bogus call:\n\n\tif false {\n\t\t_ = fmt.Sprintf(format, args...) // enable printf checking\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.\n", 65082- Default: "true", 65083- }, 65084- { 65085- Name: "\"shadow\"", 65086- Doc: "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}\n", 65087- Default: "false", 65088- }, 65089- { 65090- Name: "\"shift\"", 65091- Doc: "check for shifts that equal or exceed the width of the integer", 65092- Default: "true", 65093- }, 65094- { 65095- Name: "\"simplifycompositelit\"", 65096- Doc: "check for composite literal simplifications\n\nAn array, slice, or map composite literal of the form:\n\t[]T{T{}, T{}}\nwill be simplified to:\n\t[]T{{}, {}}\n\nThis is one of the simplifications that \"gofmt -s\" applies.", 65097- Default: "true", 65098- }, 65099- { 65100- Name: "\"simplifyrange\"", 65101- Doc: "check for range statement simplifications\n\nA range of the form:\n\tfor x, _ = range v {...}\nwill be simplified to:\n\tfor x = range v {...}\n\nA range of the form:\n\tfor _ = range v {...}\nwill be simplified to:\n\tfor range v {...}\n\nThis is one of the simplifications that \"gofmt -s\" applies.", 65102- Default: "true", 65103- }, 65104- { 65105- Name: "\"simplifyslice\"", 65106- Doc: "check for slice simplifications\n\nA slice expression of the form:\n\ts[a:len(s)]\nwill be simplified to:\n\ts[a:]\n\nThis is one of the simplifications that \"gofmt -s\" applies.", 65107- Default: "true", 65108- }, 65109- { 65110- Name: "\"sortslice\"", 65111- Doc: "check the argument type of sort.Slice\n\nsort.Slice requires an argument of a slice type. Check that\nthe interface{} value passed to sort.Slice is actually a slice.", 65112- Default: "true", 65113- }, 65114- { 65115- Name: "\"stdmethods\"", 65116- Doc: "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n func (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo\n", 65117- Default: "true", 65118- }, 65119- { 65120- Name: "\"stringintconv\"", 65121- Doc: "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.\n", 65122- Default: "true", 65123- }, 65124- { 65125- Name: "\"structtag\"", 65126- Doc: "check that struct field tags conform to reflect.StructTag.Get\n\nAlso report certain struct tags (json, xml) used with unexported fields.", 65127- Default: "true", 65128- }, 65129- { 65130- Name: "\"testinggoroutine\"", 65131- Doc: "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\nfunc TestFoo(t *testing.T) {\n go func() {\n t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n }()\n}\n", 65132- Default: "true", 65133- }, 65134- { 65135- Name: "\"tests\"", 65136- Doc: "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.", 65137- Default: "true", 65138- }, 65139- { 65140- Name: "\"timeformat\"", 65141- Doc: "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.\n", 65142- Default: "true", 65143- }, 65144- { 65145- Name: "\"unmarshal\"", 65146- Doc: "report passing non-pointer or non-interface values to unmarshal\n\nThe unmarshal analysis reports calls to functions such as json.Unmarshal\nin which the argument type is not a pointer or an interface.", 65147- Default: "true", 65148- }, 65149- { 65150- Name: "\"unreachable\"", 65151- Doc: "check for unreachable code\n\nThe unreachable analyzer finds statements that execution can never reach\nbecause they are preceded by an return statement, a call to panic, an\ninfinite loop, or similar constructs.", 65152- Default: "true", 65153- }, 65154- { 65155- Name: "\"unsafeptr\"", 65156- Doc: "check for invalid conversions of uintptr to unsafe.Pointer\n\nThe unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer\nto convert integers to pointers. A conversion from uintptr to\nunsafe.Pointer is invalid if it implies that there is a uintptr-typed\nword in memory that holds a pointer value, because that word will be\ninvisible to stack copying and to the garbage collector.", 65157- Default: "true", 65158- }, 65159- { 65160- Name: "\"unusedparams\"", 65161- Doc: "check for unused parameters of functions\n\nThe unusedparams analyzer checks functions to see if there are\nany parameters that are not being used.\n\nTo reduce false positives it ignores:\n- methods\n- parameters that do not have a name or are underscored\n- functions in test files\n- functions with empty bodies or those with just a return stmt", 65162- Default: "false", 65163- }, 65164- { 65165- Name: "\"unusedresult\"", 65166- Doc: "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side effects,\nso it is always a mistake to discard the result. This analyzer reports\ncalls to certain functions in which the result of the call is ignored.\n\nThe set of functions may be controlled using flags.", 65167- Default: "true", 65168- }, 65169- { 65170- Name: "\"unusedwrite\"", 65171- Doc: "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\tfunc f(input []T) {\n\t\tfor i, v := range input { // v is a copy\n\t\t\tv.x = i // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\tfunc (t T) f() { // t is a copy\n\t\tt.x = i // unused write to field x\n\t}\n", 65172- Default: "false", 65173- }, 65174- { 65175- Name: "\"useany\"", 65176- Doc: "check for constraints that could be simplified to \"any\"", 65177- Default: "false", 65178- }, 65179- { 65180- Name: "\"fillreturns\"", 65181- Doc: "suggest fixes for errors due to an incorrect number of return values\n\nThis checker provides suggested fixes for type errors of the\ntype \"wrong number of return values (want %d, got %d)\". For example:\n\tfunc m() (int, string, *bool, error) {\n\t\treturn\n\t}\nwill turn into\n\tfunc m() (int, string, *bool, error) {\n\t\treturn 0, \"\", nil, nil\n\t}\n\nThis functionality is similar to https://github.com/sqs/goreturns.\n", 65182- Default: "true", 65183- }, 65184- { 65185- Name: "\"nonewvars\"", 65186- Doc: "suggested fixes for \"no new vars on left side of :=\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"no new vars on left side of :=\". For example:\n\tz := 1\n\tz := 2\nwill turn into\n\tz := 1\n\tz = 2\n", 65187- Default: "true", 65188- }, 65189- { 65190- Name: "\"noresultvalues\"", 65191- Doc: "suggested fixes for unexpected return values\n\nThis checker provides suggested fixes for type errors of the\ntype \"no result values expected\" or \"too many return values\".\nFor example:\n\tfunc z() { return nil }\nwill turn into\n\tfunc z() { return }\n", 65192- Default: "true", 65193- }, 65194- { 65195- Name: "\"undeclaredname\"", 65196- Doc: "suggested fixes for \"undeclared name: <>\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"undeclared name: <>\". It will either insert a new statement,\nsuch as:\n\n\"<> := \"\n\nor a new function declaration, such as:\n\nfunc <>(inferred parameters) {\n\tpanic(\"implement me!\")\n}\n", 65197- Default: "true", 65198- }, 65199- { 65200- Name: "\"unusedvariable\"", 65201- Doc: "check for unused variables\n\nThe unusedvariable analyzer suggests fixes for unused variables errors.\n", 65202- Default: "false", 65203- }, 65204- { 65205- Name: "\"fillstruct\"", 65206- Doc: "note incomplete struct initializations\n\nThis analyzer provides diagnostics for any struct literals that do not have\nany fields initialized. Because the suggested fix for this analysis is\nexpensive to compute, callers should compute it separately, using the\nSuggestedFix function below.\n", 65207- Default: "true", 65208- }, 65209- { 65210- Name: "\"stubmethods\"", 65211- Doc: "stub methods analyzer\n\nThis analyzer generates method stubs for concrete types\nin order to implement a target interface", 65212- Default: "true", 65213- }, 65214- }, 65215- }, 65216- Default: "{}", 65217- Hierarchy: "ui.diagnostic", 65218- }, 65219- { 65220- Name: "staticcheck", 65221- Type: "bool", 65222- Doc: "staticcheck enables additional analyses from staticcheck.io.\nThese analyses are documented on\n[Staticcheck's website](https://staticcheck.io/docs/checks/).\n", 65223- Default: "false", 65224- Status: "experimental", 65225- Hierarchy: "ui.diagnostic", 65226- }, 65227- { 65228- Name: "annotations", 65229- Type: "map[string]bool", 65230- Doc: "annotations specifies the various kinds of optimization diagnostics\nthat should be reported by the gc_details command.\n", 65231- EnumKeys: EnumKeys{ 65232- ValueType: "bool", 65233- Keys: []EnumKey{ 65234- { 65235- Name: "\"bounds\"", 65236- Doc: "`\"bounds\"` controls bounds checking diagnostics.\n", 65237- Default: "true", 65238- }, 65239- { 65240- Name: "\"escape\"", 65241- Doc: "`\"escape\"` controls diagnostics about escape choices.\n", 65242- Default: "true", 65243- }, 65244- { 65245- Name: "\"inline\"", 65246- Doc: "`\"inline\"` controls diagnostics about inlining choices.\n", 65247- Default: "true", 65248- }, 65249- { 65250- Name: "\"nil\"", 65251- Doc: "`\"nil\"` controls nil checks.\n", 65252- Default: "true", 65253- }, 65254- }, 65255- }, 65256- Default: "{\"bounds\":true,\"escape\":true,\"inline\":true,\"nil\":true}", 65257- Status: "experimental", 65258- Hierarchy: "ui.diagnostic", 65259- }, 65260- { 65261- Name: "vulncheck", 65262- Type: "enum", 65263- Doc: "vulncheck enables vulnerability scanning.\n", 65264- EnumValues: []EnumValue{ 65265- { 65266- Value: "\"Imports\"", 65267- Doc: "`\"Imports\"`: In Imports mode, `gopls` will report vulnerabilities that affect packages\ndirectly and indirectly used by the analyzed main module.\n", 65268- }, 65269- { 65270- Value: "\"Off\"", 65271- Doc: "`\"Off\"`: Disable vulnerability analysis.\n", 65272- }, 65273- }, 65274- Default: "\"Off\"", 65275- Status: "experimental", 65276- Hierarchy: "ui.diagnostic", 65277- }, 65278- { 65279- Name: "diagnosticsDelay", 65280- Type: "time.Duration", 65281- Doc: "diagnosticsDelay controls the amount of time that gopls waits\nafter the most recent file modification before computing deep diagnostics.\nSimple diagnostics (parsing and type-checking) are always run immediately\non recently modified packages.\n\nThis option must be set to a valid duration string, for example `\"250ms\"`.\n", 65282- Default: "\"250ms\"", 65283- Status: "advanced", 65284- Hierarchy: "ui.diagnostic", 65285- }, 65286- { 65287- Name: "hints", 65288- Type: "map[string]bool", 65289- Doc: "hints specify inlay hints that users want to see. A full list of hints\nthat gopls uses can be found in\n[inlayHints.md](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md).\n", 65290- EnumKeys: EnumKeys{Keys: []EnumKey{ 65291- { 65292- Name: "\"assignVariableTypes\"", 65293- Doc: "Enable/disable inlay hints for variable types in assign statements:\n```go\n\ti/* int*/, j/* int*/ := 0, len(r)-1\n```", 65294- Default: "false", 65295- }, 65296- { 65297- Name: "\"compositeLiteralFields\"", 65298- Doc: "Enable/disable inlay hints for composite literal field names:\n```go\n\t{/*in: */\"Hello, world\", /*want: */\"dlrow ,olleH\"}\n```", 65299- Default: "false", 65300- }, 65301- { 65302- Name: "\"compositeLiteralTypes\"", 65303- Doc: "Enable/disable inlay hints for composite literal types:\n```go\n\tfor _, c := range []struct {\n\t\tin, want string\n\t}{\n\t\t/*struct{ in string; want string }*/{\"Hello, world\", \"dlrow ,olleH\"},\n\t}\n```", 65304- Default: "false", 65305- }, 65306- { 65307- Name: "\"constantValues\"", 65308- Doc: "Enable/disable inlay hints for constant values:\n```go\n\tconst (\n\t\tKindNone Kind = iota/* = 0*/\n\t\tKindPrint/* = 1*/\n\t\tKindPrintf/* = 2*/\n\t\tKindErrorf/* = 3*/\n\t)\n```", 65309- Default: "false", 65310- }, 65311- { 65312- Name: "\"functionTypeParameters\"", 65313- Doc: "Enable/disable inlay hints for implicit type parameters on generic functions:\n```go\n\tmyFoo/*[int, string]*/(1, \"hello\")\n```", 65314- Default: "false", 65315- }, 65316- { 65317- Name: "\"parameterNames\"", 65318- Doc: "Enable/disable inlay hints for parameter names:\n```go\n\tparseInt(/* str: */ \"123\", /* radix: */ 8)\n```", 65319- Default: "false", 65320- }, 65321- { 65322- Name: "\"rangeVariableTypes\"", 65323- Doc: "Enable/disable inlay hints for variable types in range statements:\n```go\n\tfor k/* int*/, v/* string*/ := range []string{} {\n\t\tfmt.Println(k, v)\n\t}\n```", 65324- Default: "false", 65325- }, 65326- }}, 65327- Default: "{}", 65328- Status: "experimental", 65329- Hierarchy: "ui.inlayhint", 65330- }, 65331- { 65332- Name: "codelenses", 65333- Type: "map[string]bool", 65334- Doc: "codelenses overrides the enabled/disabled state of code lenses. See the\n\"Code Lenses\" section of the\n[Settings page](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#code-lenses)\nfor the list of supported lenses.\n\nExample Usage:\n\n```json5\n\"gopls\": {\n...\n \"codelenses\": {\n \"generate\": false, // Don't show the `go generate` lens.\n \"gc_details\": true // Show a code lens toggling the display of gc's choices.\n }\n...\n}\n```\n", 65335- EnumKeys: EnumKeys{ 65336- ValueType: "bool", 65337- Keys: []EnumKey{ 65338- { 65339- Name: "\"gc_details\"", 65340- Doc: "Toggle the calculation of gc annotations.", 65341- Default: "false", 65342- }, 65343- { 65344- Name: "\"generate\"", 65345- Doc: "Runs `go generate` for a given directory.", 65346- Default: "true", 65347- }, 65348- { 65349- Name: "\"regenerate_cgo\"", 65350- Doc: "Regenerates cgo definitions.", 65351- Default: "true", 65352- }, 65353- { 65354- Name: "\"run_govulncheck\"", 65355- Doc: "Run vulnerability check (`govulncheck`).", 65356- Default: "false", 65357- }, 65358- { 65359- Name: "\"test\"", 65360- Doc: "Runs `go test` for a specific set of test or benchmark functions.", 65361- Default: "false", 65362- }, 65363- { 65364- Name: "\"tidy\"", 65365- Doc: "Runs `go mod tidy` for a module.", 65366- Default: "true", 65367- }, 65368- { 65369- Name: "\"upgrade_dependency\"", 65370- Doc: "Upgrades a dependency in the go.mod file for a module.", 65371- Default: "true", 65372- }, 65373- { 65374- Name: "\"vendor\"", 65375- Doc: "Runs `go mod vendor` for a module.", 65376- Default: "true", 65377- }, 65378- }, 65379- }, 65380- Default: "{\"gc_details\":false,\"generate\":true,\"regenerate_cgo\":true,\"tidy\":true,\"upgrade_dependency\":true,\"vendor\":true}", 65381- Hierarchy: "ui", 65382- }, 65383- { 65384- Name: "semanticTokens", 65385- Type: "bool", 65386- Doc: "semanticTokens controls whether the LSP server will send\nsemantic tokens to the client.\n", 65387- Default: "false", 65388- Status: "experimental", 65389- Hierarchy: "ui", 65390- }, 65391- { 65392- Name: "noSemanticString", 65393- Type: "bool", 65394- Doc: "noSemanticString turns off the sending of the semantic token 'string'\n", 65395- Default: "false", 65396- Status: "experimental", 65397- Hierarchy: "ui", 65398- }, 65399- { 65400- Name: "noSemanticNumber", 65401- Type: "bool", 65402- Doc: "noSemanticNumber turns off the sending of the semantic token 'number'\n", 65403- Default: "false", 65404- Status: "experimental", 65405- Hierarchy: "ui", 65406- }, 65407- { 65408- Name: "local", 65409- Type: "string", 65410- Doc: "local is the equivalent of the `goimports -local` flag, which puts\nimports beginning with this string after third-party packages. It should\nbe the prefix of the import path whose imports should be grouped\nseparately.\n", 65411- Default: "\"\"", 65412- Hierarchy: "formatting", 65413- }, 65414- { 65415- Name: "gofumpt", 65416- Type: "bool", 65417- Doc: "gofumpt indicates if we should run gofumpt formatting.\n", 65418- Default: "false", 65419- Hierarchy: "formatting", 65420- }, 65421- { 65422- Name: "verboseOutput", 65423- Type: "bool", 65424- Doc: "verboseOutput enables additional debug logging.\n", 65425- Default: "false", 65426- Status: "debug", 65427- }, 65428- }, 65429- }, 65430- Commands: []*CommandJSON{ 65431- { 65432- Command: "gopls.add_dependency", 65433- Title: "Add a dependency", 65434- Doc: "Adds a dependency to the go.mod file for a module.", 65435- ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// Additional args to pass to the go command.\n\t\"GoCmdArgs\": []string,\n\t// Whether to add a require directive.\n\t\"AddRequire\": bool,\n}", 65436- }, 65437- { 65438- Command: "gopls.add_import", 65439- Title: "Add an import", 65440- Doc: "Ask the server to add an import path to a given Go file. The method will\ncall applyEdit on the client so that clients don't have to apply the edit\nthemselves.", 65441- ArgDoc: "{\n\t// ImportPath is the target import path that should\n\t// be added to the URI file\n\t\"ImportPath\": string,\n\t// URI is the file that the ImportPath should be\n\t// added to\n\t\"URI\": string,\n}", 65442- }, 65443- { 65444- Command: "gopls.apply_fix", 65445- Title: "Apply a fix", 65446- Doc: "Applies a fix to a region of source code.", 65447- ArgDoc: "{\n\t// The fix to apply.\n\t\"Fix\": string,\n\t// The file URI for the document to fix.\n\t\"URI\": string,\n\t// The document range to scan for fixes.\n\t\"Range\": {\n\t\t\"start\": {\n\t\t\t\"line\": uint32,\n\t\t\t\"character\": uint32,\n\t\t},\n\t\t\"end\": {\n\t\t\t\"line\": uint32,\n\t\t\t\"character\": uint32,\n\t\t},\n\t},\n}", 65448- }, 65449- { 65450- Command: "gopls.check_upgrades", 65451- Title: "Check for upgrades", 65452- Doc: "Checks for module upgrades.", 65453- ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The modules to check.\n\t\"Modules\": []string,\n}", 65454- }, 65455- { 65456- Command: "gopls.edit_go_directive", 65457- Title: "Run go mod edit -go=version", 65458- Doc: "Runs `go mod edit -go=version` for a module.", 65459- ArgDoc: "{\n\t// Any document URI within the relevant module.\n\t\"URI\": string,\n\t// The version to pass to `go mod edit -go`.\n\t\"Version\": string,\n}", 65460- }, 65461- { 65462- Command: "gopls.fetch_vulncheck_result", 65463- Title: "Get known vulncheck result", 65464- Doc: "Fetch the result of latest vulnerability check (`govulncheck`).", 65465- ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}", 65466- ResultDoc: "map[golang.org/x/tools/gopls/internal/lsp/protocol.DocumentURI]*golang.org/x/tools/gopls/internal/govulncheck.Result", 65467- }, 65468- { 65469- Command: "gopls.gc_details", 65470- Title: "Toggle gc_details", 65471- Doc: "Toggle the calculation of gc annotations.", 65472- ArgDoc: "string", 65473- }, 65474- { 65475- Command: "gopls.generate", 65476- Title: "Run go generate", 65477- Doc: "Runs `go generate` for a given directory.", 65478- ArgDoc: "{\n\t// URI for the directory to generate.\n\t\"Dir\": string,\n\t// Whether to generate recursively (go generate ./...)\n\t\"Recursive\": bool,\n}", 65479- }, 65480- { 65481- Command: "gopls.go_get_package", 65482- Title: "go get a package", 65483- Doc: "Runs `go get` to fetch a package.", 65484- ArgDoc: "{\n\t// Any document URI within the relevant module.\n\t\"URI\": string,\n\t// The package to go get.\n\t\"Pkg\": string,\n\t\"AddRequire\": bool,\n}", 65485- }, 65486- { 65487- Command: "gopls.list_imports", 65488- Title: "List imports of a file and its package", 65489- Doc: "Retrieve a list of imports in the given Go file, and the package it\nbelongs to.", 65490- ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}", 65491- ResultDoc: "{\n\t// Imports is a list of imports in the requested file.\n\t\"Imports\": []{\n\t\t\"Path\": string,\n\t\t\"Name\": string,\n\t},\n\t// PackageImports is a list of all imports in the requested file's package.\n\t\"PackageImports\": []{\n\t\t\"Path\": string,\n\t},\n}", 65492- }, 65493- { 65494- Command: "gopls.list_known_packages", 65495- Title: "List known packages", 65496- Doc: "Retrieve a list of packages that are importable from the given URI.", 65497- ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}", 65498- ResultDoc: "{\n\t// Packages is a list of packages relative\n\t// to the URIArg passed by the command request.\n\t// In other words, it omits paths that are already\n\t// imported or cannot be imported due to compiler\n\t// restrictions.\n\t\"Packages\": []string,\n}", 65499- }, 65500- { 65501- Command: "gopls.mem_stats", 65502- Title: "fetch memory statistics", 65503- Doc: "Call runtime.GC multiple times and return memory statistics as reported by\nruntime.MemStats.\n\nThis command is used for benchmarking, and may change in the future.", 65504- ResultDoc: "{\n\t\"HeapAlloc\": uint64,\n\t\"HeapInUse\": uint64,\n}", 65505- }, 65506- { 65507- Command: "gopls.regenerate_cgo", 65508- Title: "Regenerate cgo", 65509- Doc: "Regenerates cgo definitions.", 65510- ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}", 65511- }, 65512- { 65513- Command: "gopls.remove_dependency", 65514- Title: "Remove a dependency", 65515- Doc: "Removes a dependency from the go.mod file of a module.", 65516- ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The module path to remove.\n\t\"ModulePath\": string,\n\t\"OnlyDiagnostic\": bool,\n}", 65517- }, 65518- { 65519- Command: "gopls.reset_go_mod_diagnostics", 65520- Title: "Reset go.mod diagnostics", 65521- Doc: "Reset diagnostics in the go.mod file of a module.", 65522- ArgDoc: "{\n\t\"URIArg\": {\n\t\t\"URI\": string,\n\t},\n\t// Optional: source of the diagnostics to reset.\n\t// If not set, all resettable go.mod diagnostics will be cleared.\n\t\"DiagnosticSource\": string,\n}", 65523- }, 65524- { 65525- Command: "gopls.run_govulncheck", 65526- Title: "Run govulncheck.", 65527- Doc: "Run vulnerability check (`govulncheck`).", 65528- ArgDoc: "{\n\t// Any document in the directory from which govulncheck will run.\n\t\"URI\": string,\n\t// Package pattern. E.g. \"\", \".\", \"./...\".\n\t\"Pattern\": string,\n}", 65529- ResultDoc: "{\n\t// Token holds the progress token for LSP workDone reporting of the vulncheck\n\t// invocation.\n\t\"Token\": interface{},\n}", 65530- }, 65531- { 65532- Command: "gopls.run_tests", 65533- Title: "Run test(s)", 65534- Doc: "Runs `go test` for a specific set of test or benchmark functions.", 65535- ArgDoc: "{\n\t// The test file containing the tests to run.\n\t\"URI\": string,\n\t// Specific test names to run, e.g. TestFoo.\n\t\"Tests\": []string,\n\t// Specific benchmarks to run, e.g. BenchmarkFoo.\n\t\"Benchmarks\": []string,\n}", 65536- }, 65537- { 65538- Command: "gopls.start_debugging", 65539- Title: "Start the gopls debug server", 65540- Doc: "Start the gopls debug server if it isn't running, and return the debug\naddress.", 65541- ArgDoc: "{\n\t// Optional: the address (including port) for the debug server to listen on.\n\t// If not provided, the debug server will bind to \"localhost:0\", and the\n\t// full debug URL will be contained in the result.\n\t// \n\t// If there is more than one gopls instance along the serving path (i.e. you\n\t// are using a daemon), each gopls instance will attempt to start debugging.\n\t// If Addr specifies a port, only the daemon will be able to bind to that\n\t// port, and each intermediate gopls instance will fail to start debugging.\n\t// For this reason it is recommended not to specify a port (or equivalently,\n\t// to specify \":0\").\n\t// \n\t// If the server was already debugging this field has no effect, and the\n\t// result will contain the previously configured debug URL(s).\n\t\"Addr\": string,\n}", 65542- ResultDoc: "{\n\t// The URLs to use to access the debug servers, for all gopls instances in\n\t// the serving path. For the common case of a single gopls instance (i.e. no\n\t// daemon), this will be exactly one address.\n\t// \n\t// In the case of one or more gopls instances forwarding the LSP to a daemon,\n\t// URLs will contain debug addresses for each server in the serving path, in\n\t// serving order. The daemon debug address will be the last entry in the\n\t// slice. If any intermediate gopls instance fails to start debugging, no\n\t// error will be returned but the debug URL for that server in the URLs slice\n\t// will be empty.\n\t\"URLs\": []string,\n}", 65543- }, 65544- { 65545- Command: "gopls.test", 65546- Title: "Run test(s) (legacy)", 65547- Doc: "Runs `go test` for a specific set of test or benchmark functions.", 65548- ArgDoc: "string,\n[]string,\n[]string", 65549- }, 65550- { 65551- Command: "gopls.tidy", 65552- Title: "Run go mod tidy", 65553- Doc: "Runs `go mod tidy` for a module.", 65554- ArgDoc: "{\n\t// The file URIs.\n\t\"URIs\": []string,\n}", 65555- }, 65556- { 65557- Command: "gopls.toggle_gc_details", 65558- Title: "Toggle gc_details", 65559- Doc: "Toggle the calculation of gc annotations.", 65560- ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}", 65561- }, 65562- { 65563- Command: "gopls.update_go_sum", 65564- Title: "Update go.sum", 65565- Doc: "Updates the go.sum file for a module.", 65566- ArgDoc: "{\n\t// The file URIs.\n\t\"URIs\": []string,\n}", 65567- }, 65568- { 65569- Command: "gopls.upgrade_dependency", 65570- Title: "Upgrade a dependency", 65571- Doc: "Upgrades a dependency in the go.mod file for a module.", 65572- ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// Additional args to pass to the go command.\n\t\"GoCmdArgs\": []string,\n\t// Whether to add a require directive.\n\t\"AddRequire\": bool,\n}", 65573- }, 65574- { 65575- Command: "gopls.vendor", 65576- Title: "Run go mod vendor", 65577- Doc: "Runs `go mod vendor` for a module.", 65578- ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}", 65579- }, 65580- }, 65581- Lenses: []*LensJSON{ 65582- { 65583- Lens: "gc_details", 65584- Title: "Toggle gc_details", 65585- Doc: "Toggle the calculation of gc annotations.", 65586- }, 65587- { 65588- Lens: "generate", 65589- Title: "Run go generate", 65590- Doc: "Runs `go generate` for a given directory.", 65591- }, 65592- { 65593- Lens: "regenerate_cgo", 65594- Title: "Regenerate cgo", 65595- Doc: "Regenerates cgo definitions.", 65596- }, 65597- { 65598- Lens: "run_govulncheck", 65599- Title: "Run govulncheck.", 65600- Doc: "Run vulnerability check (`govulncheck`).", 65601- }, 65602- { 65603- Lens: "test", 65604- Title: "Run test(s) (legacy)", 65605- Doc: "Runs `go test` for a specific set of test or benchmark functions.", 65606- }, 65607- { 65608- Lens: "tidy", 65609- Title: "Run go mod tidy", 65610- Doc: "Runs `go mod tidy` for a module.", 65611- }, 65612- { 65613- Lens: "upgrade_dependency", 65614- Title: "Upgrade a dependency", 65615- Doc: "Upgrades a dependency in the go.mod file for a module.", 65616- }, 65617- { 65618- Lens: "vendor", 65619- Title: "Run go mod vendor", 65620- Doc: "Runs `go mod vendor` for a module.", 65621- }, 65622- }, 65623- Analyzers: []*AnalyzerJSON{ 65624- { 65625- Name: "asmdecl", 65626- Doc: "report mismatches between assembly files and Go declarations", 65627- Default: true, 65628- }, 65629- { 65630- Name: "assign", 65631- Doc: "check for useless assignments\n\nThis checker reports assignments of the form x = x or a[i] = a[i].\nThese are almost always useless, and even when they aren't they are\nusually a mistake.", 65632- Default: true, 65633- }, 65634- { 65635- Name: "atomic", 65636- Doc: "check for common mistakes using the sync/atomic package\n\nThe atomic checker looks for assignment statements of the form:\n\n\tx = atomic.AddUint64(&x, 1)\n\nwhich are not atomic.", 65637- Default: true, 65638- }, 65639- { 65640- Name: "atomicalign", 65641- Doc: "check for non-64-bits-aligned arguments to sync/atomic functions", 65642- Default: true, 65643- }, 65644- { 65645- Name: "bools", 65646- Doc: "check for common mistakes involving boolean operators", 65647- Default: true, 65648- }, 65649- { 65650- Name: "buildtag", 65651- Doc: "check //go:build and // +build directives", 65652- Default: true, 65653- }, 65654- { 65655- Name: "cgocall", 65656- Doc: "detect some violations of the cgo pointer passing rules\n\nCheck for invalid cgo pointer passing.\nThis looks for code that uses cgo to call C code passing values\nwhose types are almost always invalid according to the cgo pointer\nsharing rules.\nSpecifically, it warns about attempts to pass a Go chan, map, func,\nor slice to C, either directly, or via a pointer, array, or struct.", 65657- Default: true, 65658- }, 65659- { 65660- Name: "composites", 65661- Doc: "check for unkeyed composite literals\n\nThis analyzer reports a diagnostic for composite literals of struct\ntypes imported from another package that do not use the field-keyed\nsyntax. Such literals are fragile because the addition of a new field\n(even if unexported) to the struct will cause compilation to fail.\n\nAs an example,\n\n\terr = &net.DNSConfigError{err}\n\nshould be replaced by:\n\n\terr = &net.DNSConfigError{Err: err}\n", 65662- Default: true, 65663- }, 65664- { 65665- Name: "copylocks", 65666- Doc: "check for locks erroneously passed by value\n\nInadvertently copying a value containing a lock, such as sync.Mutex or\nsync.WaitGroup, may cause both copies to malfunction. Generally such\nvalues should be referred to through a pointer.", 65667- Default: true, 65668- }, 65669- { 65670- Name: "deepequalerrors", 65671- Doc: "check for calls of reflect.DeepEqual on error values\n\nThe deepequalerrors checker looks for calls of the form:\n\n reflect.DeepEqual(err1, err2)\n\nwhere err1 and err2 are errors. Using reflect.DeepEqual to compare\nerrors is discouraged.", 65672- Default: true, 65673- }, 65674- { 65675- Name: "directive", 65676- Doc: "check Go toolchain directives such as //go:debug\n\nThis analyzer checks for problems with known Go toolchain directives\nin all Go source files in a package directory, even those excluded by\n//go:build constraints, and all non-Go source files too.\n\nFor //go:debug (see https://go.dev/doc/godebug), the analyzer checks\nthat the directives are placed only in Go source files, only above the\npackage comment, and only in package main or *_test.go files.\n\nSupport for other known directives may be added in the future.\n\nThis analyzer does not check //go:build, which is handled by the\nbuildtag analyzer.\n", 65677- Default: true, 65678- }, 65679- { 65680- Name: "embed", 65681- Doc: "check for //go:embed directive import\n\nThis analyzer checks that the embed package is imported when source code contains //go:embed comment directives.\nThe embed package must be imported for //go:embed directives to function.import _ \"embed\".", 65682- Default: true, 65683- }, 65684- { 65685- Name: "errorsas", 65686- Doc: "report passing non-pointer or non-error values to errors.As\n\nThe errorsas analysis reports calls to errors.As where the type\nof the second argument is not a pointer to a type implementing error.", 65687- Default: true, 65688- }, 65689- { 65690- Name: "fieldalignment", 65691- Doc: "find structs that would use less memory if their fields were sorted\n\nThis analyzer find structs that can be rearranged to use less memory, and provides\na suggested edit with the most compact order.\n\nNote that there are two different diagnostics reported. One checks struct size,\nand the other reports \"pointer bytes\" used. Pointer bytes is how many bytes of the\nobject that the garbage collector has to potentially scan for pointers, for example:\n\n\tstruct { uint32; string }\n\nhave 16 pointer bytes because the garbage collector has to scan up through the string's\ninner pointer.\n\n\tstruct { string; *uint32 }\n\nhas 24 pointer bytes because it has to scan further through the *uint32.\n\n\tstruct { string; uint32 }\n\nhas 8 because it can stop immediately after the string pointer.\n\nBe aware that the most compact order is not always the most efficient.\nIn rare cases it may cause two variables each updated by its own goroutine\nto occupy the same CPU cache line, inducing a form of memory contention\nknown as \"false sharing\" that slows down both goroutines.\n", 65692- }, 65693- { 65694- Name: "httpresponse", 65695- Doc: "check for mistakes using HTTP responses\n\nA common mistake when using the net/http package is to defer a function\ncall to close the http.Response Body before checking the error that\ndetermines whether the response is valid:\n\n\tresp, err := http.Head(url)\n\tdefer resp.Body.Close()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// (defer statement belongs here)\n\nThis checker helps uncover latent nil dereference bugs by reporting a\ndiagnostic for such mistakes.", 65696- Default: true, 65697- }, 65698- { 65699- Name: "ifaceassert", 65700- Doc: "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.\n", 65701- Default: true, 65702- }, 65703- { 65704- Name: "infertypeargs", 65705- Doc: "check for unnecessary type arguments in call expressions\n\nExplicit type arguments may be omitted from call expressions if they can be\ninferred from function arguments, or from other type arguments:\n\n\tfunc f[T any](T) {}\n\t\n\tfunc _() {\n\t\tf[string](\"foo\") // string could be inferred\n\t}\n", 65706- Default: true, 65707- }, 65708- { 65709- Name: "loopclosure", 65710- Doc: "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n for _, v := range list {\n defer func() {\n use(v) // incorrect\n }()\n }\n\nOne fix is to create a new variable for each iteration of the loop:\n\n for _, v := range list {\n v := v // new var per iteration\n defer func() {\n use(v) // ok\n }()\n }\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n for _, v := range elem {\n go func() {\n use(v) // incorrect, and a data race\n }()\n }\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n func Test(t *testing.T) {\n for _, test := range tests {\n t.Run(test.name, func(t *testing.T) {\n t.Parallel()\n use(test) // incorrect, and a data race\n })\n }\n }\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines", 65711- Default: true, 65712- }, 65713- { 65714- Name: "lostcancel", 65715- Doc: "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nand WithDeadline must be called or the new context will remain live\nuntil its parent context is cancelled.\n(The background context is never cancelled.)", 65716- Default: true, 65717- }, 65718- { 65719- Name: "nilfunc", 65720- Doc: "check for useless comparisons between functions and nil\n\nA useless comparison is one like f == nil as opposed to f() == nil.", 65721- Default: true, 65722- }, 65723- { 65724- Name: "nilness", 65725- Doc: "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}\n", 65726- }, 65727- { 65728- Name: "printf", 65729- Doc: "check consistency of Printf format strings and arguments\n\nThe check applies to known functions (for example, those in package fmt)\nas well as any detected wrappers of known functions.\n\nA function that wants to avail itself of printf checking but is not\nfound by this analyzer's heuristics (for example, due to use of\ndynamic calls) can insert a bogus call:\n\n\tif false {\n\t\t_ = fmt.Sprintf(format, args...) // enable printf checking\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.\n", 65730- Default: true, 65731- }, 65732- { 65733- Name: "shadow", 65734- Doc: "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}\n", 65735- }, 65736- { 65737- Name: "shift", 65738- Doc: "check for shifts that equal or exceed the width of the integer", 65739- Default: true, 65740- }, 65741- { 65742- Name: "simplifycompositelit", 65743- Doc: "check for composite literal simplifications\n\nAn array, slice, or map composite literal of the form:\n\t[]T{T{}, T{}}\nwill be simplified to:\n\t[]T{{}, {}}\n\nThis is one of the simplifications that \"gofmt -s\" applies.", 65744- Default: true, 65745- }, 65746- { 65747- Name: "simplifyrange", 65748- Doc: "check for range statement simplifications\n\nA range of the form:\n\tfor x, _ = range v {...}\nwill be simplified to:\n\tfor x = range v {...}\n\nA range of the form:\n\tfor _ = range v {...}\nwill be simplified to:\n\tfor range v {...}\n\nThis is one of the simplifications that \"gofmt -s\" applies.", 65749- Default: true, 65750- }, 65751- { 65752- Name: "simplifyslice", 65753- Doc: "check for slice simplifications\n\nA slice expression of the form:\n\ts[a:len(s)]\nwill be simplified to:\n\ts[a:]\n\nThis is one of the simplifications that \"gofmt -s\" applies.", 65754- Default: true, 65755- }, 65756- { 65757- Name: "sortslice", 65758- Doc: "check the argument type of sort.Slice\n\nsort.Slice requires an argument of a slice type. Check that\nthe interface{} value passed to sort.Slice is actually a slice.", 65759- Default: true, 65760- }, 65761- { 65762- Name: "stdmethods", 65763- Doc: "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n func (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo\n", 65764- Default: true, 65765- }, 65766- { 65767- Name: "stringintconv", 65768- Doc: "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.\n", 65769- Default: true, 65770- }, 65771- { 65772- Name: "structtag", 65773- Doc: "check that struct field tags conform to reflect.StructTag.Get\n\nAlso report certain struct tags (json, xml) used with unexported fields.", 65774- Default: true, 65775- }, 65776- { 65777- Name: "testinggoroutine", 65778- Doc: "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\nfunc TestFoo(t *testing.T) {\n go func() {\n t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n }()\n}\n", 65779- Default: true, 65780- }, 65781- { 65782- Name: "tests", 65783- Doc: "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.", 65784- Default: true, 65785- }, 65786- { 65787- Name: "timeformat", 65788- Doc: "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.\n", 65789- Default: true, 65790- }, 65791- { 65792- Name: "unmarshal", 65793- Doc: "report passing non-pointer or non-interface values to unmarshal\n\nThe unmarshal analysis reports calls to functions such as json.Unmarshal\nin which the argument type is not a pointer or an interface.", 65794- Default: true, 65795- }, 65796- { 65797- Name: "unreachable", 65798- Doc: "check for unreachable code\n\nThe unreachable analyzer finds statements that execution can never reach\nbecause they are preceded by an return statement, a call to panic, an\ninfinite loop, or similar constructs.", 65799- Default: true, 65800- }, 65801- { 65802- Name: "unsafeptr", 65803- Doc: "check for invalid conversions of uintptr to unsafe.Pointer\n\nThe unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer\nto convert integers to pointers. A conversion from uintptr to\nunsafe.Pointer is invalid if it implies that there is a uintptr-typed\nword in memory that holds a pointer value, because that word will be\ninvisible to stack copying and to the garbage collector.", 65804- Default: true, 65805- }, 65806- { 65807- Name: "unusedparams", 65808- Doc: "check for unused parameters of functions\n\nThe unusedparams analyzer checks functions to see if there are\nany parameters that are not being used.\n\nTo reduce false positives it ignores:\n- methods\n- parameters that do not have a name or are underscored\n- functions in test files\n- functions with empty bodies or those with just a return stmt", 65809- }, 65810- { 65811- Name: "unusedresult", 65812- Doc: "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side effects,\nso it is always a mistake to discard the result. This analyzer reports\ncalls to certain functions in which the result of the call is ignored.\n\nThe set of functions may be controlled using flags.", 65813- Default: true, 65814- }, 65815- { 65816- Name: "unusedwrite", 65817- Doc: "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\tfunc f(input []T) {\n\t\tfor i, v := range input { // v is a copy\n\t\t\tv.x = i // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\tfunc (t T) f() { // t is a copy\n\t\tt.x = i // unused write to field x\n\t}\n", 65818- }, 65819- { 65820- Name: "useany", 65821- Doc: "check for constraints that could be simplified to \"any\"", 65822- }, 65823- { 65824- Name: "fillreturns", 65825- Doc: "suggest fixes for errors due to an incorrect number of return values\n\nThis checker provides suggested fixes for type errors of the\ntype \"wrong number of return values (want %d, got %d)\". For example:\n\tfunc m() (int, string, *bool, error) {\n\t\treturn\n\t}\nwill turn into\n\tfunc m() (int, string, *bool, error) {\n\t\treturn 0, \"\", nil, nil\n\t}\n\nThis functionality is similar to https://github.com/sqs/goreturns.\n", 65826- Default: true, 65827- }, 65828- { 65829- Name: "nonewvars", 65830- Doc: "suggested fixes for \"no new vars on left side of :=\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"no new vars on left side of :=\". For example:\n\tz := 1\n\tz := 2\nwill turn into\n\tz := 1\n\tz = 2\n", 65831- Default: true, 65832- }, 65833- { 65834- Name: "noresultvalues", 65835- Doc: "suggested fixes for unexpected return values\n\nThis checker provides suggested fixes for type errors of the\ntype \"no result values expected\" or \"too many return values\".\nFor example:\n\tfunc z() { return nil }\nwill turn into\n\tfunc z() { return }\n", 65836- Default: true, 65837- }, 65838- { 65839- Name: "undeclaredname", 65840- Doc: "suggested fixes for \"undeclared name: <>\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"undeclared name: <>\". It will either insert a new statement,\nsuch as:\n\n\"<> := \"\n\nor a new function declaration, such as:\n\nfunc <>(inferred parameters) {\n\tpanic(\"implement me!\")\n}\n", 65841- Default: true, 65842- }, 65843- { 65844- Name: "unusedvariable", 65845- Doc: "check for unused variables\n\nThe unusedvariable analyzer suggests fixes for unused variables errors.\n", 65846- }, 65847- { 65848- Name: "fillstruct", 65849- Doc: "note incomplete struct initializations\n\nThis analyzer provides diagnostics for any struct literals that do not have\nany fields initialized. Because the suggested fix for this analysis is\nexpensive to compute, callers should compute it separately, using the\nSuggestedFix function below.\n", 65850- Default: true, 65851- }, 65852- { 65853- Name: "stubmethods", 65854- Doc: "stub methods analyzer\n\nThis analyzer generates method stubs for concrete types\nin order to implement a target interface", 65855- Default: true, 65856- }, 65857- }, 65858- Hints: []*HintJSON{ 65859- { 65860- Name: "assignVariableTypes", 65861- Doc: "Enable/disable inlay hints for variable types in assign statements:\n```go\n\ti/* int*/, j/* int*/ := 0, len(r)-1\n```", 65862- }, 65863- { 65864- Name: "compositeLiteralFields", 65865- Doc: "Enable/disable inlay hints for composite literal field names:\n```go\n\t{/*in: */\"Hello, world\", /*want: */\"dlrow ,olleH\"}\n```", 65866- }, 65867- { 65868- Name: "compositeLiteralTypes", 65869- Doc: "Enable/disable inlay hints for composite literal types:\n```go\n\tfor _, c := range []struct {\n\t\tin, want string\n\t}{\n\t\t/*struct{ in string; want string }*/{\"Hello, world\", \"dlrow ,olleH\"},\n\t}\n```", 65870- }, 65871- { 65872- Name: "constantValues", 65873- Doc: "Enable/disable inlay hints for constant values:\n```go\n\tconst (\n\t\tKindNone Kind = iota/* = 0*/\n\t\tKindPrint/* = 1*/\n\t\tKindPrintf/* = 2*/\n\t\tKindErrorf/* = 3*/\n\t)\n```", 65874- }, 65875- { 65876- Name: "functionTypeParameters", 65877- Doc: "Enable/disable inlay hints for implicit type parameters on generic functions:\n```go\n\tmyFoo/*[int, string]*/(1, \"hello\")\n```", 65878- }, 65879- { 65880- Name: "parameterNames", 65881- Doc: "Enable/disable inlay hints for parameter names:\n```go\n\tparseInt(/* str: */ \"123\", /* radix: */ 8)\n```", 65882- }, 65883- { 65884- Name: "rangeVariableTypes", 65885- Doc: "Enable/disable inlay hints for variable types in range statements:\n```go\n\tfor k/* int*/, v/* string*/ := range []string{} {\n\t\tfmt.Println(k, v)\n\t}\n```", 65886- }, 65887- }, 65888-} 65889diff -urN a/gopls/internal/lsp/source/call_hierarchy.go b/gopls/internal/lsp/source/call_hierarchy.go 65890--- a/gopls/internal/lsp/source/call_hierarchy.go 2000-01-01 00:00:00.000000000 -0000 65891+++ b/gopls/internal/lsp/source/call_hierarchy.go 1970-01-01 00:00:00.000000000 +0000 65892@@ -1,311 +0,0 @@ 65893-// Copyright 2020 The Go Authors. All rights reserved. 65894-// Use of this source code is governed by a BSD-style 65895-// license that can be found in the LICENSE file. 65896- 65897-package source 65898- 65899-import ( 65900- "context" 65901- "errors" 65902- "fmt" 65903- "go/ast" 65904- "go/token" 65905- "go/types" 65906- "path/filepath" 65907- 65908- "golang.org/x/tools/go/ast/astutil" 65909- "golang.org/x/tools/gopls/internal/lsp/protocol" 65910- "golang.org/x/tools/gopls/internal/lsp/safetoken" 65911- "golang.org/x/tools/gopls/internal/span" 65912- "golang.org/x/tools/internal/bug" 65913- "golang.org/x/tools/internal/event" 65914- "golang.org/x/tools/internal/event/tag" 65915-) 65916- 65917-// PrepareCallHierarchy returns an array of CallHierarchyItem for a file and the position within the file. 65918-func PrepareCallHierarchy(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) ([]protocol.CallHierarchyItem, error) { 65919- ctx, done := event.Start(ctx, "source.PrepareCallHierarchy") 65920- defer done() 65921- 65922- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 65923- if err != nil { 65924- return nil, err 65925- } 65926- pos, err := pgf.PositionPos(pp) 65927- if err != nil { 65928- return nil, err 65929- } 65930- 65931- _, obj, _ := referencedObject(pkg, pgf, pos) 65932- if obj == nil { 65933- return nil, nil 65934- } 65935- 65936- if _, ok := obj.Type().Underlying().(*types.Signature); !ok { 65937- return nil, nil 65938- } 65939- 65940- declLoc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), adjustedObjEnd(obj)) 65941- if err != nil { 65942- return nil, err 65943- } 65944- rng := declLoc.Range 65945- 65946- callHierarchyItem := protocol.CallHierarchyItem{ 65947- Name: obj.Name(), 65948- Kind: protocol.Function, 65949- Tags: []protocol.SymbolTag{}, 65950- Detail: fmt.Sprintf("%s • %s", obj.Pkg().Path(), filepath.Base(declLoc.URI.SpanURI().Filename())), 65951- URI: declLoc.URI, 65952- Range: rng, 65953- SelectionRange: rng, 65954- } 65955- return []protocol.CallHierarchyItem{callHierarchyItem}, nil 65956-} 65957- 65958-// IncomingCalls returns an array of CallHierarchyIncomingCall for a file and the position within the file. 65959-func IncomingCalls(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]protocol.CallHierarchyIncomingCall, error) { 65960- ctx, done := event.Start(ctx, "source.IncomingCalls") 65961- defer done() 65962- 65963- refs, err := references(ctx, snapshot, fh, pos, false) 65964- if err != nil { 65965- if errors.Is(err, ErrNoIdentFound) || errors.Is(err, errNoObjectFound) { 65966- return nil, nil 65967- } 65968- return nil, err 65969- } 65970- 65971- // Group references by their enclosing function declaration. 65972- incomingCalls := make(map[protocol.Location]*protocol.CallHierarchyIncomingCall) 65973- for _, ref := range refs { 65974- callItem, err := enclosingNodeCallItem(ctx, snapshot, ref.pkgPath, ref.location) 65975- if err != nil { 65976- event.Error(ctx, "error getting enclosing node", err, tag.Method.Of(string(ref.pkgPath))) 65977- continue 65978- } 65979- loc := protocol.Location{ 65980- URI: callItem.URI, 65981- Range: callItem.Range, 65982- } 65983- call, ok := incomingCalls[loc] 65984- if !ok { 65985- call = &protocol.CallHierarchyIncomingCall{From: callItem} 65986- incomingCalls[loc] = call 65987- } 65988- call.FromRanges = append(call.FromRanges, ref.location.Range) 65989- } 65990- 65991- // Flatten the map of pointers into a slice of values. 65992- incomingCallItems := make([]protocol.CallHierarchyIncomingCall, 0, len(incomingCalls)) 65993- for _, callItem := range incomingCalls { 65994- incomingCallItems = append(incomingCallItems, *callItem) 65995- } 65996- return incomingCallItems, nil 65997-} 65998- 65999-// enclosingNodeCallItem creates a CallHierarchyItem representing the function call at loc. 66000-func enclosingNodeCallItem(ctx context.Context, snapshot Snapshot, pkgPath PackagePath, loc protocol.Location) (protocol.CallHierarchyItem, error) { 66001- // Parse the file containing the reference. 66002- fh, err := snapshot.GetFile(ctx, loc.URI.SpanURI()) 66003- if err != nil { 66004- return protocol.CallHierarchyItem{}, err 66005- } 66006- // TODO(adonovan): opt: before parsing, trim the bodies of functions 66007- // that don't contain the reference, using either a scanner-based 66008- // implementation such as https://go.dev/play/p/KUrObH1YkX8 66009- // (~31% speedup), or a byte-oriented implementation (2x speedup). 66010- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 66011- if err != nil { 66012- return protocol.CallHierarchyItem{}, err 66013- } 66014- start, end, err := pgf.RangePos(loc.Range) 66015- if err != nil { 66016- return protocol.CallHierarchyItem{}, err 66017- } 66018- 66019- // Find the enclosing function, if any, and the number of func literals in between. 66020- var funcDecl *ast.FuncDecl 66021- var funcLit *ast.FuncLit // innermost function literal 66022- var litCount int 66023- path, _ := astutil.PathEnclosingInterval(pgf.File, start, end) 66024-outer: 66025- for _, node := range path { 66026- switch n := node.(type) { 66027- case *ast.FuncDecl: 66028- funcDecl = n 66029- break outer 66030- case *ast.FuncLit: 66031- litCount++ 66032- if litCount > 1 { 66033- continue 66034- } 66035- funcLit = n 66036- } 66037- } 66038- 66039- nameIdent := path[len(path)-1].(*ast.File).Name 66040- kind := protocol.Package 66041- if funcDecl != nil { 66042- nameIdent = funcDecl.Name 66043- kind = protocol.Function 66044- } 66045- 66046- nameStart, nameEnd := nameIdent.Pos(), nameIdent.End() 66047- if funcLit != nil { 66048- nameStart, nameEnd = funcLit.Type.Func, funcLit.Type.Params.Pos() 66049- kind = protocol.Function 66050- } 66051- rng, err := pgf.PosRange(nameStart, nameEnd) 66052- if err != nil { 66053- return protocol.CallHierarchyItem{}, err 66054- } 66055- 66056- name := nameIdent.Name 66057- for i := 0; i < litCount; i++ { 66058- name += ".func()" 66059- } 66060- 66061- return protocol.CallHierarchyItem{ 66062- Name: name, 66063- Kind: kind, 66064- Tags: []protocol.SymbolTag{}, 66065- Detail: fmt.Sprintf("%s • %s", pkgPath, filepath.Base(fh.URI().Filename())), 66066- URI: loc.URI, 66067- Range: rng, 66068- SelectionRange: rng, 66069- }, nil 66070-} 66071- 66072-// OutgoingCalls returns an array of CallHierarchyOutgoingCall for a file and the position within the file. 66073-func OutgoingCalls(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) ([]protocol.CallHierarchyOutgoingCall, error) { 66074- ctx, done := event.Start(ctx, "source.OutgoingCalls") 66075- defer done() 66076- 66077- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 66078- if err != nil { 66079- return nil, err 66080- } 66081- pos, err := pgf.PositionPos(pp) 66082- if err != nil { 66083- return nil, err 66084- } 66085- 66086- _, obj, _ := referencedObject(pkg, pgf, pos) 66087- if obj == nil { 66088- return nil, nil 66089- } 66090- 66091- if _, ok := obj.Type().Underlying().(*types.Signature); !ok { 66092- return nil, nil 66093- } 66094- 66095- // Skip builtins. 66096- if obj.Pkg() == nil { 66097- return nil, nil 66098- } 66099- 66100- if !obj.Pos().IsValid() { 66101- return nil, bug.Errorf("internal error: object %s.%s missing position", obj.Pkg().Path(), obj.Name()) 66102- } 66103- 66104- declFile := pkg.FileSet().File(obj.Pos()) 66105- if declFile == nil { 66106- return nil, bug.Errorf("file not found for %d", obj.Pos()) 66107- } 66108- 66109- uri := span.URIFromPath(declFile.Name()) 66110- offset, err := safetoken.Offset(declFile, obj.Pos()) 66111- if err != nil { 66112- return nil, err 66113- } 66114- 66115- // Use TypecheckFull as we want to inspect the body of the function declaration. 66116- declPkg, declPGF, err := PackageForFile(ctx, snapshot, uri, NarrowestPackage) 66117- if err != nil { 66118- return nil, err 66119- } 66120- 66121- declPos, err := safetoken.Pos(declPGF.Tok, offset) 66122- if err != nil { 66123- return nil, err 66124- } 66125- 66126- declNode, _, _ := findDeclInfo([]*ast.File{declPGF.File}, declPos) 66127- if declNode == nil { 66128- // TODO(rfindley): why don't we return an error here, or even bug.Errorf? 66129- return nil, nil 66130- // return nil, bug.Errorf("failed to find declaration for object %s.%s", obj.Pkg().Path(), obj.Name()) 66131- } 66132- 66133- type callRange struct { 66134- start, end token.Pos 66135- } 66136- callRanges := []callRange{} 66137- ast.Inspect(declNode, func(n ast.Node) bool { 66138- if call, ok := n.(*ast.CallExpr); ok { 66139- var start, end token.Pos 66140- switch n := call.Fun.(type) { 66141- case *ast.SelectorExpr: 66142- start, end = n.Sel.NamePos, call.Lparen 66143- case *ast.Ident: 66144- start, end = n.NamePos, call.Lparen 66145- case *ast.FuncLit: 66146- // while we don't add the function literal as an 'outgoing' call 66147- // we still want to traverse into it 66148- return true 66149- default: 66150- // ignore any other kind of call expressions 66151- // for ex: direct function literal calls since that's not an 'outgoing' call 66152- return false 66153- } 66154- callRanges = append(callRanges, callRange{start: start, end: end}) 66155- } 66156- return true 66157- }) 66158- 66159- outgoingCalls := map[token.Pos]*protocol.CallHierarchyOutgoingCall{} 66160- for _, callRange := range callRanges { 66161- _, obj, _ := referencedObject(declPkg, declPGF, callRange.start) 66162- if obj == nil { 66163- continue 66164- } 66165- 66166- // ignore calls to builtin functions 66167- if obj.Pkg() == nil { 66168- continue 66169- } 66170- 66171- outgoingCall, ok := outgoingCalls[obj.Pos()] 66172- if !ok { 66173- loc, err := mapPosition(ctx, declPkg.FileSet(), snapshot, obj.Pos(), obj.Pos()+token.Pos(len(obj.Name()))) 66174- if err != nil { 66175- return nil, err 66176- } 66177- outgoingCall = &protocol.CallHierarchyOutgoingCall{ 66178- To: protocol.CallHierarchyItem{ 66179- Name: obj.Name(), 66180- Kind: protocol.Function, 66181- Tags: []protocol.SymbolTag{}, 66182- Detail: fmt.Sprintf("%s • %s", obj.Pkg().Path(), filepath.Base(loc.URI.SpanURI().Filename())), 66183- URI: loc.URI, 66184- Range: loc.Range, 66185- SelectionRange: loc.Range, 66186- }, 66187- } 66188- outgoingCalls[obj.Pos()] = outgoingCall 66189- } 66190- 66191- rng, err := declPGF.PosRange(callRange.start, callRange.end) 66192- if err != nil { 66193- return nil, err 66194- } 66195- outgoingCall.FromRanges = append(outgoingCall.FromRanges, rng) 66196- } 66197- 66198- outgoingCallItems := make([]protocol.CallHierarchyOutgoingCall, 0, len(outgoingCalls)) 66199- for _, callItem := range outgoingCalls { 66200- outgoingCallItems = append(outgoingCallItems, *callItem) 66201- } 66202- return outgoingCallItems, nil 66203-} 66204diff -urN a/gopls/internal/lsp/source/code_lens.go b/gopls/internal/lsp/source/code_lens.go 66205--- a/gopls/internal/lsp/source/code_lens.go 2000-01-01 00:00:00.000000000 -0000 66206+++ b/gopls/internal/lsp/source/code_lens.go 1970-01-01 00:00:00.000000000 +0000 66207@@ -1,248 +0,0 @@ 66208-// Copyright 2020 The Go Authors. All rights reserved. 66209-// Use of this source code is governed by a BSD-style 66210-// license that can be found in the LICENSE file. 66211- 66212-package source 66213- 66214-import ( 66215- "context" 66216- "go/ast" 66217- "go/token" 66218- "go/types" 66219- "path/filepath" 66220- "regexp" 66221- "strings" 66222- 66223- "golang.org/x/tools/gopls/internal/lsp/command" 66224- "golang.org/x/tools/gopls/internal/lsp/protocol" 66225- "golang.org/x/tools/gopls/internal/span" 66226-) 66227- 66228-type LensFunc func(context.Context, Snapshot, FileHandle) ([]protocol.CodeLens, error) 66229- 66230-// LensFuncs returns the supported lensFuncs for Go files. 66231-func LensFuncs() map[command.Command]LensFunc { 66232- return map[command.Command]LensFunc{ 66233- command.Generate: goGenerateCodeLens, 66234- command.Test: runTestCodeLens, 66235- command.RegenerateCgo: regenerateCgoLens, 66236- command.GCDetails: toggleDetailsCodeLens, 66237- } 66238-} 66239- 66240-var ( 66241- testRe = regexp.MustCompile("^Test[^a-z]") 66242- benchmarkRe = regexp.MustCompile("^Benchmark[^a-z]") 66243-) 66244- 66245-func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) { 66246- codeLens := make([]protocol.CodeLens, 0) 66247- 66248- fns, err := TestsAndBenchmarks(ctx, snapshot, fh) 66249- if err != nil { 66250- return nil, err 66251- } 66252- puri := protocol.URIFromSpanURI(fh.URI()) 66253- for _, fn := range fns.Tests { 66254- cmd, err := command.NewTestCommand("run test", puri, []string{fn.Name}, nil) 66255- if err != nil { 66256- return nil, err 66257- } 66258- rng := protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start} 66259- codeLens = append(codeLens, protocol.CodeLens{Range: rng, Command: &cmd}) 66260- } 66261- 66262- for _, fn := range fns.Benchmarks { 66263- cmd, err := command.NewTestCommand("run benchmark", puri, nil, []string{fn.Name}) 66264- if err != nil { 66265- return nil, err 66266- } 66267- rng := protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start} 66268- codeLens = append(codeLens, protocol.CodeLens{Range: rng, Command: &cmd}) 66269- } 66270- 66271- if len(fns.Benchmarks) > 0 { 66272- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 66273- if err != nil { 66274- return nil, err 66275- } 66276- // add a code lens to the top of the file which runs all benchmarks in the file 66277- rng, err := pgf.PosRange(pgf.File.Package, pgf.File.Package) 66278- if err != nil { 66279- return nil, err 66280- } 66281- var benches []string 66282- for _, fn := range fns.Benchmarks { 66283- benches = append(benches, fn.Name) 66284- } 66285- cmd, err := command.NewTestCommand("run file benchmarks", puri, nil, benches) 66286- if err != nil { 66287- return nil, err 66288- } 66289- codeLens = append(codeLens, protocol.CodeLens{Range: rng, Command: &cmd}) 66290- } 66291- return codeLens, nil 66292-} 66293- 66294-type testFn struct { 66295- Name string 66296- Rng protocol.Range 66297-} 66298- 66299-type testFns struct { 66300- Tests []testFn 66301- Benchmarks []testFn 66302-} 66303- 66304-func TestsAndBenchmarks(ctx context.Context, snapshot Snapshot, fh FileHandle) (testFns, error) { 66305- var out testFns 66306- 66307- if !strings.HasSuffix(fh.URI().Filename(), "_test.go") { 66308- return out, nil 66309- } 66310- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 66311- if err != nil { 66312- return out, err 66313- } 66314- 66315- for _, d := range pgf.File.Decls { 66316- fn, ok := d.(*ast.FuncDecl) 66317- if !ok { 66318- continue 66319- } 66320- 66321- rng, err := pgf.NodeRange(fn) 66322- if err != nil { 66323- return out, err 66324- } 66325- 66326- if matchTestFunc(fn, pkg, testRe, "T") { 66327- out.Tests = append(out.Tests, testFn{fn.Name.Name, rng}) 66328- } 66329- 66330- if matchTestFunc(fn, pkg, benchmarkRe, "B") { 66331- out.Benchmarks = append(out.Benchmarks, testFn{fn.Name.Name, rng}) 66332- } 66333- } 66334- 66335- return out, nil 66336-} 66337- 66338-func matchTestFunc(fn *ast.FuncDecl, pkg Package, nameRe *regexp.Regexp, paramID string) bool { 66339- // Make sure that the function name matches a test function. 66340- if !nameRe.MatchString(fn.Name.Name) { 66341- return false 66342- } 66343- info := pkg.GetTypesInfo() 66344- if info == nil { 66345- return false 66346- } 66347- obj := info.ObjectOf(fn.Name) 66348- if obj == nil { 66349- return false 66350- } 66351- sig, ok := obj.Type().(*types.Signature) 66352- if !ok { 66353- return false 66354- } 66355- // Test functions should have only one parameter. 66356- if sig.Params().Len() != 1 { 66357- return false 66358- } 66359- 66360- // Check the type of the only parameter 66361- paramTyp, ok := sig.Params().At(0).Type().(*types.Pointer) 66362- if !ok { 66363- return false 66364- } 66365- named, ok := paramTyp.Elem().(*types.Named) 66366- if !ok { 66367- return false 66368- } 66369- namedObj := named.Obj() 66370- if namedObj.Pkg().Path() != "testing" { 66371- return false 66372- } 66373- return namedObj.Id() == paramID 66374-} 66375- 66376-func goGenerateCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) { 66377- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 66378- if err != nil { 66379- return nil, err 66380- } 66381- const ggDirective = "//go:generate" 66382- for _, c := range pgf.File.Comments { 66383- for _, l := range c.List { 66384- if !strings.HasPrefix(l.Text, ggDirective) { 66385- continue 66386- } 66387- rng, err := pgf.PosRange(l.Pos(), l.Pos()+token.Pos(len(ggDirective))) 66388- if err != nil { 66389- return nil, err 66390- } 66391- dir := protocol.URIFromSpanURI(span.URIFromPath(filepath.Dir(fh.URI().Filename()))) 66392- nonRecursiveCmd, err := command.NewGenerateCommand("run go generate", command.GenerateArgs{Dir: dir, Recursive: false}) 66393- if err != nil { 66394- return nil, err 66395- } 66396- recursiveCmd, err := command.NewGenerateCommand("run go generate ./...", command.GenerateArgs{Dir: dir, Recursive: true}) 66397- if err != nil { 66398- return nil, err 66399- } 66400- return []protocol.CodeLens{ 66401- {Range: rng, Command: &recursiveCmd}, 66402- {Range: rng, Command: &nonRecursiveCmd}, 66403- }, nil 66404- 66405- } 66406- } 66407- return nil, nil 66408-} 66409- 66410-func regenerateCgoLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) { 66411- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 66412- if err != nil { 66413- return nil, err 66414- } 66415- var c *ast.ImportSpec 66416- for _, imp := range pgf.File.Imports { 66417- if imp.Path.Value == `"C"` { 66418- c = imp 66419- } 66420- } 66421- if c == nil { 66422- return nil, nil 66423- } 66424- rng, err := pgf.NodeRange(c) 66425- if err != nil { 66426- return nil, err 66427- } 66428- puri := protocol.URIFromSpanURI(fh.URI()) 66429- cmd, err := command.NewRegenerateCgoCommand("regenerate cgo definitions", command.URIArg{URI: puri}) 66430- if err != nil { 66431- return nil, err 66432- } 66433- return []protocol.CodeLens{{Range: rng, Command: &cmd}}, nil 66434-} 66435- 66436-func toggleDetailsCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) { 66437- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 66438- if err != nil { 66439- return nil, err 66440- } 66441- if !pgf.File.Package.IsValid() { 66442- // Without a package name we have nowhere to put the codelens, so give up. 66443- return nil, nil 66444- } 66445- rng, err := pgf.PosRange(pgf.File.Package, pgf.File.Package) 66446- if err != nil { 66447- return nil, err 66448- } 66449- puri := protocol.URIFromSpanURI(fh.URI()) 66450- cmd, err := command.NewGCDetailsCommand("Toggle gc annotation details", puri) 66451- if err != nil { 66452- return nil, err 66453- } 66454- return []protocol.CodeLens{{Range: rng, Command: &cmd}}, nil 66455-} 66456diff -urN a/gopls/internal/lsp/source/comment.go b/gopls/internal/lsp/source/comment.go 66457--- a/gopls/internal/lsp/source/comment.go 2000-01-01 00:00:00.000000000 -0000 66458+++ b/gopls/internal/lsp/source/comment.go 1970-01-01 00:00:00.000000000 +0000 66459@@ -1,384 +0,0 @@ 66460-// Copyright 2019 The Go Authors. All rights reserved. 66461-// Use of this source code is governed by a BSD-style 66462-// license that can be found in the LICENSE file. 66463- 66464-//go:build !go1.19 66465-// +build !go1.19 66466- 66467-package source 66468- 66469-import ( 66470- "bytes" 66471- "io" 66472- "regexp" 66473- "strings" 66474- "unicode" 66475- "unicode/utf8" 66476-) 66477- 66478-// CommentToMarkdown converts comment text to formatted markdown. 66479-// The comment was prepared by DocReader, 66480-// so it is known not to have leading, trailing blank lines 66481-// nor to have trailing spaces at the end of lines. 66482-// The comment markers have already been removed. 66483-// 66484-// Each line is converted into a markdown line and empty lines are just converted to 66485-// newlines. Heading are prefixed with `### ` to make it a markdown heading. 66486-// 66487-// A span of indented lines retains a 4 space prefix block, with the common indent 66488-// prefix removed unless empty, in which case it will be converted to a newline. 66489-// 66490-// URLs in the comment text are converted into links. 66491-func CommentToMarkdown(text string, _ *Options) string { 66492- buf := &bytes.Buffer{} 66493- commentToMarkdown(buf, text) 66494- return buf.String() 66495-} 66496- 66497-var ( 66498- mdNewline = []byte("\n") 66499- mdHeader = []byte("### ") 66500- mdIndent = []byte(" ") 66501- mdLinkStart = []byte("[") 66502- mdLinkDiv = []byte("](") 66503- mdLinkEnd = []byte(")") 66504-) 66505- 66506-func commentToMarkdown(w io.Writer, text string) { 66507- blocks := blocks(text) 66508- for i, b := range blocks { 66509- switch b.op { 66510- case opPara: 66511- for _, line := range b.lines { 66512- emphasize(w, line, true) 66513- } 66514- case opHead: 66515- // The header block can consist of only one line. 66516- // However, check the number of lines, just in case. 66517- if len(b.lines) == 0 { 66518- // Skip this block. 66519- continue 66520- } 66521- header := b.lines[0] 66522- 66523- w.Write(mdHeader) 66524- commentEscape(w, header, true) 66525- // Header doesn't end with \n unlike the lines of other blocks. 66526- w.Write(mdNewline) 66527- case opPre: 66528- for _, line := range b.lines { 66529- if isBlank(line) { 66530- w.Write(mdNewline) 66531- continue 66532- } 66533- w.Write(mdIndent) 66534- w.Write([]byte(line)) 66535- } 66536- } 66537- 66538- if i < len(blocks)-1 { 66539- w.Write(mdNewline) 66540- } 66541- } 66542-} 66543- 66544-const ( 66545- ulquo = "“" 66546- urquo = "”" 66547-) 66548- 66549-var ( 66550- markdownEscape = regexp.MustCompile(`([\\\x60*{}[\]()#+\-.!_>~|"$%&'\/:;<=?@^])`) 66551- 66552- unicodeQuoteReplacer = strings.NewReplacer("``", ulquo, "''", urquo) 66553-) 66554- 66555-// commentEscape escapes comment text for markdown. If nice is set, 66556-// also turn double ` and ' into “ and ”. 66557-func commentEscape(w io.Writer, text string, nice bool) { 66558- if nice { 66559- text = convertQuotes(text) 66560- } 66561- text = escapeRegex(text) 66562- w.Write([]byte(text)) 66563-} 66564- 66565-func convertQuotes(text string) string { 66566- return unicodeQuoteReplacer.Replace(text) 66567-} 66568- 66569-func escapeRegex(text string) string { 66570- return markdownEscape.ReplaceAllString(text, `\$1`) 66571-} 66572- 66573-func emphasize(w io.Writer, line string, nice bool) { 66574- for { 66575- m := matchRx.FindStringSubmatchIndex(line) 66576- if m == nil { 66577- break 66578- } 66579- // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is urlRx) 66580- 66581- // write text before match 66582- commentEscape(w, line[0:m[0]], nice) 66583- 66584- // adjust match for URLs 66585- match := line[m[0]:m[1]] 66586- if strings.Contains(match, "://") { 66587- m0, m1 := m[0], m[1] 66588- for _, s := range []string{"()", "{}", "[]"} { 66589- open, close := s[:1], s[1:] // E.g., "(" and ")" 66590- // require opening parentheses before closing parentheses (#22285) 66591- if i := strings.Index(match, close); i >= 0 && i < strings.Index(match, open) { 66592- m1 = m0 + i 66593- match = line[m0:m1] 66594- } 66595- // require balanced pairs of parentheses (#5043) 66596- for i := 0; strings.Count(match, open) != strings.Count(match, close) && i < 10; i++ { 66597- m1 = strings.LastIndexAny(line[:m1], s) 66598- match = line[m0:m1] 66599- } 66600- } 66601- if m1 != m[1] { 66602- // redo matching with shortened line for correct indices 66603- m = matchRx.FindStringSubmatchIndex(line[:m[0]+len(match)]) 66604- } 66605- } 66606- 66607- // Following code has been modified from go/doc since words is always 66608- // nil. All html formatting has also been transformed into markdown formatting 66609- 66610- // analyze match 66611- url := "" 66612- if m[2] >= 0 { 66613- url = match 66614- } 66615- 66616- // write match 66617- if len(url) > 0 { 66618- w.Write(mdLinkStart) 66619- } 66620- 66621- commentEscape(w, match, nice) 66622- 66623- if len(url) > 0 { 66624- w.Write(mdLinkDiv) 66625- w.Write([]byte(urlReplacer.Replace(url))) 66626- w.Write(mdLinkEnd) 66627- } 66628- 66629- // advance 66630- line = line[m[1]:] 66631- } 66632- commentEscape(w, line, nice) 66633-} 66634- 66635-// Everything from here on is a copy of go/doc/comment.go 66636- 66637-const ( 66638- // Regexp for Go identifiers 66639- identRx = `[\pL_][\pL_0-9]*` 66640- 66641- // Regexp for URLs 66642- // Match parens, and check later for balance - see #5043, #22285 66643- // Match .,:;?! within path, but not at end - see #18139, #16565 66644- // This excludes some rare yet valid urls ending in common punctuation 66645- // in order to allow sentences ending in URLs. 66646- 66647- // protocol (required) e.g. http 66648- protoPart = `(https?|ftp|file|gopher|mailto|nntp)` 66649- // host (required) e.g. www.example.com or [::1]:8080 66650- hostPart = `([a-zA-Z0-9_@\-.\[\]:]+)` 66651- // path+query+fragment (optional) e.g. /path/index.html?q=foo#bar 66652- pathPart = `([.,:;?!]*[a-zA-Z0-9$'()*+&#=@~_/\-\[\]%])*` 66653- 66654- urlRx = protoPart + `://` + hostPart + pathPart 66655-) 66656- 66657-var ( 66658- matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`) 66659- urlReplacer = strings.NewReplacer(`(`, `\(`, `)`, `\)`) 66660-) 66661- 66662-func indentLen(s string) int { 66663- i := 0 66664- for i < len(s) && (s[i] == ' ' || s[i] == '\t') { 66665- i++ 66666- } 66667- return i 66668-} 66669- 66670-func isBlank(s string) bool { 66671- return len(s) == 0 || (len(s) == 1 && s[0] == '\n') 66672-} 66673- 66674-func commonPrefix(a, b string) string { 66675- i := 0 66676- for i < len(a) && i < len(b) && a[i] == b[i] { 66677- i++ 66678- } 66679- return a[0:i] 66680-} 66681- 66682-func unindent(block []string) { 66683- if len(block) == 0 { 66684- return 66685- } 66686- 66687- // compute maximum common white prefix 66688- prefix := block[0][0:indentLen(block[0])] 66689- for _, line := range block { 66690- if !isBlank(line) { 66691- prefix = commonPrefix(prefix, line) 66692- } 66693- } 66694- n := len(prefix) 66695- 66696- // remove 66697- for i, line := range block { 66698- if !isBlank(line) { 66699- block[i] = line[n:] 66700- } 66701- } 66702-} 66703- 66704-// heading returns the trimmed line if it passes as a section heading; 66705-// otherwise it returns the empty string. 66706-func heading(line string) string { 66707- line = strings.TrimSpace(line) 66708- if len(line) == 0 { 66709- return "" 66710- } 66711- 66712- // a heading must start with an uppercase letter 66713- r, _ := utf8.DecodeRuneInString(line) 66714- if !unicode.IsLetter(r) || !unicode.IsUpper(r) { 66715- return "" 66716- } 66717- 66718- // it must end in a letter or digit: 66719- r, _ = utf8.DecodeLastRuneInString(line) 66720- if !unicode.IsLetter(r) && !unicode.IsDigit(r) { 66721- return "" 66722- } 66723- 66724- // exclude lines with illegal characters. we allow "()," 66725- if strings.ContainsAny(line, ";:!?+*/=[]{}_^°&§~%#@<\">\\") { 66726- return "" 66727- } 66728- 66729- // allow "'" for possessive "'s" only 66730- for b := line; ; { 66731- i := strings.IndexRune(b, '\'') 66732- if i < 0 { 66733- break 66734- } 66735- if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') { 66736- return "" // not followed by "s " 66737- } 66738- b = b[i+2:] 66739- } 66740- 66741- // allow "." when followed by non-space 66742- for b := line; ; { 66743- i := strings.IndexRune(b, '.') 66744- if i < 0 { 66745- break 66746- } 66747- if i+1 >= len(b) || b[i+1] == ' ' { 66748- return "" // not followed by non-space 66749- } 66750- b = b[i+1:] 66751- } 66752- 66753- return line 66754-} 66755- 66756-type op int 66757- 66758-const ( 66759- opPara op = iota 66760- opHead 66761- opPre 66762-) 66763- 66764-type block struct { 66765- op op 66766- lines []string 66767-} 66768- 66769-func blocks(text string) []block { 66770- var ( 66771- out []block 66772- para []string 66773- 66774- lastWasBlank = false 66775- lastWasHeading = false 66776- ) 66777- 66778- close := func() { 66779- if para != nil { 66780- out = append(out, block{opPara, para}) 66781- para = nil 66782- } 66783- } 66784- 66785- lines := strings.SplitAfter(text, "\n") 66786- unindent(lines) 66787- for i := 0; i < len(lines); { 66788- line := lines[i] 66789- if isBlank(line) { 66790- // close paragraph 66791- close() 66792- i++ 66793- lastWasBlank = true 66794- continue 66795- } 66796- if indentLen(line) > 0 { 66797- // close paragraph 66798- close() 66799- 66800- // count indented or blank lines 66801- j := i + 1 66802- for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) { 66803- j++ 66804- } 66805- // but not trailing blank lines 66806- for j > i && isBlank(lines[j-1]) { 66807- j-- 66808- } 66809- pre := lines[i:j] 66810- i = j 66811- 66812- unindent(pre) 66813- 66814- // put those lines in a pre block 66815- out = append(out, block{opPre, pre}) 66816- lastWasHeading = false 66817- continue 66818- } 66819- 66820- if lastWasBlank && !lastWasHeading && i+2 < len(lines) && 66821- isBlank(lines[i+1]) && !isBlank(lines[i+2]) && indentLen(lines[i+2]) == 0 { 66822- // current line is non-blank, surrounded by blank lines 66823- // and the next non-blank line is not indented: this 66824- // might be a heading. 66825- if head := heading(line); head != "" { 66826- close() 66827- out = append(out, block{opHead, []string{head}}) 66828- i += 2 66829- lastWasHeading = true 66830- continue 66831- } 66832- } 66833- 66834- // open paragraph 66835- lastWasBlank = false 66836- lastWasHeading = false 66837- para = append(para, lines[i]) 66838- i++ 66839- } 66840- close() 66841- 66842- return out 66843-} 66844diff -urN a/gopls/internal/lsp/source/comment_go118_test.go b/gopls/internal/lsp/source/comment_go118_test.go 66845--- a/gopls/internal/lsp/source/comment_go118_test.go 2000-01-01 00:00:00.000000000 -0000 66846+++ b/gopls/internal/lsp/source/comment_go118_test.go 1970-01-01 00:00:00.000000000 +0000 66847@@ -1,371 +0,0 @@ 66848-// Copyright 2019 The Go Authors. All rights reserved. 66849-// Use of this source code is governed by a BSD-style 66850-// license that can be found in the LICENSE file. 66851- 66852-//go:build !go1.19 66853-// +build !go1.19 66854- 66855-package source 66856- 66857-import ( 66858- "bytes" 66859- "reflect" 66860- "strings" 66861- "testing" 66862-) 66863- 66864-// This file is a copy of go/doc/comment_test.go with the exception for 66865-// the test cases for TestEmphasize and TestCommentEscape 66866- 66867-var headingTests = []struct { 66868- line string 66869- ok bool 66870-}{ 66871- {"Section", true}, 66872- {"A typical usage", true}, 66873- {"ΔΛΞ is Greek", true}, 66874- {"Foo 42", true}, 66875- {"", false}, 66876- {"section", false}, 66877- {"A typical usage:", false}, 66878- {"This code:", false}, 66879- {"δ is Greek", false}, 66880- {"Foo §", false}, 66881- {"Fermat's Last Sentence", true}, 66882- {"Fermat's", true}, 66883- {"'sX", false}, 66884- {"Ted 'Too' Bar", false}, 66885- {"Use n+m", false}, 66886- {"Scanning:", false}, 66887- {"N:M", false}, 66888-} 66889- 66890-func TestIsHeading(t *testing.T) { 66891- for _, tt := range headingTests { 66892- if h := heading(tt.line); (len(h) > 0) != tt.ok { 66893- t.Errorf("isHeading(%q) = %v, want %v", tt.line, h, tt.ok) 66894- } 66895- } 66896-} 66897- 66898-var blocksTests = []struct { 66899- in string 66900- out []block 66901- text string 66902-}{ 66903- { 66904- in: `Para 1. 66905-Para 1 line 2. 66906- 66907-Para 2. 66908- 66909-Section 66910- 66911-Para 3. 66912- 66913- pre 66914- pre1 66915- 66916-Para 4. 66917- 66918- pre 66919- pre1 66920- 66921- pre2 66922- 66923-Para 5. 66924- 66925- 66926- pre 66927- 66928- 66929- pre1 66930- pre2 66931- 66932-Para 6. 66933- pre 66934- pre2 66935-`, 66936- out: []block{ 66937- {opPara, []string{"Para 1.\n", "Para 1 line 2.\n"}}, 66938- {opPara, []string{"Para 2.\n"}}, 66939- {opHead, []string{"Section"}}, 66940- {opPara, []string{"Para 3.\n"}}, 66941- {opPre, []string{"pre\n", "pre1\n"}}, 66942- {opPara, []string{"Para 4.\n"}}, 66943- {opPre, []string{"pre\n", "pre1\n", "\n", "pre2\n"}}, 66944- {opPara, []string{"Para 5.\n"}}, 66945- {opPre, []string{"pre\n", "\n", "\n", "pre1\n", "pre2\n"}}, 66946- {opPara, []string{"Para 6.\n"}}, 66947- {opPre, []string{"pre\n", "pre2\n"}}, 66948- }, 66949- text: `. Para 1. Para 1 line 2. 66950- 66951-. Para 2. 66952- 66953- 66954-. Section 66955- 66956-. Para 3. 66957- 66958-$ pre 66959-$ pre1 66960- 66961-. Para 4. 66962- 66963-$ pre 66964-$ pre1 66965- 66966-$ pre2 66967- 66968-. Para 5. 66969- 66970-$ pre 66971- 66972- 66973-$ pre1 66974-$ pre2 66975- 66976-. Para 6. 66977- 66978-$ pre 66979-$ pre2 66980-`, 66981- }, 66982- { 66983- in: "Para.\n\tshould not be ``escaped''", 66984- out: []block{ 66985- {opPara, []string{"Para.\n"}}, 66986- {opPre, []string{"should not be ``escaped''"}}, 66987- }, 66988- text: ". Para.\n\n$ should not be ``escaped''", 66989- }, 66990- { 66991- in: "// A very long line of 46 char for line wrapping.", 66992- out: []block{ 66993- {opPara, []string{"// A very long line of 46 char for line wrapping."}}, 66994- }, 66995- text: `. // A very long line of 46 char for line 66996-. // wrapping. 66997-`, 66998- }, 66999- { 67000- in: `/* A very long line of 46 char for line wrapping. 67001-A very long line of 46 char for line wrapping. */`, 67002- out: []block{ 67003- {opPara, []string{"/* A very long line of 46 char for line wrapping.\n", "A very long line of 46 char for line wrapping. */"}}, 67004- }, 67005- text: `. /* A very long line of 46 char for line 67006-. wrapping. A very long line of 46 char 67007-. for line wrapping. */ 67008-`, 67009- }, 67010-} 67011- 67012-func TestBlocks(t *testing.T) { 67013- for i, tt := range blocksTests { 67014- b := blocks(tt.in) 67015- if !reflect.DeepEqual(b, tt.out) { 67016- t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, b, tt.out) 67017- } 67018- } 67019-} 67020- 67021-// This has been modified from go/doc to use markdown links instead of html ones 67022-// and use markdown escaping instead oh html 67023-var emphasizeTests = []struct { 67024- in, out string 67025-}{ 67026- {"", ""}, 67027- {"http://[::1]:8080/foo.txt", `[http\:\/\/\[\:\:1\]\:8080\/foo\.txt](http://[::1]:8080/foo.txt)`}, 67028- {"before (https://www.google.com) after", `before \([https\:\/\/www\.google\.com](https://www.google.com)\) after`}, 67029- {"before https://www.google.com:30/x/y/z:b::c. After", `before [https\:\/\/www\.google\.com\:30\/x\/y\/z\:b\:\:c](https://www.google.com:30/x/y/z:b::c)\. After`}, 67030- {"http://www.google.com/path/:;!-/?query=%34b#093124", `[http\:\/\/www\.google\.com\/path\/\:\;\!\-\/\?query\=\%34b\#093124](http://www.google.com/path/:;!-/?query=%34b#093124)`}, 67031- {"http://www.google.com/path/:;!-/?query=%34bar#093124", `[http\:\/\/www\.google\.com\/path\/\:\;\!\-\/\?query\=\%34bar\#093124](http://www.google.com/path/:;!-/?query=%34bar#093124)`}, 67032- {"http://www.google.com/index.html! After", `[http\:\/\/www\.google\.com\/index\.html](http://www.google.com/index.html)\! After`}, 67033- {"http://www.google.com/", `[http\:\/\/www\.google\.com\/](http://www.google.com/)`}, 67034- {"https://www.google.com/", `[https\:\/\/www\.google\.com\/](https://www.google.com/)`}, 67035- {"http://www.google.com/path.", `[http\:\/\/www\.google\.com\/path](http://www.google.com/path)\.`}, 67036- {"http://en.wikipedia.org/wiki/Camellia_(cipher)", `[http\:\/\/en\.wikipedia\.org\/wiki\/Camellia\_\(cipher\)](http://en.wikipedia.org/wiki/Camellia_\(cipher\))`}, 67037- {"(http://www.google.com/)", `\([http\:\/\/www\.google\.com\/](http://www.google.com/)\)`}, 67038- {"http://gmail.com)", `[http\:\/\/gmail\.com](http://gmail.com)\)`}, 67039- {"((http://gmail.com))", `\(\([http\:\/\/gmail\.com](http://gmail.com)\)\)`}, 67040- {"http://gmail.com ((http://gmail.com)) ()", `[http\:\/\/gmail\.com](http://gmail.com) \(\([http\:\/\/gmail\.com](http://gmail.com)\)\) \(\)`}, 67041- {"Foo bar http://example.com/ quux!", `Foo bar [http\:\/\/example\.com\/](http://example.com/) quux\!`}, 67042- {"Hello http://example.com/%2f/ /world.", `Hello [http\:\/\/example\.com\/\%2f\/](http://example.com/%2f/) \/world\.`}, 67043- {"Lorem http: ipsum //host/path", `Lorem http\: ipsum \/\/host\/path`}, 67044- {"javascript://is/not/linked", `javascript\:\/\/is\/not\/linked`}, 67045- {"http://foo", `[http\:\/\/foo](http://foo)`}, 67046- {"art by [[https://www.example.com/person/][Person Name]]", `art by \[\[[https\:\/\/www\.example\.com\/person\/](https://www.example.com/person/)\]\[Person Name\]\]`}, 67047- {"please visit (http://golang.org/)", `please visit \([http\:\/\/golang\.org\/](http://golang.org/)\)`}, 67048- {"please visit http://golang.org/hello())", `please visit [http\:\/\/golang\.org\/hello\(\)](http://golang.org/hello\(\))\)`}, 67049- {"http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD", `[http\:\/\/git\.qemu\.org\/\?p\=qemu\.git\;a\=blob\;f\=qapi\-schema\.json\;hb\=HEAD](http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD)`}, 67050- {"https://foo.bar/bal/x(])", `[https\:\/\/foo\.bar\/bal\/x\(](https://foo.bar/bal/x\()\]\)`}, 67051- {"foo [ http://bar(])", `foo \[ [http\:\/\/bar\(](http://bar\()\]\)`}, 67052-} 67053- 67054-func TestEmphasize(t *testing.T) { 67055- for i, tt := range emphasizeTests { 67056- var buf bytes.Buffer 67057- emphasize(&buf, tt.in, true) 67058- out := buf.String() 67059- if out != tt.out { 67060- t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, out, tt.out) 67061- } 67062- } 67063-} 67064- 67065-func TestCommentEscape(t *testing.T) { 67066- //ldquo -> ulquo and rdquo -> urquo 67067- commentTests := []struct { 67068- in, out string 67069- }{ 67070- {"typically invoked as ``go tool asm'',", "typically invoked as " + ulquo + "go tool asm" + urquo + ","}, 67071- {"For more detail, run ``go help test'' and ``go help testflag''", "For more detail, run " + ulquo + "go help test" + urquo + " and " + ulquo + "go help testflag" + urquo}} 67072- for i, tt := range commentTests { 67073- var buf strings.Builder 67074- commentEscape(&buf, tt.in, true) 67075- out := buf.String() 67076- if out != tt.out { 67077- t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out) 67078- } 67079- } 67080-} 67081- 67082-func TestCommentToMarkdown(t *testing.T) { 67083- tests := []struct { 67084- in, out string 67085- }{ 67086- { 67087- in: "F declaration.\n", 67088- out: "F declaration\\.\n", 67089- }, 67090- { 67091- in: ` 67092-F declaration. Lorem ipsum dolor sit amet. 67093-Etiam mattis eros at orci mollis molestie. 67094-`, 67095- out: ` 67096-F declaration\. Lorem ipsum dolor sit amet\. 67097-Etiam mattis eros at orci mollis molestie\. 67098-`, 67099- }, 67100- { 67101- in: ` 67102-F declaration. 67103- 67104-Lorem ipsum dolor sit amet. 67105-Sed id dui turpis. 67106- 67107- 67108- 67109- 67110-Aenean tempus velit non auctor eleifend. 67111-Aenean efficitur a sem id ultricies. 67112- 67113- 67114-Phasellus efficitur mauris et viverra bibendum. 67115-`, 67116- out: ` 67117-F declaration\. 67118- 67119-Lorem ipsum dolor sit amet\. 67120-Sed id dui turpis\. 67121- 67122-Aenean tempus velit non auctor eleifend\. 67123-Aenean efficitur a sem id ultricies\. 67124- 67125-Phasellus efficitur mauris et viverra bibendum\. 67126-`, 67127- }, 67128- { 67129- in: ` 67130-F declaration. 67131- 67132-Aenean tempus velit non auctor eleifend. 67133- 67134-Section 67135- 67136-Lorem ipsum dolor sit amet, consectetur adipiscing elit. 67137- 67138- func foo() {} 67139- 67140- 67141- func bar() {} 67142- 67143-Fusce lorem lacus. 67144- 67145- func foo() {} 67146- 67147- func bar() {} 67148- 67149-Maecenas in lobortis lectus. 67150- 67151- func foo() {} 67152- 67153- func bar() {} 67154- 67155-Phasellus efficitur mauris et viverra bibendum. 67156-`, 67157- out: ` 67158-F declaration\. 67159- 67160-Aenean tempus velit non auctor eleifend\. 67161- 67162-### Section 67163- 67164-Lorem ipsum dolor sit amet, consectetur adipiscing elit\. 67165- 67166- func foo() {} 67167- 67168- 67169- func bar() {} 67170- 67171-Fusce lorem lacus\. 67172- 67173- func foo() {} 67174- 67175- func bar() {} 67176- 67177-Maecenas in lobortis lectus\. 67178- 67179- func foo() {} 67180- 67181- func bar() {} 67182- 67183-Phasellus efficitur mauris et viverra bibendum\. 67184-`, 67185- }, 67186- { 67187- in: ` 67188-F declaration. 67189- 67190- func foo() { 67191- fmt.Println("foo") 67192- } 67193- func bar() { 67194- fmt.Println("bar") 67195- } 67196-`, 67197- out: ` 67198-F declaration\. 67199- 67200- func foo() { 67201- fmt.Println("foo") 67202- } 67203- func bar() { 67204- fmt.Println("bar") 67205- } 67206-`, 67207- }, 67208- } 67209- for i, tt := range tests { 67210- // Comments start with new lines for better readability. So, we should trim them. 67211- tt.in = strings.TrimPrefix(tt.in, "\n") 67212- tt.out = strings.TrimPrefix(tt.out, "\n") 67213- 67214- if out := CommentToMarkdown(tt.in, nil); out != tt.out { 67215- t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out) 67216- } 67217- } 67218-} 67219diff -urN a/gopls/internal/lsp/source/comment_go119.go b/gopls/internal/lsp/source/comment_go119.go 67220--- a/gopls/internal/lsp/source/comment_go119.go 2000-01-01 00:00:00.000000000 -0000 67221+++ b/gopls/internal/lsp/source/comment_go119.go 1970-01-01 00:00:00.000000000 +0000 67222@@ -1,56 +0,0 @@ 67223-// Copyright 2022 The Go Authors. All rights reserved. 67224-// Use of this source code is governed by a BSD-style 67225-// license that can be found in the LICENSE file. 67226- 67227-//go:build go1.19 67228-// +build go1.19 67229- 67230-package source 67231- 67232-// Starting with go1.19, the formatting of comments has changed, and there 67233-// is a new package (go/doc/comment) for processing them. 67234-// As long as gopls has to compile under earlier versions, tests 67235-// have to pass with both the old and new code, which produce 67236-// slightly different results. (cmd/test/definition.go, source/comment_test.go, 67237-// and source/source_test.go) Each of the test files checks the results 67238-// with a function, tests.CheckSameMarkdown, that accepts both the old and the new 67239-// results. (The old code escapes many characters the new code does not, 67240-// and the new code sometimes adds a blank line.) 67241- 67242-// When gopls no longer needs to compile with go1.18, the old comment.go should 67243-// be replaced by this file, the golden test files should be updated. 67244-// (and checkSameMarkdown() could be replaced by a simple comparison.) 67245- 67246-import ( 67247- "fmt" 67248- "go/doc/comment" 67249-) 67250- 67251-// CommentToMarkdown converts comment text to formatted markdown. 67252-// The comment was prepared by DocReader, 67253-// so it is known not to have leading, trailing blank lines 67254-// nor to have trailing spaces at the end of lines. 67255-// The comment markers have already been removed. 67256-func CommentToMarkdown(text string, options *Options) string { 67257- var p comment.Parser 67258- doc := p.Parse(text) 67259- var pr comment.Printer 67260- // The default produces {#Hdr-...} tags for headings. 67261- // vscode displays thems, which is undesirable. 67262- // The godoc for comment.Printer says the tags 67263- // avoid a security problem. 67264- pr.HeadingID = func(*comment.Heading) string { return "" } 67265- pr.DocLinkURL = func(link *comment.DocLink) string { 67266- msg := fmt.Sprintf("https://%s/%s", options.LinkTarget, link.ImportPath) 67267- if link.Name != "" { 67268- msg += "#" 67269- if link.Recv != "" { 67270- msg += link.Recv + "." 67271- } 67272- msg += link.Name 67273- } 67274- return msg 67275- } 67276- easy := pr.Markdown(doc) 67277- return string(easy) 67278-} 67279diff -urN a/gopls/internal/lsp/source/completion/builtin.go b/gopls/internal/lsp/source/completion/builtin.go 67280--- a/gopls/internal/lsp/source/completion/builtin.go 2000-01-01 00:00:00.000000000 -0000 67281+++ b/gopls/internal/lsp/source/completion/builtin.go 1970-01-01 00:00:00.000000000 +0000 67282@@ -1,147 +0,0 @@ 67283-// Copyright 2020 The Go Authors. All rights reserved. 67284-// Use of this source code is governed by a BSD-style 67285-// license that can be found in the LICENSE file. 67286- 67287-package completion 67288- 67289-import ( 67290- "context" 67291- "go/ast" 67292- "go/types" 67293-) 67294- 67295-// builtinArgKind determines the expected object kind for a builtin 67296-// argument. It attempts to use the AST hints from builtin.go where 67297-// possible. 67298-func (c *completer) builtinArgKind(ctx context.Context, obj types.Object, call *ast.CallExpr) objKind { 67299- builtin, err := c.snapshot.BuiltinFile(ctx) 67300- if err != nil { 67301- return 0 67302- } 67303- exprIdx := exprAtPos(c.pos, call.Args) 67304- 67305- builtinObj := builtin.File.Scope.Lookup(obj.Name()) 67306- if builtinObj == nil { 67307- return 0 67308- } 67309- decl, ok := builtinObj.Decl.(*ast.FuncDecl) 67310- if !ok || exprIdx >= len(decl.Type.Params.List) { 67311- return 0 67312- } 67313- 67314- switch ptyp := decl.Type.Params.List[exprIdx].Type.(type) { 67315- case *ast.ChanType: 67316- return kindChan 67317- case *ast.ArrayType: 67318- return kindSlice 67319- case *ast.MapType: 67320- return kindMap 67321- case *ast.Ident: 67322- switch ptyp.Name { 67323- case "Type": 67324- switch obj.Name() { 67325- case "make": 67326- return kindChan | kindSlice | kindMap 67327- case "len": 67328- return kindSlice | kindMap | kindArray | kindString | kindChan 67329- case "cap": 67330- return kindSlice | kindArray | kindChan 67331- } 67332- } 67333- } 67334- 67335- return 0 67336-} 67337- 67338-// builtinArgType infers the type of an argument to a builtin 67339-// function. parentInf is the inferred type info for the builtin 67340-// call's parent node. 67341-func (c *completer) builtinArgType(obj types.Object, call *ast.CallExpr, parentInf candidateInference) candidateInference { 67342- var ( 67343- exprIdx = exprAtPos(c.pos, call.Args) 67344- 67345- // Propagate certain properties from our parent's inference. 67346- inf = candidateInference{ 67347- typeName: parentInf.typeName, 67348- modifiers: parentInf.modifiers, 67349- } 67350- ) 67351- 67352- switch obj.Name() { 67353- case "append": 67354- if exprIdx <= 0 { 67355- // Infer first append() arg type as apparent return type of 67356- // append(). 67357- inf.objType = parentInf.objType 67358- if parentInf.variadic { 67359- inf.objType = types.NewSlice(inf.objType) 67360- } 67361- break 67362- } 67363- 67364- // For non-initial append() args, infer slice type from the first 67365- // append() arg, or from parent context. 67366- if len(call.Args) > 0 { 67367- inf.objType = c.pkg.GetTypesInfo().TypeOf(call.Args[0]) 67368- } 67369- if inf.objType == nil { 67370- inf.objType = parentInf.objType 67371- } 67372- if inf.objType == nil { 67373- break 67374- } 67375- 67376- inf.objType = deslice(inf.objType) 67377- 67378- // Check if we are completing the variadic append() param. 67379- inf.variadic = exprIdx == 1 && len(call.Args) <= 2 67380- 67381- // Penalize the first append() argument as a candidate. You 67382- // don't normally append a slice to itself. 67383- if sliceChain := objChain(c.pkg.GetTypesInfo(), call.Args[0]); len(sliceChain) > 0 { 67384- inf.penalized = append(inf.penalized, penalizedObj{objChain: sliceChain, penalty: 0.9}) 67385- } 67386- case "delete": 67387- if exprIdx > 0 && len(call.Args) > 0 { 67388- // Try to fill in expected type of map key. 67389- firstArgType := c.pkg.GetTypesInfo().TypeOf(call.Args[0]) 67390- if firstArgType != nil { 67391- if mt, ok := firstArgType.Underlying().(*types.Map); ok { 67392- inf.objType = mt.Key() 67393- } 67394- } 67395- } 67396- case "copy": 67397- var t1, t2 types.Type 67398- if len(call.Args) > 0 { 67399- t1 = c.pkg.GetTypesInfo().TypeOf(call.Args[0]) 67400- if len(call.Args) > 1 { 67401- t2 = c.pkg.GetTypesInfo().TypeOf(call.Args[1]) 67402- } 67403- } 67404- 67405- // Fill in expected type of either arg if the other is already present. 67406- if exprIdx == 1 && t1 != nil { 67407- inf.objType = t1 67408- } else if exprIdx == 0 && t2 != nil { 67409- inf.objType = t2 67410- } 67411- case "new": 67412- inf.typeName.wantTypeName = true 67413- if parentInf.objType != nil { 67414- // Expected type for "new" is the de-pointered parent type. 67415- if ptr, ok := parentInf.objType.Underlying().(*types.Pointer); ok { 67416- inf.objType = ptr.Elem() 67417- } 67418- } 67419- case "make": 67420- if exprIdx == 0 { 67421- inf.typeName.wantTypeName = true 67422- inf.objType = parentInf.objType 67423- } else { 67424- inf.objType = types.Typ[types.UntypedInt] 67425- } 67426- } 67427- 67428- return inf 67429-} 67430diff -urN a/gopls/internal/lsp/source/completion/completion.go b/gopls/internal/lsp/source/completion/completion.go 67431--- a/gopls/internal/lsp/source/completion/completion.go 2000-01-01 00:00:00.000000000 -0000 67432+++ b/gopls/internal/lsp/source/completion/completion.go 1970-01-01 00:00:00.000000000 +0000 67433@@ -1,3252 +0,0 @@ 67434-// Copyright 2018 The Go Authors. All rights reserved. 67435-// Use of this source code is governed by a BSD-style 67436-// license that can be found in the LICENSE file. 67437- 67438-// Package completion provides core functionality for code completion in Go 67439-// editors and tools. 67440-package completion 67441- 67442-import ( 67443- "bytes" 67444- "context" 67445- "fmt" 67446- "go/ast" 67447- "go/constant" 67448- "go/parser" 67449- "go/scanner" 67450- "go/token" 67451- "go/types" 67452- "math" 67453- "sort" 67454- "strconv" 67455- "strings" 67456- "sync" 67457- "sync/atomic" 67458- "time" 67459- "unicode" 67460- 67461- "golang.org/x/sync/errgroup" 67462- "golang.org/x/tools/go/ast/astutil" 67463- "golang.org/x/tools/gopls/internal/lsp/protocol" 67464- "golang.org/x/tools/gopls/internal/lsp/safetoken" 67465- "golang.org/x/tools/gopls/internal/lsp/snippet" 67466- "golang.org/x/tools/gopls/internal/lsp/source" 67467- "golang.org/x/tools/gopls/internal/span" 67468- "golang.org/x/tools/internal/event" 67469- "golang.org/x/tools/internal/fuzzy" 67470- "golang.org/x/tools/internal/imports" 67471- "golang.org/x/tools/internal/typeparams" 67472-) 67473- 67474-// A CompletionItem represents a possible completion suggested by the algorithm. 67475-type CompletionItem struct { 67476- 67477- // Invariant: CompletionItem does not refer to syntax or types. 67478- 67479- // Label is the primary text the user sees for this completion item. 67480- Label string 67481- 67482- // Detail is supplemental information to present to the user. 67483- // This often contains the type or return type of the completion item. 67484- Detail string 67485- 67486- // InsertText is the text to insert if this item is selected. 67487- // Any of the prefix that has already been typed is not trimmed. 67488- // The insert text does not contain snippets. 67489- InsertText string 67490- 67491- Kind protocol.CompletionItemKind 67492- Tags []protocol.CompletionItemTag 67493- Deprecated bool // Deprecated, prefer Tags if available 67494- 67495- // An optional array of additional TextEdits that are applied when 67496- // selecting this completion. 67497- // 67498- // Additional text edits should be used to change text unrelated to the current cursor position 67499- // (for example adding an import statement at the top of the file if the completion item will 67500- // insert an unqualified type). 67501- AdditionalTextEdits []protocol.TextEdit 67502- 67503- // Depth is how many levels were searched to find this completion. 67504- // For example when completing "foo<>", "fooBar" is depth 0, and 67505- // "fooBar.Baz" is depth 1. 67506- Depth int 67507- 67508- // Score is the internal relevance score. 67509- // A higher score indicates that this completion item is more relevant. 67510- Score float64 67511- 67512- // snippet is the LSP snippet for the completion item. The LSP 67513- // specification contains details about LSP snippets. For example, a 67514- // snippet for a function with the following signature: 67515- // 67516- // func foo(a, b, c int) 67517- // 67518- // would be: 67519- // 67520- // foo(${1:a int}, ${2: b int}, ${3: c int}) 67521- // 67522- // If Placeholders is false in the CompletionOptions, the above 67523- // snippet would instead be: 67524- // 67525- // foo(${1:}) 67526- snippet *snippet.Builder 67527- 67528- // Documentation is the documentation for the completion item. 67529- Documentation string 67530- 67531- // isSlice reports whether the underlying type of the object 67532- // from which this candidate was derived is a slice. 67533- // (Used to complete append() calls.) 67534- isSlice bool 67535-} 67536- 67537-// completionOptions holds completion specific configuration. 67538-type completionOptions struct { 67539- unimported bool 67540- documentation bool 67541- fullDocumentation bool 67542- placeholders bool 67543- literal bool 67544- snippets bool 67545- postfix bool 67546- matcher source.Matcher 67547- budget time.Duration 67548-} 67549- 67550-// Snippet is a convenience returns the snippet if available, otherwise 67551-// the InsertText. 67552-// used for an item, depending on if the callee wants placeholders or not. 67553-func (i *CompletionItem) Snippet() string { 67554- if i.snippet != nil { 67555- return i.snippet.String() 67556- } 67557- return i.InsertText 67558-} 67559- 67560-// Scoring constants are used for weighting the relevance of different candidates. 67561-const ( 67562- // stdScore is the base score for all completion items. 67563- stdScore float64 = 1.0 67564- 67565- // highScore indicates a very relevant completion item. 67566- highScore float64 = 10.0 67567- 67568- // lowScore indicates an irrelevant or not useful completion item. 67569- lowScore float64 = 0.01 67570-) 67571- 67572-// matcher matches a candidate's label against the user input. The 67573-// returned score reflects the quality of the match. A score of zero 67574-// indicates no match, and a score of one means a perfect match. 67575-type matcher interface { 67576- Score(candidateLabel string) (score float32) 67577-} 67578- 67579-// prefixMatcher implements case sensitive prefix matching. 67580-type prefixMatcher string 67581- 67582-func (pm prefixMatcher) Score(candidateLabel string) float32 { 67583- if strings.HasPrefix(candidateLabel, string(pm)) { 67584- return 1 67585- } 67586- return -1 67587-} 67588- 67589-// insensitivePrefixMatcher implements case insensitive prefix matching. 67590-type insensitivePrefixMatcher string 67591- 67592-func (ipm insensitivePrefixMatcher) Score(candidateLabel string) float32 { 67593- if strings.HasPrefix(strings.ToLower(candidateLabel), string(ipm)) { 67594- return 1 67595- } 67596- return -1 67597-} 67598- 67599-// completer contains the necessary information for a single completion request. 67600-type completer struct { 67601- snapshot source.Snapshot 67602- pkg source.Package 67603- qf types.Qualifier // for qualifying typed expressions 67604- mq source.MetadataQualifier // for syntactic qualifying 67605- opts *completionOptions 67606- 67607- // completionContext contains information about the trigger for this 67608- // completion request. 67609- completionContext completionContext 67610- 67611- // fh is a handle to the file associated with this completion request. 67612- fh source.FileHandle 67613- 67614- // filename is the name of the file associated with this completion request. 67615- filename string 67616- 67617- // file is the AST of the file associated with this completion request. 67618- file *ast.File 67619- 67620- // (tokFile, pos) is the position at which the request was triggered. 67621- tokFile *token.File 67622- pos token.Pos 67623- 67624- // path is the path of AST nodes enclosing the position. 67625- path []ast.Node 67626- 67627- // seen is the map that ensures we do not return duplicate results. 67628- seen map[types.Object]bool 67629- 67630- // items is the list of completion items returned. 67631- items []CompletionItem 67632- 67633- // completionCallbacks is a list of callbacks to collect completions that 67634- // require expensive operations. This includes operations where we search 67635- // through the entire module cache. 67636- completionCallbacks []func(opts *imports.Options) error 67637- 67638- // surrounding describes the identifier surrounding the position. 67639- surrounding *Selection 67640- 67641- // inference contains information we've inferred about ideal 67642- // candidates such as the candidate's type. 67643- inference candidateInference 67644- 67645- // enclosingFunc contains information about the function enclosing 67646- // the position. 67647- enclosingFunc *funcInfo 67648- 67649- // enclosingCompositeLiteral contains information about the composite literal 67650- // enclosing the position. 67651- enclosingCompositeLiteral *compLitInfo 67652- 67653- // deepState contains the current state of our deep completion search. 67654- deepState deepCompletionState 67655- 67656- // matcher matches the candidates against the surrounding prefix. 67657- matcher matcher 67658- 67659- // methodSetCache caches the types.NewMethodSet call, which is relatively 67660- // expensive and can be called many times for the same type while searching 67661- // for deep completions. 67662- methodSetCache map[methodSetKey]*types.MethodSet 67663- 67664- // mapper converts the positions in the file from which the completion originated. 67665- mapper *protocol.Mapper 67666- 67667- // startTime is when we started processing this completion request. It does 67668- // not include any time the request spent in the queue. 67669- startTime time.Time 67670- 67671- // scopes contains all scopes defined by nodes in our path, 67672- // including nil values for nodes that don't defined a scope. It 67673- // also includes our package scope and the universal scope at the 67674- // end. 67675- scopes []*types.Scope 67676-} 67677- 67678-// funcInfo holds info about a function object. 67679-type funcInfo struct { 67680- // sig is the function declaration enclosing the position. 67681- sig *types.Signature 67682- 67683- // body is the function's body. 67684- body *ast.BlockStmt 67685-} 67686- 67687-type compLitInfo struct { 67688- // cl is the *ast.CompositeLit enclosing the position. 67689- cl *ast.CompositeLit 67690- 67691- // clType is the type of cl. 67692- clType types.Type 67693- 67694- // kv is the *ast.KeyValueExpr enclosing the position, if any. 67695- kv *ast.KeyValueExpr 67696- 67697- // inKey is true if we are certain the position is in the key side 67698- // of a key-value pair. 67699- inKey bool 67700- 67701- // maybeInFieldName is true if inKey is false and it is possible 67702- // we are completing a struct field name. For example, 67703- // "SomeStruct{<>}" will be inKey=false, but maybeInFieldName=true 67704- // because we _could_ be completing a field name. 67705- maybeInFieldName bool 67706-} 67707- 67708-type importInfo struct { 67709- importPath string 67710- name string 67711-} 67712- 67713-type methodSetKey struct { 67714- typ types.Type 67715- addressable bool 67716-} 67717- 67718-type completionContext struct { 67719- // triggerCharacter is the character used to trigger completion at current 67720- // position, if any. 67721- triggerCharacter string 67722- 67723- // triggerKind is information about how a completion was triggered. 67724- triggerKind protocol.CompletionTriggerKind 67725- 67726- // commentCompletion is true if we are completing a comment. 67727- commentCompletion bool 67728- 67729- // packageCompletion is true if we are completing a package name. 67730- packageCompletion bool 67731-} 67732- 67733-// A Selection represents the cursor position and surrounding identifier. 67734-type Selection struct { 67735- content string 67736- tokFile *token.File 67737- start, end, cursor token.Pos // relative to rng.TokFile 67738- mapper *protocol.Mapper 67739-} 67740- 67741-func (p Selection) Content() string { 67742- return p.content 67743-} 67744- 67745-func (p Selection) Range() (protocol.Range, error) { 67746- return p.mapper.PosRange(p.tokFile, p.start, p.end) 67747-} 67748- 67749-func (p Selection) Prefix() string { 67750- return p.content[:p.cursor-p.start] 67751-} 67752- 67753-func (p Selection) Suffix() string { 67754- return p.content[p.cursor-p.start:] 67755-} 67756- 67757-func (c *completer) setSurrounding(ident *ast.Ident) { 67758- if c.surrounding != nil { 67759- return 67760- } 67761- if !(ident.Pos() <= c.pos && c.pos <= ident.End()) { 67762- return 67763- } 67764- 67765- c.surrounding = &Selection{ 67766- content: ident.Name, 67767- cursor: c.pos, 67768- // Overwrite the prefix only. 67769- tokFile: c.tokFile, 67770- start: ident.Pos(), 67771- end: ident.End(), 67772- mapper: c.mapper, 67773- } 67774- 67775- c.setMatcherFromPrefix(c.surrounding.Prefix()) 67776-} 67777- 67778-func (c *completer) setMatcherFromPrefix(prefix string) { 67779- switch c.opts.matcher { 67780- case source.Fuzzy: 67781- c.matcher = fuzzy.NewMatcher(prefix) 67782- case source.CaseSensitive: 67783- c.matcher = prefixMatcher(prefix) 67784- default: 67785- c.matcher = insensitivePrefixMatcher(strings.ToLower(prefix)) 67786- } 67787-} 67788- 67789-func (c *completer) getSurrounding() *Selection { 67790- if c.surrounding == nil { 67791- c.surrounding = &Selection{ 67792- content: "", 67793- cursor: c.pos, 67794- tokFile: c.tokFile, 67795- start: c.pos, 67796- end: c.pos, 67797- mapper: c.mapper, 67798- } 67799- } 67800- return c.surrounding 67801-} 67802- 67803-// candidate represents a completion candidate. 67804-type candidate struct { 67805- // obj is the types.Object to complete to. 67806- // TODO(adonovan): eliminate dependence on go/types throughout this struct. 67807- obj types.Object 67808- 67809- // score is used to rank candidates. 67810- score float64 67811- 67812- // name is the deep object name path, e.g. "foo.bar" 67813- name string 67814- 67815- // detail is additional information about this item. If not specified, 67816- // defaults to type string for the object. 67817- detail string 67818- 67819- // path holds the path from the search root (excluding the candidate 67820- // itself) for a deep candidate. 67821- path []types.Object 67822- 67823- // pathInvokeMask is a bit mask tracking whether each entry in path 67824- // should be formatted with "()" (i.e. whether it is a function 67825- // invocation). 67826- pathInvokeMask uint16 67827- 67828- // mods contains modifications that should be applied to the 67829- // candidate when inserted. For example, "foo" may be inserted as 67830- // "*foo" or "foo()". 67831- mods []typeModKind 67832- 67833- // addressable is true if a pointer can be taken to the candidate. 67834- addressable bool 67835- 67836- // convertTo is a type that this candidate should be cast to. For 67837- // example, if convertTo is float64, "foo" should be formatted as 67838- // "float64(foo)". 67839- convertTo types.Type 67840- 67841- // imp is the import that needs to be added to this package in order 67842- // for this candidate to be valid. nil if no import needed. 67843- imp *importInfo 67844-} 67845- 67846-func (c candidate) hasMod(mod typeModKind) bool { 67847- for _, m := range c.mods { 67848- if m == mod { 67849- return true 67850- } 67851- } 67852- return false 67853-} 67854- 67855-// ErrIsDefinition is an error that informs the user they got no 67856-// completions because they tried to complete the name of a new object 67857-// being defined. 67858-type ErrIsDefinition struct { 67859- objStr string 67860-} 67861- 67862-func (e ErrIsDefinition) Error() string { 67863- msg := "this is a definition" 67864- if e.objStr != "" { 67865- msg += " of " + e.objStr 67866- } 67867- return msg 67868-} 67869- 67870-// Completion returns a list of possible candidates for completion, given a 67871-// a file and a position. 67872-// 67873-// The selection is computed based on the preceding identifier and can be used by 67874-// the client to score the quality of the completion. For instance, some clients 67875-// may tolerate imperfect matches as valid completion results, since users may make typos. 67876-func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, protoPos protocol.Position, protoContext protocol.CompletionContext) ([]CompletionItem, *Selection, error) { 67877- ctx, done := event.Start(ctx, "completion.Completion") 67878- defer done() 67879- 67880- startTime := time.Now() 67881- 67882- pkg, pgf, err := source.PackageForFile(ctx, snapshot, fh.URI(), source.NarrowestPackage) 67883- if err != nil || pgf.File.Package == token.NoPos { 67884- // If we can't parse this file or find position for the package 67885- // keyword, it may be missing a package declaration. Try offering 67886- // suggestions for the package declaration. 67887- // Note that this would be the case even if the keyword 'package' is 67888- // present but no package name exists. 67889- items, surrounding, innerErr := packageClauseCompletions(ctx, snapshot, fh, protoPos) 67890- if innerErr != nil { 67891- // return the error for GetParsedFile since it's more relevant in this situation. 67892- return nil, nil, fmt.Errorf("getting file %s for Completion: %w (package completions: %v)", fh.URI(), err, innerErr) 67893- } 67894- return items, surrounding, nil 67895- } 67896- pos, err := pgf.PositionPos(protoPos) 67897- if err != nil { 67898- return nil, nil, err 67899- } 67900- // Completion is based on what precedes the cursor. 67901- // Find the path to the position before pos. 67902- path, _ := astutil.PathEnclosingInterval(pgf.File, pos-1, pos-1) 67903- if path == nil { 67904- return nil, nil, fmt.Errorf("cannot find node enclosing position") 67905- } 67906- 67907- // Check if completion at this position is valid. If not, return early. 67908- switch n := path[0].(type) { 67909- case *ast.BasicLit: 67910- // Skip completion inside literals except for ImportSpec 67911- if len(path) > 1 { 67912- if _, ok := path[1].(*ast.ImportSpec); ok { 67913- break 67914- } 67915- } 67916- return nil, nil, nil 67917- case *ast.CallExpr: 67918- if n.Ellipsis.IsValid() && pos > n.Ellipsis && pos <= n.Ellipsis+token.Pos(len("...")) { 67919- // Don't offer completions inside or directly after "...". For 67920- // example, don't offer completions at "<>" in "foo(bar...<>"). 67921- return nil, nil, nil 67922- } 67923- case *ast.Ident: 67924- // reject defining identifiers 67925- if obj, ok := pkg.GetTypesInfo().Defs[n]; ok { 67926- if v, ok := obj.(*types.Var); ok && v.IsField() && v.Embedded() { 67927- // An anonymous field is also a reference to a type. 67928- } else if pgf.File.Name == n { 67929- // Don't skip completions if Ident is for package name. 67930- break 67931- } else { 67932- objStr := "" 67933- if obj != nil { 67934- qual := types.RelativeTo(pkg.GetTypes()) 67935- objStr = types.ObjectString(obj, qual) 67936- } 67937- ans, sel := definition(path, obj, pgf) 67938- if ans != nil { 67939- sort.Slice(ans, func(i, j int) bool { 67940- return ans[i].Score > ans[j].Score 67941- }) 67942- return ans, sel, nil 67943- } 67944- return nil, nil, ErrIsDefinition{objStr: objStr} 67945- } 67946- } 67947- } 67948- 67949- // Collect all surrounding scopes, innermost first. 67950- scopes := source.CollectScopes(pkg.GetTypesInfo(), path, pos) 67951- scopes = append(scopes, pkg.GetTypes().Scope(), types.Universe) 67952- 67953- opts := snapshot.View().Options() 67954- c := &completer{ 67955- pkg: pkg, 67956- snapshot: snapshot, 67957- qf: source.Qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo()), 67958- mq: source.MetadataQualifierForFile(snapshot, pgf.File, pkg.Metadata()), 67959- completionContext: completionContext{ 67960- triggerCharacter: protoContext.TriggerCharacter, 67961- triggerKind: protoContext.TriggerKind, 67962- }, 67963- fh: fh, 67964- filename: fh.URI().Filename(), 67965- tokFile: pgf.Tok, 67966- file: pgf.File, 67967- path: path, 67968- pos: pos, 67969- seen: make(map[types.Object]bool), 67970- enclosingFunc: enclosingFunction(path, pkg.GetTypesInfo()), 67971- enclosingCompositeLiteral: enclosingCompositeLiteral(path, pos, pkg.GetTypesInfo()), 67972- deepState: deepCompletionState{ 67973- enabled: opts.DeepCompletion, 67974- }, 67975- opts: &completionOptions{ 67976- matcher: opts.Matcher, 67977- unimported: opts.CompleteUnimported, 67978- documentation: opts.CompletionDocumentation && opts.HoverKind != source.NoDocumentation, 67979- fullDocumentation: opts.HoverKind == source.FullDocumentation, 67980- placeholders: opts.UsePlaceholders, 67981- literal: opts.LiteralCompletions && opts.InsertTextFormat == protocol.SnippetTextFormat, 67982- budget: opts.CompletionBudget, 67983- snippets: opts.InsertTextFormat == protocol.SnippetTextFormat, 67984- postfix: opts.ExperimentalPostfixCompletions, 67985- }, 67986- // default to a matcher that always matches 67987- matcher: prefixMatcher(""), 67988- methodSetCache: make(map[methodSetKey]*types.MethodSet), 67989- mapper: pgf.Mapper, 67990- startTime: startTime, 67991- scopes: scopes, 67992- } 67993- 67994- var cancel context.CancelFunc 67995- if c.opts.budget == 0 { 67996- ctx, cancel = context.WithCancel(ctx) 67997- } else { 67998- // timeoutDuration is the completion budget remaining. If less than 67999- // 10ms, set to 10ms 68000- timeoutDuration := time.Until(c.startTime.Add(c.opts.budget)) 68001- if timeoutDuration < 10*time.Millisecond { 68002- timeoutDuration = 10 * time.Millisecond 68003- } 68004- ctx, cancel = context.WithTimeout(ctx, timeoutDuration) 68005- } 68006- defer cancel() 68007- 68008- if surrounding := c.containingIdent(pgf.Src); surrounding != nil { 68009- c.setSurrounding(surrounding) 68010- } 68011- 68012- c.inference = expectedCandidate(ctx, c) 68013- 68014- err = c.collectCompletions(ctx) 68015- if err != nil { 68016- return nil, nil, err 68017- } 68018- 68019- // Deep search collected candidates and their members for more candidates. 68020- c.deepSearch(ctx) 68021- 68022- for _, callback := range c.completionCallbacks { 68023- if err := c.snapshot.RunProcessEnvFunc(ctx, callback); err != nil { 68024- return nil, nil, err 68025- } 68026- } 68027- 68028- // Search candidates populated by expensive operations like 68029- // unimportedMembers etc. for more completion items. 68030- c.deepSearch(ctx) 68031- 68032- // Statement candidates offer an entire statement in certain contexts, as 68033- // opposed to a single object. Add statement candidates last because they 68034- // depend on other candidates having already been collected. 68035- c.addStatementCandidates() 68036- 68037- c.sortItems() 68038- return c.items, c.getSurrounding(), nil 68039-} 68040- 68041-// collectCompletions adds possible completion candidates to either the deep 68042-// search queue or completion items directly for different completion contexts. 68043-func (c *completer) collectCompletions(ctx context.Context) error { 68044- // Inside import blocks, return completions for unimported packages. 68045- for _, importSpec := range c.file.Imports { 68046- if !(importSpec.Path.Pos() <= c.pos && c.pos <= importSpec.Path.End()) { 68047- continue 68048- } 68049- return c.populateImportCompletions(ctx, importSpec) 68050- } 68051- 68052- // Inside comments, offer completions for the name of the relevant symbol. 68053- for _, comment := range c.file.Comments { 68054- if comment.Pos() < c.pos && c.pos <= comment.End() { 68055- c.populateCommentCompletions(ctx, comment) 68056- return nil 68057- } 68058- } 68059- 68060- // Struct literals are handled entirely separately. 68061- if c.wantStructFieldCompletions() { 68062- // If we are definitely completing a struct field name, deep completions 68063- // don't make sense. 68064- if c.enclosingCompositeLiteral.inKey { 68065- c.deepState.enabled = false 68066- } 68067- return c.structLiteralFieldName(ctx) 68068- } 68069- 68070- if lt := c.wantLabelCompletion(); lt != labelNone { 68071- c.labels(lt) 68072- return nil 68073- } 68074- 68075- if c.emptySwitchStmt() { 68076- // Empty switch statements only admit "default" and "case" keywords. 68077- c.addKeywordItems(map[string]bool{}, highScore, CASE, DEFAULT) 68078- return nil 68079- } 68080- 68081- switch n := c.path[0].(type) { 68082- case *ast.Ident: 68083- if c.file.Name == n { 68084- return c.packageNameCompletions(ctx, c.fh.URI(), n) 68085- } else if sel, ok := c.path[1].(*ast.SelectorExpr); ok && sel.Sel == n { 68086- // Is this the Sel part of a selector? 68087- return c.selector(ctx, sel) 68088- } 68089- return c.lexical(ctx) 68090- // The function name hasn't been typed yet, but the parens are there: 68091- // recv.‸(arg) 68092- case *ast.TypeAssertExpr: 68093- // Create a fake selector expression. 68094- return c.selector(ctx, &ast.SelectorExpr{X: n.X}) 68095- case *ast.SelectorExpr: 68096- return c.selector(ctx, n) 68097- // At the file scope, only keywords are allowed. 68098- case *ast.BadDecl, *ast.File: 68099- c.addKeywordCompletions() 68100- default: 68101- // fallback to lexical completions 68102- return c.lexical(ctx) 68103- } 68104- 68105- return nil 68106-} 68107- 68108-// containingIdent returns the *ast.Ident containing pos, if any. It 68109-// synthesizes an *ast.Ident to allow completion in the face of 68110-// certain syntax errors. 68111-func (c *completer) containingIdent(src []byte) *ast.Ident { 68112- // In the normal case, our leaf AST node is the identifier being completed. 68113- if ident, ok := c.path[0].(*ast.Ident); ok { 68114- return ident 68115- } 68116- 68117- pos, tkn, lit := c.scanToken(src) 68118- if !pos.IsValid() { 68119- return nil 68120- } 68121- 68122- fakeIdent := &ast.Ident{Name: lit, NamePos: pos} 68123- 68124- if _, isBadDecl := c.path[0].(*ast.BadDecl); isBadDecl { 68125- // You don't get *ast.Idents at the file level, so look for bad 68126- // decls and use the manually extracted token. 68127- return fakeIdent 68128- } else if c.emptySwitchStmt() { 68129- // Only keywords are allowed in empty switch statements. 68130- // *ast.Idents are not parsed, so we must use the manually 68131- // extracted token. 68132- return fakeIdent 68133- } else if tkn.IsKeyword() { 68134- // Otherwise, manually extract the prefix if our containing token 68135- // is a keyword. This improves completion after an "accidental 68136- // keyword", e.g. completing to "variance" in "someFunc(var<>)". 68137- return fakeIdent 68138- } 68139- 68140- return nil 68141-} 68142- 68143-// scanToken scans pgh's contents for the token containing pos. 68144-func (c *completer) scanToken(contents []byte) (token.Pos, token.Token, string) { 68145- tok := c.pkg.FileSet().File(c.pos) 68146- 68147- var s scanner.Scanner 68148- s.Init(tok, contents, nil, 0) 68149- for { 68150- tknPos, tkn, lit := s.Scan() 68151- if tkn == token.EOF || tknPos >= c.pos { 68152- return token.NoPos, token.ILLEGAL, "" 68153- } 68154- 68155- if len(lit) > 0 && tknPos <= c.pos && c.pos <= tknPos+token.Pos(len(lit)) { 68156- return tknPos, tkn, lit 68157- } 68158- } 68159-} 68160- 68161-func (c *completer) sortItems() { 68162- sort.SliceStable(c.items, func(i, j int) bool { 68163- // Sort by score first. 68164- if c.items[i].Score != c.items[j].Score { 68165- return c.items[i].Score > c.items[j].Score 68166- } 68167- 68168- // Then sort by label so order stays consistent. This also has the 68169- // effect of preferring shorter candidates. 68170- return c.items[i].Label < c.items[j].Label 68171- }) 68172-} 68173- 68174-// emptySwitchStmt reports whether pos is in an empty switch or select 68175-// statement. 68176-func (c *completer) emptySwitchStmt() bool { 68177- block, ok := c.path[0].(*ast.BlockStmt) 68178- if !ok || len(block.List) > 0 || len(c.path) == 1 { 68179- return false 68180- } 68181- 68182- switch c.path[1].(type) { 68183- case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt: 68184- return true 68185- default: 68186- return false 68187- } 68188-} 68189- 68190-// populateImportCompletions yields completions for an import path around the cursor. 68191-// 68192-// Completions are suggested at the directory depth of the given import path so 68193-// that we don't overwhelm the user with a large list of possibilities. As an 68194-// example, a completion for the prefix "golang" results in "golang.org/". 68195-// Completions for "golang.org/" yield its subdirectories 68196-// (i.e. "golang.org/x/"). The user is meant to accept completion suggestions 68197-// until they reach a complete import path. 68198-func (c *completer) populateImportCompletions(ctx context.Context, searchImport *ast.ImportSpec) error { 68199- if !strings.HasPrefix(searchImport.Path.Value, `"`) { 68200- return nil 68201- } 68202- 68203- // deepSearch is not valuable for import completions. 68204- c.deepState.enabled = false 68205- 68206- importPath := searchImport.Path.Value 68207- 68208- // Extract the text between the quotes (if any) in an import spec. 68209- // prefix is the part of import path before the cursor. 68210- prefixEnd := c.pos - searchImport.Path.Pos() 68211- prefix := strings.Trim(importPath[:prefixEnd], `"`) 68212- 68213- // The number of directories in the import path gives us the depth at 68214- // which to search. 68215- depth := len(strings.Split(prefix, "/")) - 1 68216- 68217- content := importPath 68218- start, end := searchImport.Path.Pos(), searchImport.Path.End() 68219- namePrefix, nameSuffix := `"`, `"` 68220- // If a starting quote is present, adjust surrounding to either after the 68221- // cursor or after the first slash (/), except if cursor is at the starting 68222- // quote. Otherwise we provide a completion including the starting quote. 68223- if strings.HasPrefix(importPath, `"`) && c.pos > searchImport.Path.Pos() { 68224- content = content[1:] 68225- start++ 68226- if depth > 0 { 68227- // Adjust textEdit start to replacement range. For ex: if current 68228- // path was "golang.or/x/to<>ols/internal/", where <> is the cursor 68229- // position, start of the replacement range would be after 68230- // "golang.org/x/". 68231- path := strings.SplitAfter(prefix, "/") 68232- numChars := len(strings.Join(path[:len(path)-1], "")) 68233- content = content[numChars:] 68234- start += token.Pos(numChars) 68235- } 68236- namePrefix = "" 68237- } 68238- 68239- // We won't provide an ending quote if one is already present, except if 68240- // cursor is after the ending quote but still in import spec. This is 68241- // because cursor has to be in our textEdit range. 68242- if strings.HasSuffix(importPath, `"`) && c.pos < searchImport.Path.End() { 68243- end-- 68244- content = content[:len(content)-1] 68245- nameSuffix = "" 68246- } 68247- 68248- c.surrounding = &Selection{ 68249- content: content, 68250- cursor: c.pos, 68251- tokFile: c.tokFile, 68252- start: start, 68253- end: end, 68254- mapper: c.mapper, 68255- } 68256- 68257- seenImports := make(map[string]struct{}) 68258- for _, importSpec := range c.file.Imports { 68259- if importSpec.Path.Value == importPath { 68260- continue 68261- } 68262- seenImportPath, err := strconv.Unquote(importSpec.Path.Value) 68263- if err != nil { 68264- return err 68265- } 68266- seenImports[seenImportPath] = struct{}{} 68267- } 68268- 68269- var mu sync.Mutex // guard c.items locally, since searchImports is called in parallel 68270- seen := make(map[string]struct{}) 68271- searchImports := func(pkg imports.ImportFix) { 68272- path := pkg.StmtInfo.ImportPath 68273- if _, ok := seenImports[path]; ok { 68274- return 68275- } 68276- 68277- // Any package path containing fewer directories than the search 68278- // prefix is not a match. 68279- pkgDirList := strings.Split(path, "/") 68280- if len(pkgDirList) < depth+1 { 68281- return 68282- } 68283- pkgToConsider := strings.Join(pkgDirList[:depth+1], "/") 68284- 68285- name := pkgDirList[depth] 68286- // if we're adding an opening quote to completion too, set name to full 68287- // package path since we'll need to overwrite that range. 68288- if namePrefix == `"` { 68289- name = pkgToConsider 68290- } 68291- 68292- score := pkg.Relevance 68293- if len(pkgDirList)-1 == depth { 68294- score *= highScore 68295- } else { 68296- // For incomplete package paths, add a terminal slash to indicate that the 68297- // user should keep triggering completions. 68298- name += "/" 68299- pkgToConsider += "/" 68300- } 68301- 68302- if _, ok := seen[pkgToConsider]; ok { 68303- return 68304- } 68305- seen[pkgToConsider] = struct{}{} 68306- 68307- mu.Lock() 68308- defer mu.Unlock() 68309- 68310- name = namePrefix + name + nameSuffix 68311- obj := types.NewPkgName(0, nil, name, types.NewPackage(pkgToConsider, name)) 68312- c.deepState.enqueue(candidate{ 68313- obj: obj, 68314- detail: fmt.Sprintf("%q", pkgToConsider), 68315- score: score, 68316- }) 68317- } 68318- 68319- c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error { 68320- return imports.GetImportPaths(ctx, searchImports, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env) 68321- }) 68322- return nil 68323-} 68324- 68325-// populateCommentCompletions yields completions for comments preceding or in declarations. 68326-func (c *completer) populateCommentCompletions(ctx context.Context, comment *ast.CommentGroup) { 68327- // If the completion was triggered by a period, ignore it. These types of 68328- // completions will not be useful in comments. 68329- if c.completionContext.triggerCharacter == "." { 68330- return 68331- } 68332- 68333- // Using the comment position find the line after 68334- file := c.pkg.FileSet().File(comment.End()) 68335- if file == nil { 68336- return 68337- } 68338- 68339- // Deep completion doesn't work properly in comments since we don't 68340- // have a type object to complete further. 68341- c.deepState.enabled = false 68342- c.completionContext.commentCompletion = true 68343- 68344- // Documentation isn't useful in comments, since it might end up being the 68345- // comment itself. 68346- c.opts.documentation = false 68347- 68348- commentLine := file.Line(comment.End()) 68349- 68350- // comment is valid, set surrounding as word boundaries around cursor 68351- c.setSurroundingForComment(comment) 68352- 68353- // Using the next line pos, grab and parse the exported symbol on that line 68354- for _, n := range c.file.Decls { 68355- declLine := file.Line(n.Pos()) 68356- // if the comment is not in, directly above or on the same line as a declaration 68357- if declLine != commentLine && declLine != commentLine+1 && 68358- !(n.Pos() <= comment.Pos() && comment.End() <= n.End()) { 68359- continue 68360- } 68361- switch node := n.(type) { 68362- // handle const, vars, and types 68363- case *ast.GenDecl: 68364- for _, spec := range node.Specs { 68365- switch spec := spec.(type) { 68366- case *ast.ValueSpec: 68367- for _, name := range spec.Names { 68368- if name.String() == "_" { 68369- continue 68370- } 68371- obj := c.pkg.GetTypesInfo().ObjectOf(name) 68372- c.deepState.enqueue(candidate{obj: obj, score: stdScore}) 68373- } 68374- case *ast.TypeSpec: 68375- // add TypeSpec fields to completion 68376- switch typeNode := spec.Type.(type) { 68377- case *ast.StructType: 68378- c.addFieldItems(ctx, typeNode.Fields) 68379- case *ast.FuncType: 68380- c.addFieldItems(ctx, typeNode.Params) 68381- c.addFieldItems(ctx, typeNode.Results) 68382- case *ast.InterfaceType: 68383- c.addFieldItems(ctx, typeNode.Methods) 68384- } 68385- 68386- if spec.Name.String() == "_" { 68387- continue 68388- } 68389- 68390- obj := c.pkg.GetTypesInfo().ObjectOf(spec.Name) 68391- // Type name should get a higher score than fields but not highScore by default 68392- // since field near a comment cursor gets a highScore 68393- score := stdScore * 1.1 68394- // If type declaration is on the line after comment, give it a highScore. 68395- if declLine == commentLine+1 { 68396- score = highScore 68397- } 68398- 68399- c.deepState.enqueue(candidate{obj: obj, score: score}) 68400- } 68401- } 68402- // handle functions 68403- case *ast.FuncDecl: 68404- c.addFieldItems(ctx, node.Recv) 68405- c.addFieldItems(ctx, node.Type.Params) 68406- c.addFieldItems(ctx, node.Type.Results) 68407- 68408- // collect receiver struct fields 68409- if node.Recv != nil { 68410- for _, fields := range node.Recv.List { 68411- for _, name := range fields.Names { 68412- obj := c.pkg.GetTypesInfo().ObjectOf(name) 68413- if obj == nil { 68414- continue 68415- } 68416- 68417- recvType := obj.Type().Underlying() 68418- if ptr, ok := recvType.(*types.Pointer); ok { 68419- recvType = ptr.Elem() 68420- } 68421- recvStruct, ok := recvType.Underlying().(*types.Struct) 68422- if !ok { 68423- continue 68424- } 68425- for i := 0; i < recvStruct.NumFields(); i++ { 68426- field := recvStruct.Field(i) 68427- c.deepState.enqueue(candidate{obj: field, score: lowScore}) 68428- } 68429- } 68430- } 68431- } 68432- 68433- if node.Name.String() == "_" { 68434- continue 68435- } 68436- 68437- obj := c.pkg.GetTypesInfo().ObjectOf(node.Name) 68438- if obj == nil || obj.Pkg() != nil && obj.Pkg() != c.pkg.GetTypes() { 68439- continue 68440- } 68441- 68442- c.deepState.enqueue(candidate{obj: obj, score: highScore}) 68443- } 68444- } 68445-} 68446- 68447-// sets word boundaries surrounding a cursor for a comment 68448-func (c *completer) setSurroundingForComment(comments *ast.CommentGroup) { 68449- var cursorComment *ast.Comment 68450- for _, comment := range comments.List { 68451- if c.pos >= comment.Pos() && c.pos <= comment.End() { 68452- cursorComment = comment 68453- break 68454- } 68455- } 68456- // if cursor isn't in the comment 68457- if cursorComment == nil { 68458- return 68459- } 68460- 68461- // index of cursor in comment text 68462- cursorOffset := int(c.pos - cursorComment.Pos()) 68463- start, end := cursorOffset, cursorOffset 68464- for start > 0 && isValidIdentifierChar(cursorComment.Text[start-1]) { 68465- start-- 68466- } 68467- for end < len(cursorComment.Text) && isValidIdentifierChar(cursorComment.Text[end]) { 68468- end++ 68469- } 68470- 68471- c.surrounding = &Selection{ 68472- content: cursorComment.Text[start:end], 68473- cursor: c.pos, 68474- tokFile: c.tokFile, 68475- start: token.Pos(int(cursorComment.Slash) + start), 68476- end: token.Pos(int(cursorComment.Slash) + end), 68477- mapper: c.mapper, 68478- } 68479- c.setMatcherFromPrefix(c.surrounding.Prefix()) 68480-} 68481- 68482-// isValidIdentifierChar returns true if a byte is a valid go identifier 68483-// character, i.e. unicode letter or digit or underscore. 68484-func isValidIdentifierChar(char byte) bool { 68485- charRune := rune(char) 68486- return unicode.In(charRune, unicode.Letter, unicode.Digit) || char == '_' 68487-} 68488- 68489-// adds struct fields, interface methods, function declaration fields to completion 68490-func (c *completer) addFieldItems(ctx context.Context, fields *ast.FieldList) { 68491- if fields == nil { 68492- return 68493- } 68494- 68495- cursor := c.surrounding.cursor 68496- for _, field := range fields.List { 68497- for _, name := range field.Names { 68498- if name.String() == "_" { 68499- continue 68500- } 68501- obj := c.pkg.GetTypesInfo().ObjectOf(name) 68502- if obj == nil { 68503- continue 68504- } 68505- 68506- // if we're in a field comment/doc, score that field as more relevant 68507- score := stdScore 68508- if field.Comment != nil && field.Comment.Pos() <= cursor && cursor <= field.Comment.End() { 68509- score = highScore 68510- } else if field.Doc != nil && field.Doc.Pos() <= cursor && cursor <= field.Doc.End() { 68511- score = highScore 68512- } 68513- 68514- c.deepState.enqueue(candidate{obj: obj, score: score}) 68515- } 68516- } 68517-} 68518- 68519-func (c *completer) wantStructFieldCompletions() bool { 68520- clInfo := c.enclosingCompositeLiteral 68521- if clInfo == nil { 68522- return false 68523- } 68524- 68525- return clInfo.isStruct() && (clInfo.inKey || clInfo.maybeInFieldName) 68526-} 68527- 68528-func (c *completer) wantTypeName() bool { 68529- return !c.completionContext.commentCompletion && c.inference.typeName.wantTypeName 68530-} 68531- 68532-// See https://golang.org/issue/36001. Unimported completions are expensive. 68533-const ( 68534- maxUnimportedPackageNames = 5 68535- unimportedMemberTarget = 100 68536-) 68537- 68538-// selector finds completions for the specified selector expression. 68539-func (c *completer) selector(ctx context.Context, sel *ast.SelectorExpr) error { 68540- c.inference.objChain = objChain(c.pkg.GetTypesInfo(), sel.X) 68541- 68542- // True selector? 68543- if tv, ok := c.pkg.GetTypesInfo().Types[sel.X]; ok { 68544- c.methodsAndFields(tv.Type, tv.Addressable(), nil, c.deepState.enqueue) 68545- c.addPostfixSnippetCandidates(ctx, sel) 68546- return nil 68547- } 68548- 68549- id, ok := sel.X.(*ast.Ident) 68550- if !ok { 68551- return nil 68552- } 68553- 68554- // Treat sel as a qualified identifier. 68555- var filter func(*source.Metadata) bool 68556- needImport := false 68557- if pkgName, ok := c.pkg.GetTypesInfo().Uses[id].(*types.PkgName); ok { 68558- // Qualified identifier with import declaration. 68559- imp := pkgName.Imported() 68560- 68561- // Known direct dependency? Expand using type information. 68562- if _, ok := c.pkg.Metadata().DepsByPkgPath[source.PackagePath(imp.Path())]; ok { 68563- c.packageMembers(imp, stdScore, nil, c.deepState.enqueue) 68564- return nil 68565- } 68566- 68567- // Imported declaration with missing type information. 68568- // Fall through to shallow completion of unimported package members. 68569- // Match candidate packages by path. 68570- // TODO(adonovan): simplify by merging with else case and matching on name only? 68571- filter = func(m *source.Metadata) bool { 68572- return strings.TrimPrefix(string(m.PkgPath), "vendor/") == imp.Path() 68573- } 68574- } else { 68575- // Qualified identifier without import declaration. 68576- // Match candidate packages by name. 68577- filter = func(m *source.Metadata) bool { 68578- return string(m.Name) == id.Name 68579- } 68580- needImport = true 68581- } 68582- 68583- // Search unimported packages. 68584- if !c.opts.unimported { 68585- return nil // feature disabled 68586- } 68587- 68588- // The deep completion algorithm is exceedingly complex and 68589- // deeply coupled to the now obsolete notions that all 68590- // token.Pos values can be interpreted by as a single FileSet 68591- // belonging to the Snapshot and that all types.Object values 68592- // are canonicalized by a single types.Importer mapping. 68593- // These invariants are no longer true now that gopls uses 68594- // an incremental approach, parsing and type-checking each 68595- // package separately. 68596- // 68597- // Consequently, completion of symbols defined in packages that 68598- // are not currently imported by the query file cannot use the 68599- // deep completion machinery which is based on type information. 68600- // Instead it must use only syntax information from a quick 68601- // parse of top-level declarations (but not function bodies). 68602- // 68603- // TODO(adonovan): rewrite the deep completion machinery to 68604- // not assume global Pos/Object realms and then use export 68605- // data instead of the quick parse approach taken here. 68606- 68607- // First, we search among packages in the workspace. 68608- // We'll use a fast parse to extract package members 68609- // from those that match the name/path criterion. 68610- all, err := c.snapshot.AllMetadata(ctx) 68611- if err != nil { 68612- return err 68613- } 68614- var paths []string 68615- known := make(map[source.PackagePath][]*source.Metadata) // may include test variant 68616- for _, m := range all { 68617- if m.IsIntermediateTestVariant() || m.Name == "main" || !filter(m) { 68618- continue 68619- } 68620- known[m.PkgPath] = append(known[m.PkgPath], m) 68621- paths = append(paths, string(m.PkgPath)) 68622- } 68623- 68624- // Rank import paths as goimports would. 68625- var relevances map[string]float64 68626- if len(paths) > 0 { 68627- if err := c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error { 68628- var err error 68629- relevances, err = imports.ScoreImportPaths(ctx, opts.Env, paths) 68630- return err 68631- }); err != nil { 68632- return err 68633- } 68634- sort.Slice(paths, func(i, j int) bool { 68635- return relevances[paths[i]] > relevances[paths[j]] 68636- }) 68637- } 68638- 68639- // quickParse does a quick parse of a single file of package m, 68640- // extracts exported package members and adds candidates to c.items. 68641- var itemsMu sync.Mutex // guards c.items 68642- var enough int32 // atomic bool 68643- quickParse := func(uri span.URI, m *source.Metadata) error { 68644- if atomic.LoadInt32(&enough) != 0 { 68645- return nil 68646- } 68647- 68648- fh, err := c.snapshot.GetFile(ctx, uri) 68649- if err != nil { 68650- return err 68651- } 68652- content, err := fh.Read() 68653- if err != nil { 68654- return err 68655- } 68656- path := string(m.PkgPath) 68657- forEachPackageMember(content, func(tok token.Token, id *ast.Ident, fn *ast.FuncDecl) { 68658- if atomic.LoadInt32(&enough) != 0 { 68659- return 68660- } 68661- 68662- if !id.IsExported() || 68663- sel.Sel.Name != "_" && !strings.HasPrefix(id.Name, sel.Sel.Name) { 68664- return // not a match 68665- } 68666- 68667- // The only detail is the kind and package: `var (from "example.com/foo")` 68668- // TODO(adonovan): pretty-print FuncDecl.FuncType or TypeSpec.Type? 68669- item := CompletionItem{ 68670- Label: id.Name, 68671- Detail: fmt.Sprintf("%s (from %q)", strings.ToLower(tok.String()), m.PkgPath), 68672- InsertText: id.Name, 68673- Score: unimportedScore(relevances[path]), 68674- } 68675- switch tok { 68676- case token.FUNC: 68677- item.Kind = protocol.FunctionCompletion 68678- case token.VAR: 68679- item.Kind = protocol.VariableCompletion 68680- case token.CONST: 68681- item.Kind = protocol.ConstantCompletion 68682- case token.TYPE: 68683- // Without types, we can't distinguish Class from Interface. 68684- item.Kind = protocol.ClassCompletion 68685- } 68686- 68687- if needImport { 68688- imp := &importInfo{importPath: path} 68689- if imports.ImportPathToAssumedName(path) != string(m.Name) { 68690- imp.name = string(m.Name) 68691- } 68692- item.AdditionalTextEdits, _ = c.importEdits(imp) 68693- } 68694- 68695- // For functions, add a parameter snippet. 68696- if fn != nil { 68697- var sn snippet.Builder 68698- sn.WriteText(id.Name) 68699- sn.WriteText("(") 68700- var nparams int 68701- for _, field := range fn.Type.Params.List { 68702- if field.Names != nil { 68703- nparams += len(field.Names) 68704- } else { 68705- nparams++ 68706- } 68707- } 68708- for i := 0; i < nparams; i++ { 68709- if i > 0 { 68710- sn.WriteText(", ") 68711- } 68712- sn.WritePlaceholder(nil) 68713- } 68714- sn.WriteText(")") 68715- item.snippet = &sn 68716- } 68717- 68718- itemsMu.Lock() 68719- c.items = append(c.items, item) 68720- if len(c.items) >= unimportedMemberTarget { 68721- atomic.StoreInt32(&enough, 1) 68722- } 68723- itemsMu.Unlock() 68724- }) 68725- return nil 68726- } 68727- 68728- // Extract the package-level candidates using a quick parse. 68729- var g errgroup.Group 68730- for _, path := range paths { 68731- for _, m := range known[source.PackagePath(path)] { 68732- m := m 68733- for _, uri := range m.CompiledGoFiles { 68734- uri := uri 68735- g.Go(func() error { 68736- return quickParse(uri, m) 68737- }) 68738- } 68739- } 68740- } 68741- if err := g.Wait(); err != nil { 68742- return err 68743- } 68744- 68745- // In addition, we search in the module cache using goimports. 68746- ctx, cancel := context.WithCancel(ctx) 68747- var mu sync.Mutex 68748- add := func(pkgExport imports.PackageExport) { 68749- mu.Lock() 68750- defer mu.Unlock() 68751- // TODO(adonovan): what if the actual package has a vendor/ prefix? 68752- if _, ok := known[source.PackagePath(pkgExport.Fix.StmtInfo.ImportPath)]; ok { 68753- return // We got this one above. 68754- } 68755- 68756- // Continue with untyped proposals. 68757- pkg := types.NewPackage(pkgExport.Fix.StmtInfo.ImportPath, pkgExport.Fix.IdentName) 68758- for _, export := range pkgExport.Exports { 68759- score := unimportedScore(pkgExport.Fix.Relevance) 68760- c.deepState.enqueue(candidate{ 68761- obj: types.NewVar(0, pkg, export, nil), 68762- score: score, 68763- imp: &importInfo{ 68764- importPath: pkgExport.Fix.StmtInfo.ImportPath, 68765- name: pkgExport.Fix.StmtInfo.Name, 68766- }, 68767- }) 68768- } 68769- if len(c.items) >= unimportedMemberTarget { 68770- cancel() 68771- } 68772- } 68773- 68774- c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error { 68775- defer cancel() 68776- return imports.GetPackageExports(ctx, add, id.Name, c.filename, c.pkg.GetTypes().Name(), opts.Env) 68777- }) 68778- return nil 68779-} 68780- 68781-// unimportedScore returns a score for an unimported package that is generally 68782-// lower than other candidates. 68783-func unimportedScore(relevance float64) float64 { 68784- return (stdScore + .1*relevance) / 2 68785-} 68786- 68787-func (c *completer) packageMembers(pkg *types.Package, score float64, imp *importInfo, cb func(candidate)) { 68788- scope := pkg.Scope() 68789- for _, name := range scope.Names() { 68790- obj := scope.Lookup(name) 68791- cb(candidate{ 68792- obj: obj, 68793- score: score, 68794- imp: imp, 68795- addressable: isVar(obj), 68796- }) 68797- } 68798-} 68799- 68800-func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *importInfo, cb func(candidate)) { 68801- mset := c.methodSetCache[methodSetKey{typ, addressable}] 68802- if mset == nil { 68803- if addressable && !types.IsInterface(typ) && !isPointer(typ) { 68804- // Add methods of *T, which includes methods with receiver T. 68805- mset = types.NewMethodSet(types.NewPointer(typ)) 68806- } else { 68807- // Add methods of T. 68808- mset = types.NewMethodSet(typ) 68809- } 68810- c.methodSetCache[methodSetKey{typ, addressable}] = mset 68811- } 68812- 68813- if isStarTestingDotF(typ) && addressable { 68814- // is that a sufficient test? (or is more care needed?) 68815- if c.fuzz(typ, mset, imp, cb, c.pkg.FileSet()) { 68816- return 68817- } 68818- } 68819- 68820- for i := 0; i < mset.Len(); i++ { 68821- cb(candidate{ 68822- obj: mset.At(i).Obj(), 68823- score: stdScore, 68824- imp: imp, 68825- addressable: addressable || isPointer(typ), 68826- }) 68827- } 68828- 68829- // Add fields of T. 68830- eachField(typ, func(v *types.Var) { 68831- cb(candidate{ 68832- obj: v, 68833- score: stdScore - 0.01, 68834- imp: imp, 68835- addressable: addressable || isPointer(typ), 68836- }) 68837- }) 68838-} 68839- 68840-// isStarTestingDotF reports whether typ is *testing.F. 68841-func isStarTestingDotF(typ types.Type) bool { 68842- ptr, _ := typ.(*types.Pointer) 68843- if ptr == nil { 68844- return false 68845- } 68846- named, _ := ptr.Elem().(*types.Named) 68847- if named == nil { 68848- return false 68849- } 68850- obj := named.Obj() 68851- // obj.Pkg is nil for the error type. 68852- return obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "testing" && obj.Name() == "F" 68853-} 68854- 68855-// lexical finds completions in the lexical environment. 68856-func (c *completer) lexical(ctx context.Context) error { 68857- var ( 68858- builtinIota = types.Universe.Lookup("iota") 68859- builtinNil = types.Universe.Lookup("nil") 68860- 68861- // TODO(rfindley): only allow "comparable" where it is valid (in constraint 68862- // position or embedded in interface declarations). 68863- // builtinComparable = types.Universe.Lookup("comparable") 68864- ) 68865- 68866- // Track seen variables to avoid showing completions for shadowed variables. 68867- // This works since we look at scopes from innermost to outermost. 68868- seen := make(map[string]struct{}) 68869- 68870- // Process scopes innermost first. 68871- for i, scope := range c.scopes { 68872- if scope == nil { 68873- continue 68874- } 68875- 68876- Names: 68877- for _, name := range scope.Names() { 68878- declScope, obj := scope.LookupParent(name, c.pos) 68879- if declScope != scope { 68880- continue // Name was declared in some enclosing scope, or not at all. 68881- } 68882- 68883- // If obj's type is invalid, find the AST node that defines the lexical block 68884- // containing the declaration of obj. Don't resolve types for packages. 68885- if !isPkgName(obj) && !typeIsValid(obj.Type()) { 68886- // Match the scope to its ast.Node. If the scope is the package scope, 68887- // use the *ast.File as the starting node. 68888- var node ast.Node 68889- if i < len(c.path) { 68890- node = c.path[i] 68891- } else if i == len(c.path) { // use the *ast.File for package scope 68892- node = c.path[i-1] 68893- } 68894- if node != nil { 68895- if resolved := resolveInvalid(c.pkg.FileSet(), obj, node, c.pkg.GetTypesInfo()); resolved != nil { 68896- obj = resolved 68897- } 68898- } 68899- } 68900- 68901- // Don't use LHS of decl in RHS. 68902- for _, ident := range enclosingDeclLHS(c.path) { 68903- if obj.Pos() == ident.Pos() { 68904- continue Names 68905- } 68906- } 68907- 68908- // Don't suggest "iota" outside of const decls. 68909- if obj == builtinIota && !c.inConstDecl() { 68910- continue 68911- } 68912- 68913- // Rank outer scopes lower than inner. 68914- score := stdScore * math.Pow(.99, float64(i)) 68915- 68916- // Dowrank "nil" a bit so it is ranked below more interesting candidates. 68917- if obj == builtinNil { 68918- score /= 2 68919- } 68920- 68921- // If we haven't already added a candidate for an object with this name. 68922- if _, ok := seen[obj.Name()]; !ok { 68923- seen[obj.Name()] = struct{}{} 68924- c.deepState.enqueue(candidate{ 68925- obj: obj, 68926- score: score, 68927- addressable: isVar(obj), 68928- }) 68929- } 68930- } 68931- } 68932- 68933- if c.inference.objType != nil { 68934- if named, _ := source.Deref(c.inference.objType).(*types.Named); named != nil { 68935- // If we expected a named type, check the type's package for 68936- // completion items. This is useful when the current file hasn't 68937- // imported the type's package yet. 68938- 68939- if named.Obj() != nil && named.Obj().Pkg() != nil { 68940- pkg := named.Obj().Pkg() 68941- 68942- // Make sure the package name isn't already in use by another 68943- // object, and that this file doesn't import the package yet. 68944- // TODO(adonovan): what if pkg.Path has vendor/ prefix? 68945- if _, ok := seen[pkg.Name()]; !ok && pkg != c.pkg.GetTypes() && !alreadyImports(c.file, source.ImportPath(pkg.Path())) { 68946- seen[pkg.Name()] = struct{}{} 68947- obj := types.NewPkgName(0, nil, pkg.Name(), pkg) 68948- imp := &importInfo{ 68949- importPath: pkg.Path(), 68950- } 68951- if imports.ImportPathToAssumedName(pkg.Path()) != pkg.Name() { 68952- imp.name = pkg.Name() 68953- } 68954- c.deepState.enqueue(candidate{ 68955- obj: obj, 68956- score: stdScore, 68957- imp: imp, 68958- }) 68959- } 68960- } 68961- } 68962- } 68963- 68964- if c.opts.unimported { 68965- if err := c.unimportedPackages(ctx, seen); err != nil { 68966- return err 68967- } 68968- } 68969- 68970- if c.inference.typeName.isTypeParam { 68971- // If we are completing a type param, offer each structural type. 68972- // This ensures we suggest "[]int" and "[]float64" for a constraint 68973- // with type union "[]int | []float64". 68974- if t, _ := c.inference.objType.(*types.Interface); t != nil { 68975- terms, _ := typeparams.InterfaceTermSet(t) 68976- for _, term := range terms { 68977- c.injectType(ctx, term.Type()) 68978- } 68979- } 68980- } else { 68981- c.injectType(ctx, c.inference.objType) 68982- } 68983- 68984- // Add keyword completion items appropriate in the current context. 68985- c.addKeywordCompletions() 68986- 68987- return nil 68988-} 68989- 68990-// injectType manufactures candidates based on the given type. This is 68991-// intended for types not discoverable via lexical search, such as 68992-// composite and/or generic types. For example, if the type is "[]int", 68993-// this method makes sure you get candidates "[]int{}" and "[]int" 68994-// (the latter applies when completing a type name). 68995-func (c *completer) injectType(ctx context.Context, t types.Type) { 68996- if t == nil { 68997- return 68998- } 68999- 69000- t = source.Deref(t) 69001- 69002- // If we have an expected type and it is _not_ a named type, handle 69003- // it specially. Non-named types like "[]int" will never be 69004- // considered via a lexical search, so we need to directly inject 69005- // them. Also allow generic types since lexical search does not 69006- // infer instantiated versions of them. 69007- if named, _ := t.(*types.Named); named == nil || typeparams.ForNamed(named).Len() > 0 { 69008- // If our expected type is "[]int", this will add a literal 69009- // candidate of "[]int{}". 69010- c.literal(ctx, t, nil) 69011- 69012- if _, isBasic := t.(*types.Basic); !isBasic { 69013- // If we expect a non-basic type name (e.g. "[]int"), hack up 69014- // a named type whose name is literally "[]int". This allows 69015- // us to reuse our object based completion machinery. 69016- fakeNamedType := candidate{ 69017- obj: types.NewTypeName(token.NoPos, nil, types.TypeString(t, c.qf), t), 69018- score: stdScore, 69019- } 69020- // Make sure the type name matches before considering 69021- // candidate. This cuts down on useless candidates. 69022- if c.matchingTypeName(&fakeNamedType) { 69023- c.deepState.enqueue(fakeNamedType) 69024- } 69025- } 69026- } 69027-} 69028- 69029-func (c *completer) unimportedPackages(ctx context.Context, seen map[string]struct{}) error { 69030- var prefix string 69031- if c.surrounding != nil { 69032- prefix = c.surrounding.Prefix() 69033- } 69034- 69035- // Don't suggest unimported packages if we have absolutely nothing 69036- // to go on. 69037- if prefix == "" { 69038- return nil 69039- } 69040- 69041- count := 0 69042- 69043- // Search packages across the entire workspace. 69044- all, err := c.snapshot.AllMetadata(ctx) 69045- if err != nil { 69046- return err 69047- } 69048- pkgNameByPath := make(map[source.PackagePath]string) 69049- var paths []string // actually PackagePaths 69050- for _, m := range all { 69051- if m.ForTest != "" { 69052- continue // skip all test variants 69053- } 69054- if m.Name == "main" { 69055- continue // main is non-importable 69056- } 69057- if !strings.HasPrefix(string(m.Name), prefix) { 69058- continue // not a match 69059- } 69060- paths = append(paths, string(m.PkgPath)) 69061- pkgNameByPath[m.PkgPath] = string(m.Name) 69062- } 69063- 69064- // Rank candidates using goimports' algorithm. 69065- var relevances map[string]float64 69066- if len(paths) != 0 { 69067- if err := c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error { 69068- var err error 69069- relevances, err = imports.ScoreImportPaths(ctx, opts.Env, paths) 69070- return err 69071- }); err != nil { 69072- return err 69073- } 69074- } 69075- sort.Slice(paths, func(i, j int) bool { 69076- if relevances[paths[i]] != relevances[paths[j]] { 69077- return relevances[paths[i]] > relevances[paths[j]] 69078- } 69079- 69080- // Fall back to lexical sort to keep truncated set of candidates 69081- // in a consistent order. 69082- return paths[i] < paths[j] 69083- }) 69084- 69085- for _, path := range paths { 69086- name := pkgNameByPath[source.PackagePath(path)] 69087- if _, ok := seen[name]; ok { 69088- continue 69089- } 69090- imp := &importInfo{ 69091- importPath: path, 69092- } 69093- if imports.ImportPathToAssumedName(path) != name { 69094- imp.name = name 69095- } 69096- if count >= maxUnimportedPackageNames { 69097- return nil 69098- } 69099- c.deepState.enqueue(candidate{ 69100- // Pass an empty *types.Package to disable deep completions. 69101- obj: types.NewPkgName(0, nil, name, types.NewPackage(path, name)), 69102- score: unimportedScore(relevances[path]), 69103- imp: imp, 69104- }) 69105- count++ 69106- } 69107- 69108- ctx, cancel := context.WithCancel(ctx) 69109- 69110- var mu sync.Mutex 69111- add := func(pkg imports.ImportFix) { 69112- mu.Lock() 69113- defer mu.Unlock() 69114- if _, ok := seen[pkg.IdentName]; ok { 69115- return 69116- } 69117- if _, ok := relevances[pkg.StmtInfo.ImportPath]; ok { 69118- return 69119- } 69120- 69121- if count >= maxUnimportedPackageNames { 69122- cancel() 69123- return 69124- } 69125- 69126- // Do not add the unimported packages to seen, since we can have 69127- // multiple packages of the same name as completion suggestions, since 69128- // only one will be chosen. 69129- obj := types.NewPkgName(0, nil, pkg.IdentName, types.NewPackage(pkg.StmtInfo.ImportPath, pkg.IdentName)) 69130- c.deepState.enqueue(candidate{ 69131- obj: obj, 69132- score: unimportedScore(pkg.Relevance), 69133- imp: &importInfo{ 69134- importPath: pkg.StmtInfo.ImportPath, 69135- name: pkg.StmtInfo.Name, 69136- }, 69137- }) 69138- count++ 69139- } 69140- c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error { 69141- defer cancel() 69142- return imports.GetAllCandidates(ctx, add, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env) 69143- }) 69144- return nil 69145-} 69146- 69147-// alreadyImports reports whether f has an import with the specified path. 69148-func alreadyImports(f *ast.File, path source.ImportPath) bool { 69149- for _, s := range f.Imports { 69150- if source.UnquoteImportPath(s) == path { 69151- return true 69152- } 69153- } 69154- return false 69155-} 69156- 69157-func (c *completer) inConstDecl() bool { 69158- for _, n := range c.path { 69159- if decl, ok := n.(*ast.GenDecl); ok && decl.Tok == token.CONST { 69160- return true 69161- } 69162- } 69163- return false 69164-} 69165- 69166-// structLiteralFieldName finds completions for struct field names inside a struct literal. 69167-func (c *completer) structLiteralFieldName(ctx context.Context) error { 69168- clInfo := c.enclosingCompositeLiteral 69169- 69170- // Mark fields of the composite literal that have already been set, 69171- // except for the current field. 69172- addedFields := make(map[*types.Var]bool) 69173- for _, el := range clInfo.cl.Elts { 69174- if kvExpr, ok := el.(*ast.KeyValueExpr); ok { 69175- if clInfo.kv == kvExpr { 69176- continue 69177- } 69178- 69179- if key, ok := kvExpr.Key.(*ast.Ident); ok { 69180- if used, ok := c.pkg.GetTypesInfo().Uses[key]; ok { 69181- if usedVar, ok := used.(*types.Var); ok { 69182- addedFields[usedVar] = true 69183- } 69184- } 69185- } 69186- } 69187- } 69188- 69189- deltaScore := 0.0001 69190- switch t := clInfo.clType.(type) { 69191- case *types.Struct: 69192- for i := 0; i < t.NumFields(); i++ { 69193- field := t.Field(i) 69194- if !addedFields[field] { 69195- c.deepState.enqueue(candidate{ 69196- obj: field, 69197- score: highScore - float64(i)*deltaScore, 69198- }) 69199- } 69200- } 69201- 69202- // Add lexical completions if we aren't certain we are in the key part of a 69203- // key-value pair. 69204- if clInfo.maybeInFieldName { 69205- return c.lexical(ctx) 69206- } 69207- default: 69208- return c.lexical(ctx) 69209- } 69210- 69211- return nil 69212-} 69213- 69214-func (cl *compLitInfo) isStruct() bool { 69215- _, ok := cl.clType.(*types.Struct) 69216- return ok 69217-} 69218- 69219-// enclosingCompositeLiteral returns information about the composite literal enclosing the 69220-// position. 69221-func enclosingCompositeLiteral(path []ast.Node, pos token.Pos, info *types.Info) *compLitInfo { 69222- for _, n := range path { 69223- switch n := n.(type) { 69224- case *ast.CompositeLit: 69225- // The enclosing node will be a composite literal if the user has just 69226- // opened the curly brace (e.g. &x{<>) or the completion request is triggered 69227- // from an already completed composite literal expression (e.g. &x{foo: 1, <>}) 69228- // 69229- // The position is not part of the composite literal unless it falls within the 69230- // curly braces (e.g. "foo.Foo<>Struct{}"). 69231- if !(n.Lbrace < pos && pos <= n.Rbrace) { 69232- // Keep searching since we may yet be inside a composite literal. 69233- // For example "Foo{B: Ba<>{}}". 69234- break 69235- } 69236- 69237- tv, ok := info.Types[n] 69238- if !ok { 69239- return nil 69240- } 69241- 69242- clInfo := compLitInfo{ 69243- cl: n, 69244- clType: source.Deref(tv.Type).Underlying(), 69245- } 69246- 69247- var ( 69248- expr ast.Expr 69249- hasKeys bool 69250- ) 69251- for _, el := range n.Elts { 69252- // Remember the expression that the position falls in, if any. 69253- if el.Pos() <= pos && pos <= el.End() { 69254- expr = el 69255- } 69256- 69257- if kv, ok := el.(*ast.KeyValueExpr); ok { 69258- hasKeys = true 69259- // If expr == el then we know the position falls in this expression, 69260- // so also record kv as the enclosing *ast.KeyValueExpr. 69261- if expr == el { 69262- clInfo.kv = kv 69263- break 69264- } 69265- } 69266- } 69267- 69268- if clInfo.kv != nil { 69269- // If in a *ast.KeyValueExpr, we know we are in the key if the position 69270- // is to the left of the colon (e.g. "Foo{F<>: V}". 69271- clInfo.inKey = pos <= clInfo.kv.Colon 69272- } else if hasKeys { 69273- // If we aren't in a *ast.KeyValueExpr but the composite literal has 69274- // other *ast.KeyValueExprs, we must be on the key side of a new 69275- // *ast.KeyValueExpr (e.g. "Foo{F: V, <>}"). 69276- clInfo.inKey = true 69277- } else { 69278- switch clInfo.clType.(type) { 69279- case *types.Struct: 69280- if len(n.Elts) == 0 { 69281- // If the struct literal is empty, next could be a struct field 69282- // name or an expression (e.g. "Foo{<>}" could become "Foo{F:}" 69283- // or "Foo{someVar}"). 69284- clInfo.maybeInFieldName = true 69285- } else if len(n.Elts) == 1 { 69286- // If there is one expression and the position is in that expression 69287- // and the expression is an identifier, we may be writing a field 69288- // name or an expression (e.g. "Foo{F<>}"). 69289- _, clInfo.maybeInFieldName = expr.(*ast.Ident) 69290- } 69291- case *types.Map: 69292- // If we aren't in a *ast.KeyValueExpr we must be adding a new key 69293- // to the map. 69294- clInfo.inKey = true 69295- } 69296- } 69297- 69298- return &clInfo 69299- default: 69300- if breaksExpectedTypeInference(n, pos) { 69301- return nil 69302- } 69303- } 69304- } 69305- 69306- return nil 69307-} 69308- 69309-// enclosingFunction returns the signature and body of the function 69310-// enclosing the given position. 69311-func enclosingFunction(path []ast.Node, info *types.Info) *funcInfo { 69312- for _, node := range path { 69313- switch t := node.(type) { 69314- case *ast.FuncDecl: 69315- if obj, ok := info.Defs[t.Name]; ok { 69316- return &funcInfo{ 69317- sig: obj.Type().(*types.Signature), 69318- body: t.Body, 69319- } 69320- } 69321- case *ast.FuncLit: 69322- if typ, ok := info.Types[t]; ok { 69323- if sig, _ := typ.Type.(*types.Signature); sig == nil { 69324- // golang/go#49397: it should not be possible, but we somehow arrived 69325- // here with a non-signature type, most likely due to AST mangling 69326- // such that node.Type is not a FuncType. 69327- return nil 69328- } 69329- return &funcInfo{ 69330- sig: typ.Type.(*types.Signature), 69331- body: t.Body, 69332- } 69333- } 69334- } 69335- } 69336- return nil 69337-} 69338- 69339-func (c *completer) expectedCompositeLiteralType() types.Type { 69340- clInfo := c.enclosingCompositeLiteral 69341- switch t := clInfo.clType.(type) { 69342- case *types.Slice: 69343- if clInfo.inKey { 69344- return types.Typ[types.UntypedInt] 69345- } 69346- return t.Elem() 69347- case *types.Array: 69348- if clInfo.inKey { 69349- return types.Typ[types.UntypedInt] 69350- } 69351- return t.Elem() 69352- case *types.Map: 69353- if clInfo.inKey { 69354- return t.Key() 69355- } 69356- return t.Elem() 69357- case *types.Struct: 69358- // If we are completing a key (i.e. field name), there is no expected type. 69359- if clInfo.inKey { 69360- return nil 69361- } 69362- 69363- // If we are in a key-value pair, but not in the key, then we must be on the 69364- // value side. The expected type of the value will be determined from the key. 69365- if clInfo.kv != nil { 69366- if key, ok := clInfo.kv.Key.(*ast.Ident); ok { 69367- for i := 0; i < t.NumFields(); i++ { 69368- if field := t.Field(i); field.Name() == key.Name { 69369- return field.Type() 69370- } 69371- } 69372- } 69373- } else { 69374- // If we aren't in a key-value pair and aren't in the key, we must be using 69375- // implicit field names. 69376- 69377- // The order of the literal fields must match the order in the struct definition. 69378- // Find the element that the position belongs to and suggest that field's type. 69379- if i := exprAtPos(c.pos, clInfo.cl.Elts); i < t.NumFields() { 69380- return t.Field(i).Type() 69381- } 69382- } 69383- } 69384- return nil 69385-} 69386- 69387-// typeMod represents an operator that changes the expected type. 69388-type typeMod struct { 69389- mod typeModKind 69390- arrayLen int64 69391-} 69392- 69393-type typeModKind int 69394- 69395-const ( 69396- dereference typeModKind = iota // pointer indirection: "*" 69397- reference // adds level of pointer: "&" for values, "*" for type names 69398- chanRead // channel read operator: "<-" 69399- sliceType // make a slice type: "[]" in "[]int" 69400- arrayType // make an array type: "[2]" in "[2]int" 69401- invoke // make a function call: "()" in "foo()" 69402- takeSlice // take slice of array: "[:]" in "foo[:]" 69403- takeDotDotDot // turn slice into variadic args: "..." in "foo..." 69404- index // index into slice/array: "[0]" in "foo[0]" 69405-) 69406- 69407-type objKind int 69408- 69409-const ( 69410- kindAny objKind = 0 69411- kindArray objKind = 1 << iota 69412- kindSlice 69413- kindChan 69414- kindMap 69415- kindStruct 69416- kindString 69417- kindInt 69418- kindBool 69419- kindBytes 69420- kindPtr 69421- kindFloat 69422- kindComplex 69423- kindError 69424- kindStringer 69425- kindFunc 69426-) 69427- 69428-// penalizedObj represents an object that should be disfavored as a 69429-// completion candidate. 69430-type penalizedObj struct { 69431- // objChain is the full "chain", e.g. "foo.bar().baz" becomes 69432- // []types.Object{foo, bar, baz}. 69433- objChain []types.Object 69434- // penalty is score penalty in the range (0, 1). 69435- penalty float64 69436-} 69437- 69438-// candidateInference holds information we have inferred about a type that can be 69439-// used at the current position. 69440-type candidateInference struct { 69441- // objType is the desired type of an object used at the query position. 69442- objType types.Type 69443- 69444- // objKind is a mask of expected kinds of types such as "map", "slice", etc. 69445- objKind objKind 69446- 69447- // variadic is true if we are completing the initial variadic 69448- // parameter. For example: 69449- // append([]T{}, <>) // objType=T variadic=true 69450- // append([]T{}, T{}, <>) // objType=T variadic=false 69451- variadic bool 69452- 69453- // modifiers are prefixes such as "*", "&" or "<-" that influence how 69454- // a candidate type relates to the expected type. 69455- modifiers []typeMod 69456- 69457- // convertibleTo is a type our candidate type must be convertible to. 69458- convertibleTo types.Type 69459- 69460- // typeName holds information about the expected type name at 69461- // position, if any. 69462- typeName typeNameInference 69463- 69464- // assignees are the types that would receive a function call's 69465- // results at the position. For example: 69466- // 69467- // foo := 123 69468- // foo, bar := <> 69469- // 69470- // at "<>", the assignees are [int, <invalid>]. 69471- assignees []types.Type 69472- 69473- // variadicAssignees is true if we could be completing an inner 69474- // function call that fills out an outer function call's variadic 69475- // params. For example: 69476- // 69477- // func foo(int, ...string) {} 69478- // 69479- // foo(<>) // variadicAssignees=true 69480- // foo(bar<>) // variadicAssignees=true 69481- // foo(bar, baz<>) // variadicAssignees=false 69482- variadicAssignees bool 69483- 69484- // penalized holds expressions that should be disfavored as 69485- // candidates. For example, it tracks expressions already used in a 69486- // switch statement's other cases. Each expression is tracked using 69487- // its entire object "chain" allowing differentiation between 69488- // "a.foo" and "b.foo" when "a" and "b" are the same type. 69489- penalized []penalizedObj 69490- 69491- // objChain contains the chain of objects representing the 69492- // surrounding *ast.SelectorExpr. For example, if we are completing 69493- // "foo.bar.ba<>", objChain will contain []types.Object{foo, bar}. 69494- objChain []types.Object 69495-} 69496- 69497-// typeNameInference holds information about the expected type name at 69498-// position. 69499-type typeNameInference struct { 69500- // wantTypeName is true if we expect the name of a type. 69501- wantTypeName bool 69502- 69503- // modifiers are prefixes such as "*", "&" or "<-" that influence how 69504- // a candidate type relates to the expected type. 69505- modifiers []typeMod 69506- 69507- // assertableFrom is a type that must be assertable to our candidate type. 69508- assertableFrom types.Type 69509- 69510- // wantComparable is true if we want a comparable type. 69511- wantComparable bool 69512- 69513- // seenTypeSwitchCases tracks types that have already been used by 69514- // the containing type switch. 69515- seenTypeSwitchCases []types.Type 69516- 69517- // compLitType is true if we are completing a composite literal type 69518- // name, e.g "foo<>{}". 69519- compLitType bool 69520- 69521- // isTypeParam is true if we are completing a type instantiation parameter 69522- isTypeParam bool 69523-} 69524- 69525-// expectedCandidate returns information about the expected candidate 69526-// for an expression at the query position. 69527-func expectedCandidate(ctx context.Context, c *completer) (inf candidateInference) { 69528- inf.typeName = expectTypeName(c) 69529- 69530- if c.enclosingCompositeLiteral != nil { 69531- inf.objType = c.expectedCompositeLiteralType() 69532- } 69533- 69534-Nodes: 69535- for i, node := range c.path { 69536- switch node := node.(type) { 69537- case *ast.BinaryExpr: 69538- // Determine if query position comes from left or right of op. 69539- e := node.X 69540- if c.pos < node.OpPos { 69541- e = node.Y 69542- } 69543- if tv, ok := c.pkg.GetTypesInfo().Types[e]; ok { 69544- switch node.Op { 69545- case token.LAND, token.LOR: 69546- // Don't infer "bool" type for "&&" or "||". Often you want 69547- // to compose a boolean expression from non-boolean 69548- // candidates. 69549- default: 69550- inf.objType = tv.Type 69551- } 69552- break Nodes 69553- } 69554- case *ast.AssignStmt: 69555- // Only rank completions if you are on the right side of the token. 69556- if c.pos > node.TokPos { 69557- i := exprAtPos(c.pos, node.Rhs) 69558- if i >= len(node.Lhs) { 69559- i = len(node.Lhs) - 1 69560- } 69561- if tv, ok := c.pkg.GetTypesInfo().Types[node.Lhs[i]]; ok { 69562- inf.objType = tv.Type 69563- } 69564- 69565- // If we have a single expression on the RHS, record the LHS 69566- // assignees so we can favor multi-return function calls with 69567- // matching result values. 69568- if len(node.Rhs) <= 1 { 69569- for _, lhs := range node.Lhs { 69570- inf.assignees = append(inf.assignees, c.pkg.GetTypesInfo().TypeOf(lhs)) 69571- } 69572- } else { 69573- // Otherwise, record our single assignee, even if its type is 69574- // not available. We use this info to downrank functions 69575- // with the wrong number of result values. 69576- inf.assignees = append(inf.assignees, c.pkg.GetTypesInfo().TypeOf(node.Lhs[i])) 69577- } 69578- } 69579- return inf 69580- case *ast.ValueSpec: 69581- if node.Type != nil && c.pos > node.Type.End() { 69582- inf.objType = c.pkg.GetTypesInfo().TypeOf(node.Type) 69583- } 69584- return inf 69585- case *ast.CallExpr: 69586- // Only consider CallExpr args if position falls between parens. 69587- if node.Lparen < c.pos && c.pos <= node.Rparen { 69588- // For type conversions like "int64(foo)" we can only infer our 69589- // desired type is convertible to int64. 69590- if typ := typeConversion(node, c.pkg.GetTypesInfo()); typ != nil { 69591- inf.convertibleTo = typ 69592- break Nodes 69593- } 69594- 69595- sig, _ := c.pkg.GetTypesInfo().Types[node.Fun].Type.(*types.Signature) 69596- 69597- if sig != nil && typeparams.ForSignature(sig).Len() > 0 { 69598- // If we are completing a generic func call, re-check the call expression. 69599- // This allows type param inference to work in cases like: 69600- // 69601- // func foo[T any](T) {} 69602- // foo[int](<>) // <- get "int" completions instead of "T" 69603- // 69604- // TODO: remove this after https://go.dev/issue/52503 69605- info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} 69606- types.CheckExpr(c.pkg.FileSet(), c.pkg.GetTypes(), node.Fun.Pos(), node.Fun, info) 69607- sig, _ = info.Types[node.Fun].Type.(*types.Signature) 69608- } 69609- 69610- if sig != nil { 69611- inf = c.expectedCallParamType(inf, node, sig) 69612- } 69613- 69614- if funIdent, ok := node.Fun.(*ast.Ident); ok { 69615- obj := c.pkg.GetTypesInfo().ObjectOf(funIdent) 69616- 69617- if obj != nil && obj.Parent() == types.Universe { 69618- // Defer call to builtinArgType so we can provide it the 69619- // inferred type from its parent node. 69620- defer func() { 69621- inf = c.builtinArgType(obj, node, inf) 69622- inf.objKind = c.builtinArgKind(ctx, obj, node) 69623- }() 69624- 69625- // The expected type of builtin arguments like append() is 69626- // the expected type of the builtin call itself. For 69627- // example: 69628- // 69629- // var foo []int = append(<>) 69630- // 69631- // To find the expected type at <> we "skip" the append() 69632- // node and get the expected type one level up, which is 69633- // []int. 69634- continue Nodes 69635- } 69636- } 69637- 69638- return inf 69639- } 69640- case *ast.ReturnStmt: 69641- if c.enclosingFunc != nil { 69642- sig := c.enclosingFunc.sig 69643- // Find signature result that corresponds to our return statement. 69644- if resultIdx := exprAtPos(c.pos, node.Results); resultIdx < len(node.Results) { 69645- if resultIdx < sig.Results().Len() { 69646- inf.objType = sig.Results().At(resultIdx).Type() 69647- } 69648- } 69649- } 69650- return inf 69651- case *ast.CaseClause: 69652- if swtch, ok := findSwitchStmt(c.path[i+1:], c.pos, node).(*ast.SwitchStmt); ok { 69653- if tv, ok := c.pkg.GetTypesInfo().Types[swtch.Tag]; ok { 69654- inf.objType = tv.Type 69655- 69656- // Record which objects have already been used in the case 69657- // statements so we don't suggest them again. 69658- for _, cc := range swtch.Body.List { 69659- for _, caseExpr := range cc.(*ast.CaseClause).List { 69660- // Don't record the expression we are currently completing. 69661- if caseExpr.Pos() < c.pos && c.pos <= caseExpr.End() { 69662- continue 69663- } 69664- 69665- if objs := objChain(c.pkg.GetTypesInfo(), caseExpr); len(objs) > 0 { 69666- inf.penalized = append(inf.penalized, penalizedObj{objChain: objs, penalty: 0.1}) 69667- } 69668- } 69669- } 69670- } 69671- } 69672- return inf 69673- case *ast.SliceExpr: 69674- // Make sure position falls within the brackets (e.g. "foo[a:<>]"). 69675- if node.Lbrack < c.pos && c.pos <= node.Rbrack { 69676- inf.objType = types.Typ[types.UntypedInt] 69677- } 69678- return inf 69679- case *ast.IndexExpr: 69680- // Make sure position falls within the brackets (e.g. "foo[<>]"). 69681- if node.Lbrack < c.pos && c.pos <= node.Rbrack { 69682- if tv, ok := c.pkg.GetTypesInfo().Types[node.X]; ok { 69683- switch t := tv.Type.Underlying().(type) { 69684- case *types.Map: 69685- inf.objType = t.Key() 69686- case *types.Slice, *types.Array: 69687- inf.objType = types.Typ[types.UntypedInt] 69688- } 69689- 69690- if ct := expectedConstraint(tv.Type, 0); ct != nil { 69691- inf.objType = ct 69692- inf.typeName.wantTypeName = true 69693- inf.typeName.isTypeParam = true 69694- } 69695- } 69696- } 69697- return inf 69698- case *typeparams.IndexListExpr: 69699- if node.Lbrack < c.pos && c.pos <= node.Rbrack { 69700- if tv, ok := c.pkg.GetTypesInfo().Types[node.X]; ok { 69701- if ct := expectedConstraint(tv.Type, exprAtPos(c.pos, node.Indices)); ct != nil { 69702- inf.objType = ct 69703- inf.typeName.wantTypeName = true 69704- inf.typeName.isTypeParam = true 69705- } 69706- } 69707- } 69708- return inf 69709- case *ast.SendStmt: 69710- // Make sure we are on right side of arrow (e.g. "foo <- <>"). 69711- if c.pos > node.Arrow+1 { 69712- if tv, ok := c.pkg.GetTypesInfo().Types[node.Chan]; ok { 69713- if ch, ok := tv.Type.Underlying().(*types.Chan); ok { 69714- inf.objType = ch.Elem() 69715- } 69716- } 69717- } 69718- return inf 69719- case *ast.RangeStmt: 69720- if source.NodeContains(node.X, c.pos) { 69721- inf.objKind |= kindSlice | kindArray | kindMap | kindString 69722- if node.Value == nil { 69723- inf.objKind |= kindChan 69724- } 69725- } 69726- return inf 69727- case *ast.StarExpr: 69728- inf.modifiers = append(inf.modifiers, typeMod{mod: dereference}) 69729- case *ast.UnaryExpr: 69730- switch node.Op { 69731- case token.AND: 69732- inf.modifiers = append(inf.modifiers, typeMod{mod: reference}) 69733- case token.ARROW: 69734- inf.modifiers = append(inf.modifiers, typeMod{mod: chanRead}) 69735- } 69736- case *ast.DeferStmt, *ast.GoStmt: 69737- inf.objKind |= kindFunc 69738- return inf 69739- default: 69740- if breaksExpectedTypeInference(node, c.pos) { 69741- return inf 69742- } 69743- } 69744- } 69745- 69746- return inf 69747-} 69748- 69749-func (c *completer) expectedCallParamType(inf candidateInference, node *ast.CallExpr, sig *types.Signature) candidateInference { 69750- numParams := sig.Params().Len() 69751- if numParams == 0 { 69752- return inf 69753- } 69754- 69755- exprIdx := exprAtPos(c.pos, node.Args) 69756- 69757- // If we have one or zero arg expressions, we may be 69758- // completing to a function call that returns multiple 69759- // values, in turn getting passed in to the surrounding 69760- // call. Record the assignees so we can favor function 69761- // calls that return matching values. 69762- if len(node.Args) <= 1 && exprIdx == 0 { 69763- for i := 0; i < sig.Params().Len(); i++ { 69764- inf.assignees = append(inf.assignees, sig.Params().At(i).Type()) 69765- } 69766- 69767- // Record that we may be completing into variadic parameters. 69768- inf.variadicAssignees = sig.Variadic() 69769- } 69770- 69771- // Make sure not to run past the end of expected parameters. 69772- if exprIdx >= numParams { 69773- inf.objType = sig.Params().At(numParams - 1).Type() 69774- } else { 69775- inf.objType = sig.Params().At(exprIdx).Type() 69776- } 69777- 69778- if sig.Variadic() && exprIdx >= (numParams-1) { 69779- // If we are completing a variadic param, deslice the variadic type. 69780- inf.objType = deslice(inf.objType) 69781- // Record whether we are completing the initial variadic param. 69782- inf.variadic = exprIdx == numParams-1 && len(node.Args) <= numParams 69783- 69784- // Check if we can infer object kind from printf verb. 69785- inf.objKind |= printfArgKind(c.pkg.GetTypesInfo(), node, exprIdx) 69786- } 69787- 69788- // If our expected type is an uninstantiated generic type param, 69789- // swap to the constraint which will do a decent job filtering 69790- // candidates. 69791- if tp, _ := inf.objType.(*typeparams.TypeParam); tp != nil { 69792- inf.objType = tp.Constraint() 69793- } 69794- 69795- return inf 69796-} 69797- 69798-func expectedConstraint(t types.Type, idx int) types.Type { 69799- var tp *typeparams.TypeParamList 69800- if named, _ := t.(*types.Named); named != nil { 69801- tp = typeparams.ForNamed(named) 69802- } else if sig, _ := t.Underlying().(*types.Signature); sig != nil { 69803- tp = typeparams.ForSignature(sig) 69804- } 69805- if tp == nil || idx >= tp.Len() { 69806- return nil 69807- } 69808- return tp.At(idx).Constraint() 69809-} 69810- 69811-// objChain decomposes e into a chain of objects if possible. For 69812-// example, "foo.bar().baz" will yield []types.Object{foo, bar, baz}. 69813-// If any part can't be turned into an object, return nil. 69814-func objChain(info *types.Info, e ast.Expr) []types.Object { 69815- var objs []types.Object 69816- 69817- for e != nil { 69818- switch n := e.(type) { 69819- case *ast.Ident: 69820- obj := info.ObjectOf(n) 69821- if obj == nil { 69822- return nil 69823- } 69824- objs = append(objs, obj) 69825- e = nil 69826- case *ast.SelectorExpr: 69827- obj := info.ObjectOf(n.Sel) 69828- if obj == nil { 69829- return nil 69830- } 69831- objs = append(objs, obj) 69832- e = n.X 69833- case *ast.CallExpr: 69834- if len(n.Args) > 0 { 69835- return nil 69836- } 69837- e = n.Fun 69838- default: 69839- return nil 69840- } 69841- } 69842- 69843- // Reverse order so the layout matches the syntactic order. 69844- for i := 0; i < len(objs)/2; i++ { 69845- objs[i], objs[len(objs)-1-i] = objs[len(objs)-1-i], objs[i] 69846- } 69847- 69848- return objs 69849-} 69850- 69851-// applyTypeModifiers applies the list of type modifiers to a type. 69852-// It returns nil if the modifiers could not be applied. 69853-func (ci candidateInference) applyTypeModifiers(typ types.Type, addressable bool) types.Type { 69854- for _, mod := range ci.modifiers { 69855- switch mod.mod { 69856- case dereference: 69857- // For every "*" indirection operator, remove a pointer layer 69858- // from candidate type. 69859- if ptr, ok := typ.Underlying().(*types.Pointer); ok { 69860- typ = ptr.Elem() 69861- } else { 69862- return nil 69863- } 69864- case reference: 69865- // For every "&" address operator, add another pointer layer to 69866- // candidate type, if the candidate is addressable. 69867- if addressable { 69868- typ = types.NewPointer(typ) 69869- } else { 69870- return nil 69871- } 69872- case chanRead: 69873- // For every "<-" operator, remove a layer of channelness. 69874- if ch, ok := typ.(*types.Chan); ok { 69875- typ = ch.Elem() 69876- } else { 69877- return nil 69878- } 69879- } 69880- } 69881- 69882- return typ 69883-} 69884- 69885-// applyTypeNameModifiers applies the list of type modifiers to a type name. 69886-func (ci candidateInference) applyTypeNameModifiers(typ types.Type) types.Type { 69887- for _, mod := range ci.typeName.modifiers { 69888- switch mod.mod { 69889- case reference: 69890- typ = types.NewPointer(typ) 69891- case arrayType: 69892- typ = types.NewArray(typ, mod.arrayLen) 69893- case sliceType: 69894- typ = types.NewSlice(typ) 69895- } 69896- } 69897- return typ 69898-} 69899- 69900-// matchesVariadic returns true if we are completing a variadic 69901-// parameter and candType is a compatible slice type. 69902-func (ci candidateInference) matchesVariadic(candType types.Type) bool { 69903- return ci.variadic && ci.objType != nil && assignableTo(candType, types.NewSlice(ci.objType)) 69904-} 69905- 69906-// findSwitchStmt returns an *ast.CaseClause's corresponding *ast.SwitchStmt or 69907-// *ast.TypeSwitchStmt. path should start from the case clause's first ancestor. 69908-func findSwitchStmt(path []ast.Node, pos token.Pos, c *ast.CaseClause) ast.Stmt { 69909- // Make sure position falls within a "case <>:" clause. 69910- if exprAtPos(pos, c.List) >= len(c.List) { 69911- return nil 69912- } 69913- // A case clause is always nested within a block statement in a switch statement. 69914- if len(path) < 2 { 69915- return nil 69916- } 69917- if _, ok := path[0].(*ast.BlockStmt); !ok { 69918- return nil 69919- } 69920- switch s := path[1].(type) { 69921- case *ast.SwitchStmt: 69922- return s 69923- case *ast.TypeSwitchStmt: 69924- return s 69925- default: 69926- return nil 69927- } 69928-} 69929- 69930-// breaksExpectedTypeInference reports if an expression node's type is unrelated 69931-// to its child expression node types. For example, "Foo{Bar: x.Baz(<>)}" should 69932-// expect a function argument, not a composite literal value. 69933-func breaksExpectedTypeInference(n ast.Node, pos token.Pos) bool { 69934- switch n := n.(type) { 69935- case *ast.CompositeLit: 69936- // Doesn't break inference if pos is in type name. 69937- // For example: "Foo<>{Bar: 123}" 69938- return !source.NodeContains(n.Type, pos) 69939- case *ast.CallExpr: 69940- // Doesn't break inference if pos is in func name. 69941- // For example: "Foo<>(123)" 69942- return !source.NodeContains(n.Fun, pos) 69943- case *ast.FuncLit, *ast.IndexExpr, *ast.SliceExpr: 69944- return true 69945- default: 69946- return false 69947- } 69948-} 69949- 69950-// expectTypeName returns information about the expected type name at position. 69951-func expectTypeName(c *completer) typeNameInference { 69952- var inf typeNameInference 69953- 69954-Nodes: 69955- for i, p := range c.path { 69956- switch n := p.(type) { 69957- case *ast.FieldList: 69958- // Expect a type name if pos is in a FieldList. This applies to 69959- // FuncType params/results, FuncDecl receiver, StructType, and 69960- // InterfaceType. We don't need to worry about the field name 69961- // because completion bails out early if pos is in an *ast.Ident 69962- // that defines an object. 69963- inf.wantTypeName = true 69964- break Nodes 69965- case *ast.CaseClause: 69966- // Expect type names in type switch case clauses. 69967- if swtch, ok := findSwitchStmt(c.path[i+1:], c.pos, n).(*ast.TypeSwitchStmt); ok { 69968- // The case clause types must be assertable from the type switch parameter. 69969- ast.Inspect(swtch.Assign, func(n ast.Node) bool { 69970- if ta, ok := n.(*ast.TypeAssertExpr); ok { 69971- inf.assertableFrom = c.pkg.GetTypesInfo().TypeOf(ta.X) 69972- return false 69973- } 69974- return true 69975- }) 69976- inf.wantTypeName = true 69977- 69978- // Track the types that have already been used in this 69979- // switch's case statements so we don't recommend them. 69980- for _, e := range swtch.Body.List { 69981- for _, typeExpr := range e.(*ast.CaseClause).List { 69982- // Skip if type expression contains pos. We don't want to 69983- // count it as already used if the user is completing it. 69984- if typeExpr.Pos() < c.pos && c.pos <= typeExpr.End() { 69985- continue 69986- } 69987- 69988- if t := c.pkg.GetTypesInfo().TypeOf(typeExpr); t != nil { 69989- inf.seenTypeSwitchCases = append(inf.seenTypeSwitchCases, t) 69990- } 69991- } 69992- } 69993- 69994- break Nodes 69995- } 69996- return typeNameInference{} 69997- case *ast.TypeAssertExpr: 69998- // Expect type names in type assert expressions. 69999- if n.Lparen < c.pos && c.pos <= n.Rparen { 70000- // The type in parens must be assertable from the expression type. 70001- inf.assertableFrom = c.pkg.GetTypesInfo().TypeOf(n.X) 70002- inf.wantTypeName = true 70003- break Nodes 70004- } 70005- return typeNameInference{} 70006- case *ast.StarExpr: 70007- inf.modifiers = append(inf.modifiers, typeMod{mod: reference}) 70008- case *ast.CompositeLit: 70009- // We want a type name if position is in the "Type" part of a 70010- // composite literal (e.g. "Foo<>{}"). 70011- if n.Type != nil && n.Type.Pos() <= c.pos && c.pos <= n.Type.End() { 70012- inf.wantTypeName = true 70013- inf.compLitType = true 70014- 70015- if i < len(c.path)-1 { 70016- // Track preceding "&" operator. Technically it applies to 70017- // the composite literal and not the type name, but if 70018- // affects our type completion nonetheless. 70019- if u, ok := c.path[i+1].(*ast.UnaryExpr); ok && u.Op == token.AND { 70020- inf.modifiers = append(inf.modifiers, typeMod{mod: reference}) 70021- } 70022- } 70023- } 70024- break Nodes 70025- case *ast.ArrayType: 70026- // If we are inside the "Elt" part of an array type, we want a type name. 70027- if n.Elt.Pos() <= c.pos && c.pos <= n.Elt.End() { 70028- inf.wantTypeName = true 70029- if n.Len == nil { 70030- // No "Len" expression means a slice type. 70031- inf.modifiers = append(inf.modifiers, typeMod{mod: sliceType}) 70032- } else { 70033- // Try to get the array type using the constant value of "Len". 70034- tv, ok := c.pkg.GetTypesInfo().Types[n.Len] 70035- if ok && tv.Value != nil && tv.Value.Kind() == constant.Int { 70036- if arrayLen, ok := constant.Int64Val(tv.Value); ok { 70037- inf.modifiers = append(inf.modifiers, typeMod{mod: arrayType, arrayLen: arrayLen}) 70038- } 70039- } 70040- } 70041- 70042- // ArrayTypes can be nested, so keep going if our parent is an 70043- // ArrayType. 70044- if i < len(c.path)-1 { 70045- if _, ok := c.path[i+1].(*ast.ArrayType); ok { 70046- continue Nodes 70047- } 70048- } 70049- 70050- break Nodes 70051- } 70052- case *ast.MapType: 70053- inf.wantTypeName = true 70054- if n.Key != nil { 70055- inf.wantComparable = source.NodeContains(n.Key, c.pos) 70056- } else { 70057- // If the key is empty, assume we are completing the key if 70058- // pos is directly after the "map[". 70059- inf.wantComparable = c.pos == n.Pos()+token.Pos(len("map[")) 70060- } 70061- break Nodes 70062- case *ast.ValueSpec: 70063- inf.wantTypeName = source.NodeContains(n.Type, c.pos) 70064- break Nodes 70065- case *ast.TypeSpec: 70066- inf.wantTypeName = source.NodeContains(n.Type, c.pos) 70067- default: 70068- if breaksExpectedTypeInference(p, c.pos) { 70069- return typeNameInference{} 70070- } 70071- } 70072- } 70073- 70074- return inf 70075-} 70076- 70077-func (c *completer) fakeObj(T types.Type) *types.Var { 70078- return types.NewVar(token.NoPos, c.pkg.GetTypes(), "", T) 70079-} 70080- 70081-// derivableTypes iterates types you can derive from t. For example, 70082-// from "foo" we might derive "&foo", and "foo()". 70083-func derivableTypes(t types.Type, addressable bool, f func(t types.Type, addressable bool, mod typeModKind) bool) bool { 70084- switch t := t.Underlying().(type) { 70085- case *types.Signature: 70086- // If t is a func type with a single result, offer the result type. 70087- if t.Results().Len() == 1 && f(t.Results().At(0).Type(), false, invoke) { 70088- return true 70089- } 70090- case *types.Array: 70091- if f(t.Elem(), true, index) { 70092- return true 70093- } 70094- // Try converting array to slice. 70095- if f(types.NewSlice(t.Elem()), false, takeSlice) { 70096- return true 70097- } 70098- case *types.Pointer: 70099- if f(t.Elem(), false, dereference) { 70100- return true 70101- } 70102- case *types.Slice: 70103- if f(t.Elem(), true, index) { 70104- return true 70105- } 70106- case *types.Map: 70107- if f(t.Elem(), false, index) { 70108- return true 70109- } 70110- case *types.Chan: 70111- if f(t.Elem(), false, chanRead) { 70112- return true 70113- } 70114- } 70115- 70116- // Check if c is addressable and a pointer to c matches our type inference. 70117- if addressable && f(types.NewPointer(t), false, reference) { 70118- return true 70119- } 70120- 70121- return false 70122-} 70123- 70124-// anyCandType reports whether f returns true for any candidate type 70125-// derivable from c. It searches up to three levels of type 70126-// modification. For example, given "foo" we could discover "***foo" 70127-// or "*foo()". 70128-func (c *candidate) anyCandType(f func(t types.Type, addressable bool) bool) bool { 70129- if c.obj == nil || c.obj.Type() == nil { 70130- return false 70131- } 70132- 70133- const maxDepth = 3 70134- 70135- var searchTypes func(t types.Type, addressable bool, mods []typeModKind) bool 70136- searchTypes = func(t types.Type, addressable bool, mods []typeModKind) bool { 70137- if f(t, addressable) { 70138- if len(mods) > 0 { 70139- newMods := make([]typeModKind, len(mods)+len(c.mods)) 70140- copy(newMods, mods) 70141- copy(newMods[len(mods):], c.mods) 70142- c.mods = newMods 70143- } 70144- return true 70145- } 70146- 70147- if len(mods) == maxDepth { 70148- return false 70149- } 70150- 70151- return derivableTypes(t, addressable, func(t types.Type, addressable bool, mod typeModKind) bool { 70152- return searchTypes(t, addressable, append(mods, mod)) 70153- }) 70154- } 70155- 70156- return searchTypes(c.obj.Type(), c.addressable, make([]typeModKind, 0, maxDepth)) 70157-} 70158- 70159-// matchingCandidate reports whether cand matches our type inferences. 70160-// It mutates cand's score in certain cases. 70161-func (c *completer) matchingCandidate(cand *candidate) bool { 70162- if c.completionContext.commentCompletion { 70163- return false 70164- } 70165- 70166- // Bail out early if we are completing a field name in a composite literal. 70167- if v, ok := cand.obj.(*types.Var); ok && v.IsField() && c.wantStructFieldCompletions() { 70168- return true 70169- } 70170- 70171- if isTypeName(cand.obj) { 70172- return c.matchingTypeName(cand) 70173- } else if c.wantTypeName() { 70174- // If we want a type, a non-type object never matches. 70175- return false 70176- } 70177- 70178- if c.inference.candTypeMatches(cand) { 70179- return true 70180- } 70181- 70182- candType := cand.obj.Type() 70183- if candType == nil { 70184- return false 70185- } 70186- 70187- if sig, ok := candType.Underlying().(*types.Signature); ok { 70188- if c.inference.assigneesMatch(cand, sig) { 70189- // Invoke the candidate if its results are multi-assignable. 70190- cand.mods = append(cand.mods, invoke) 70191- return true 70192- } 70193- } 70194- 70195- // Default to invoking *types.Func candidates. This is so function 70196- // completions in an empty statement (or other cases with no expected type) 70197- // are invoked by default. 70198- if isFunc(cand.obj) { 70199- cand.mods = append(cand.mods, invoke) 70200- } 70201- 70202- return false 70203-} 70204- 70205-// candTypeMatches reports whether cand makes a good completion 70206-// candidate given the candidate inference. cand's score may be 70207-// mutated to downrank the candidate in certain situations. 70208-func (ci *candidateInference) candTypeMatches(cand *candidate) bool { 70209- var ( 70210- expTypes = make([]types.Type, 0, 2) 70211- variadicType types.Type 70212- ) 70213- if ci.objType != nil { 70214- expTypes = append(expTypes, ci.objType) 70215- 70216- if ci.variadic { 70217- variadicType = types.NewSlice(ci.objType) 70218- expTypes = append(expTypes, variadicType) 70219- } 70220- } 70221- 70222- return cand.anyCandType(func(candType types.Type, addressable bool) bool { 70223- // Take into account any type modifiers on the expected type. 70224- candType = ci.applyTypeModifiers(candType, addressable) 70225- if candType == nil { 70226- return false 70227- } 70228- 70229- if ci.convertibleTo != nil && convertibleTo(candType, ci.convertibleTo) { 70230- return true 70231- } 70232- 70233- for _, expType := range expTypes { 70234- if isEmptyInterface(expType) { 70235- continue 70236- } 70237- 70238- matches := ci.typeMatches(expType, candType) 70239- if !matches { 70240- // If candType doesn't otherwise match, consider if we can 70241- // convert candType directly to expType. 70242- if considerTypeConversion(candType, expType, cand.path) { 70243- cand.convertTo = expType 70244- // Give a major score penalty so we always prefer directly 70245- // assignable candidates, all else equal. 70246- cand.score *= 0.5 70247- return true 70248- } 70249- 70250- continue 70251- } 70252- 70253- if expType == variadicType { 70254- cand.mods = append(cand.mods, takeDotDotDot) 70255- } 70256- 70257- // Lower candidate score for untyped conversions. This avoids 70258- // ranking untyped constants above candidates with an exact type 70259- // match. Don't lower score of builtin constants, e.g. "true". 70260- if isUntyped(candType) && !types.Identical(candType, expType) && cand.obj.Parent() != types.Universe { 70261- // Bigger penalty for deep completions into other packages to 70262- // avoid random constants from other packages popping up all 70263- // the time. 70264- if len(cand.path) > 0 && isPkgName(cand.path[0]) { 70265- cand.score *= 0.5 70266- } else { 70267- cand.score *= 0.75 70268- } 70269- } 70270- 70271- return true 70272- } 70273- 70274- // If we don't have a specific expected type, fall back to coarser 70275- // object kind checks. 70276- if ci.objType == nil || isEmptyInterface(ci.objType) { 70277- // If we were able to apply type modifiers to our candidate type, 70278- // count that as a match. For example: 70279- // 70280- // var foo chan int 70281- // <-fo<> 70282- // 70283- // We were able to apply the "<-" type modifier to "foo", so "foo" 70284- // matches. 70285- if len(ci.modifiers) > 0 { 70286- return true 70287- } 70288- 70289- // If we didn't have an exact type match, check if our object kind 70290- // matches. 70291- if ci.kindMatches(candType) { 70292- if ci.objKind == kindFunc { 70293- cand.mods = append(cand.mods, invoke) 70294- } 70295- return true 70296- } 70297- } 70298- 70299- return false 70300- }) 70301-} 70302- 70303-// considerTypeConversion returns true if we should offer a completion 70304-// automatically converting "from" to "to". 70305-func considerTypeConversion(from, to types.Type, path []types.Object) bool { 70306- // Don't offer to convert deep completions from other packages. 70307- // Otherwise there are many random package level consts/vars that 70308- // pop up as candidates all the time. 70309- if len(path) > 0 && isPkgName(path[0]) { 70310- return false 70311- } 70312- 70313- if _, ok := from.(*typeparams.TypeParam); ok { 70314- return false 70315- } 70316- 70317- if !convertibleTo(from, to) { 70318- return false 70319- } 70320- 70321- // Don't offer to convert ints to strings since that probably 70322- // doesn't do what the user wants. 70323- if isBasicKind(from, types.IsInteger) && isBasicKind(to, types.IsString) { 70324- return false 70325- } 70326- 70327- return true 70328-} 70329- 70330-// typeMatches reports whether an object of candType makes a good 70331-// completion candidate given the expected type expType. 70332-func (ci *candidateInference) typeMatches(expType, candType types.Type) bool { 70333- // Handle untyped values specially since AssignableTo gives false negatives 70334- // for them (see https://golang.org/issue/32146). 70335- if candBasic, ok := candType.Underlying().(*types.Basic); ok { 70336- if expBasic, ok := expType.Underlying().(*types.Basic); ok { 70337- // Note that the candidate and/or the expected can be untyped. 70338- // In "fo<> == 100" the expected type is untyped, and the 70339- // candidate could also be an untyped constant. 70340- 70341- // Sort by is_untyped and then by is_int to simplify below logic. 70342- a, b := candBasic.Info(), expBasic.Info() 70343- if a&types.IsUntyped == 0 || (b&types.IsInteger > 0 && b&types.IsUntyped > 0) { 70344- a, b = b, a 70345- } 70346- 70347- // If at least one is untyped... 70348- if a&types.IsUntyped > 0 { 70349- switch { 70350- // Untyped integers are compatible with floats. 70351- case a&types.IsInteger > 0 && b&types.IsFloat > 0: 70352- return true 70353- 70354- // Check if their constant kind (bool|int|float|complex|string) matches. 70355- // This doesn't take into account the constant value, so there will be some 70356- // false positives due to integer sign and overflow. 70357- case a&types.IsConstType == b&types.IsConstType: 70358- return true 70359- } 70360- } 70361- } 70362- } 70363- 70364- // AssignableTo covers the case where the types are equal, but also handles 70365- // cases like assigning a concrete type to an interface type. 70366- return assignableTo(candType, expType) 70367-} 70368- 70369-// kindMatches reports whether candType's kind matches our expected 70370-// kind (e.g. slice, map, etc.). 70371-func (ci *candidateInference) kindMatches(candType types.Type) bool { 70372- return ci.objKind > 0 && ci.objKind&candKind(candType) > 0 70373-} 70374- 70375-// assigneesMatch reports whether an invocation of sig matches the 70376-// number and type of any assignees. 70377-func (ci *candidateInference) assigneesMatch(cand *candidate, sig *types.Signature) bool { 70378- if len(ci.assignees) == 0 { 70379- return false 70380- } 70381- 70382- // Uniresult functions are always usable and are handled by the 70383- // normal, non-assignees type matching logic. 70384- if sig.Results().Len() == 1 { 70385- return false 70386- } 70387- 70388- // Don't prefer completing into func(...interface{}) calls since all 70389- // functions would match. 70390- if ci.variadicAssignees && len(ci.assignees) == 1 && isEmptyInterface(deslice(ci.assignees[0])) { 70391- return false 70392- } 70393- 70394- var numberOfResultsCouldMatch bool 70395- if ci.variadicAssignees { 70396- numberOfResultsCouldMatch = sig.Results().Len() >= len(ci.assignees)-1 70397- } else { 70398- numberOfResultsCouldMatch = sig.Results().Len() == len(ci.assignees) 70399- } 70400- 70401- // If our signature doesn't return the right number of values, it's 70402- // not a match, so downrank it. For example: 70403- // 70404- // var foo func() (int, int) 70405- // a, b, c := <> // downrank "foo()" since it only returns two values 70406- if !numberOfResultsCouldMatch { 70407- cand.score /= 2 70408- return false 70409- } 70410- 70411- // If at least one assignee has a valid type, and all valid 70412- // assignees match the corresponding sig result value, the signature 70413- // is a match. 70414- allMatch := false 70415- for i := 0; i < sig.Results().Len(); i++ { 70416- var assignee types.Type 70417- 70418- // If we are completing into variadic parameters, deslice the 70419- // expected variadic type. 70420- if ci.variadicAssignees && i >= len(ci.assignees)-1 { 70421- assignee = ci.assignees[len(ci.assignees)-1] 70422- if elem := deslice(assignee); elem != nil { 70423- assignee = elem 70424- } 70425- } else { 70426- assignee = ci.assignees[i] 70427- } 70428- 70429- if assignee == nil || assignee == types.Typ[types.Invalid] { 70430- continue 70431- } 70432- 70433- allMatch = ci.typeMatches(assignee, sig.Results().At(i).Type()) 70434- if !allMatch { 70435- break 70436- } 70437- } 70438- return allMatch 70439-} 70440- 70441-func (c *completer) matchingTypeName(cand *candidate) bool { 70442- if !c.wantTypeName() { 70443- return false 70444- } 70445- 70446- typeMatches := func(candType types.Type) bool { 70447- // Take into account any type name modifier prefixes. 70448- candType = c.inference.applyTypeNameModifiers(candType) 70449- 70450- if from := c.inference.typeName.assertableFrom; from != nil { 70451- // Don't suggest the starting type in type assertions. For example, 70452- // if "foo" is an io.Writer, don't suggest "foo.(io.Writer)". 70453- if types.Identical(from, candType) { 70454- return false 70455- } 70456- 70457- if intf, ok := from.Underlying().(*types.Interface); ok { 70458- if !types.AssertableTo(intf, candType) { 70459- return false 70460- } 70461- } 70462- } 70463- 70464- if c.inference.typeName.wantComparable && !types.Comparable(candType) { 70465- return false 70466- } 70467- 70468- // Skip this type if it has already been used in another type 70469- // switch case. 70470- for _, seen := range c.inference.typeName.seenTypeSwitchCases { 70471- if types.Identical(candType, seen) { 70472- return false 70473- } 70474- } 70475- 70476- // We can expect a type name and have an expected type in cases like: 70477- // 70478- // var foo []int 70479- // foo = []i<> 70480- // 70481- // Where our expected type is "[]int", and we expect a type name. 70482- if c.inference.objType != nil { 70483- return assignableTo(candType, c.inference.objType) 70484- } 70485- 70486- // Default to saying any type name is a match. 70487- return true 70488- } 70489- 70490- t := cand.obj.Type() 70491- 70492- if typeMatches(t) { 70493- return true 70494- } 70495- 70496- if !types.IsInterface(t) && typeMatches(types.NewPointer(t)) { 70497- if c.inference.typeName.compLitType { 70498- // If we are completing a composite literal type as in 70499- // "foo<>{}", to make a pointer we must prepend "&". 70500- cand.mods = append(cand.mods, reference) 70501- } else { 70502- // If we are completing a normal type name such as "foo<>", to 70503- // make a pointer we must prepend "*". 70504- cand.mods = append(cand.mods, dereference) 70505- } 70506- return true 70507- } 70508- 70509- return false 70510-} 70511- 70512-var ( 70513- // "interface { Error() string }" (i.e. error) 70514- errorIntf = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) 70515- 70516- // "interface { String() string }" (i.e. fmt.Stringer) 70517- stringerIntf = types.NewInterfaceType([]*types.Func{ 70518- types.NewFunc(token.NoPos, nil, "String", types.NewSignature( 70519- nil, 70520- nil, 70521- types.NewTuple(types.NewParam(token.NoPos, nil, "", types.Typ[types.String])), 70522- false, 70523- )), 70524- }, nil).Complete() 70525- 70526- byteType = types.Universe.Lookup("byte").Type() 70527-) 70528- 70529-// candKind returns the objKind of candType, if any. 70530-func candKind(candType types.Type) objKind { 70531- var kind objKind 70532- 70533- switch t := candType.Underlying().(type) { 70534- case *types.Array: 70535- kind |= kindArray 70536- if t.Elem() == byteType { 70537- kind |= kindBytes 70538- } 70539- case *types.Slice: 70540- kind |= kindSlice 70541- if t.Elem() == byteType { 70542- kind |= kindBytes 70543- } 70544- case *types.Chan: 70545- kind |= kindChan 70546- case *types.Map: 70547- kind |= kindMap 70548- case *types.Pointer: 70549- kind |= kindPtr 70550- 70551- // Some builtins handle array pointers as arrays, so just report a pointer 70552- // to an array as an array. 70553- if _, isArray := t.Elem().Underlying().(*types.Array); isArray { 70554- kind |= kindArray 70555- } 70556- case *types.Basic: 70557- switch info := t.Info(); { 70558- case info&types.IsString > 0: 70559- kind |= kindString 70560- case info&types.IsInteger > 0: 70561- kind |= kindInt 70562- case info&types.IsFloat > 0: 70563- kind |= kindFloat 70564- case info&types.IsComplex > 0: 70565- kind |= kindComplex 70566- case info&types.IsBoolean > 0: 70567- kind |= kindBool 70568- } 70569- case *types.Signature: 70570- return kindFunc 70571- } 70572- 70573- if types.Implements(candType, errorIntf) { 70574- kind |= kindError 70575- } 70576- 70577- if types.Implements(candType, stringerIntf) { 70578- kind |= kindStringer 70579- } 70580- 70581- return kind 70582-} 70583- 70584-// innermostScope returns the innermost scope for c.pos. 70585-func (c *completer) innermostScope() *types.Scope { 70586- for _, s := range c.scopes { 70587- if s != nil { 70588- return s 70589- } 70590- } 70591- return nil 70592-} 70593- 70594-// isSlice reports whether the object's underlying type is a slice. 70595-func isSlice(obj types.Object) bool { 70596- if obj != nil && obj.Type() != nil { 70597- if _, ok := obj.Type().Underlying().(*types.Slice); ok { 70598- return true 70599- } 70600- } 70601- return false 70602-} 70603- 70604-// forEachPackageMember calls f(tok, id, fn) for each package-level 70605-// TYPE/VAR/CONST/FUNC declaration in the Go source file, based on a 70606-// quick partial parse. fn is non-nil only for function declarations. 70607-// The AST position information is garbage. 70608-func forEachPackageMember(content []byte, f func(tok token.Token, id *ast.Ident, fn *ast.FuncDecl)) { 70609- purged := purgeFuncBodies(content) 70610- file, _ := parser.ParseFile(token.NewFileSet(), "", purged, 0) 70611- for _, decl := range file.Decls { 70612- switch decl := decl.(type) { 70613- case *ast.GenDecl: 70614- for _, spec := range decl.Specs { 70615- switch spec := spec.(type) { 70616- case *ast.ValueSpec: // var/const 70617- for _, id := range spec.Names { 70618- f(decl.Tok, id, nil) 70619- } 70620- case *ast.TypeSpec: 70621- f(decl.Tok, spec.Name, nil) 70622- } 70623- } 70624- case *ast.FuncDecl: 70625- if decl.Recv == nil { 70626- f(token.FUNC, decl.Name, decl) 70627- } 70628- } 70629- } 70630-} 70631- 70632-// purgeFuncBodies returns a copy of src in which the contents of each 70633-// outermost {...} region except struct and interface types have been 70634-// deleted. It does not preserve newlines. This reduces the amount of 70635-// work required to parse the top-level declarations. 70636-func purgeFuncBodies(src []byte) []byte { 70637- // Destroy the content of any {...}-bracketed regions that are 70638- // not immediately preceded by a "struct" or "interface" 70639- // token. That includes function bodies, composite literals, 70640- // switch/select bodies, and all blocks of statements. 70641- // This will lead to non-void functions that don't have return 70642- // statements, which of course is a type error, but that's ok. 70643- 70644- var out bytes.Buffer 70645- file := token.NewFileSet().AddFile("", -1, len(src)) 70646- var sc scanner.Scanner 70647- sc.Init(file, src, nil, 0) 70648- var prev token.Token 70649- var cursor int // last consumed src offset 70650- var braces []token.Pos // stack of unclosed braces or -1 for struct/interface type 70651- for { 70652- pos, tok, _ := sc.Scan() 70653- if tok == token.EOF { 70654- break 70655- } 70656- switch tok { 70657- case token.COMMENT: 70658- // TODO(adonovan): opt: skip, to save an estimated 20% of time. 70659- 70660- case token.LBRACE: 70661- if prev == token.STRUCT || prev == token.INTERFACE { 70662- pos = -1 70663- } 70664- braces = append(braces, pos) 70665- 70666- case token.RBRACE: 70667- if last := len(braces) - 1; last >= 0 { 70668- top := braces[last] 70669- braces = braces[:last] 70670- if top < 0 { 70671- // struct/interface type: leave alone 70672- } else if len(braces) == 0 { // toplevel only 70673- // Delete {...} body. 70674- start, _ := safetoken.Offset(file, top) 70675- end, _ := safetoken.Offset(file, pos) 70676- out.Write(src[cursor : start+len("{")]) 70677- cursor = end 70678- } 70679- } 70680- } 70681- prev = tok 70682- } 70683- out.Write(src[cursor:]) 70684- return out.Bytes() 70685-} 70686diff -urN a/gopls/internal/lsp/source/completion/deep_completion.go b/gopls/internal/lsp/source/completion/deep_completion.go 70687--- a/gopls/internal/lsp/source/completion/deep_completion.go 2000-01-01 00:00:00.000000000 -0000 70688+++ b/gopls/internal/lsp/source/completion/deep_completion.go 1970-01-01 00:00:00.000000000 +0000 70689@@ -1,362 +0,0 @@ 70690-// Copyright 2019 The Go Authors. All rights reserved. 70691-// Use of this source code is governed by a BSD-style 70692-// license that can be found in the LICENSE file. 70693- 70694-package completion 70695- 70696-import ( 70697- "context" 70698- "go/types" 70699- "strings" 70700- "time" 70701-) 70702- 70703-// MaxDeepCompletions limits deep completion results because in most cases 70704-// there are too many to be useful. 70705-const MaxDeepCompletions = 3 70706- 70707-// deepCompletionState stores our state as we search for deep completions. 70708-// "deep completion" refers to searching into objects' fields and methods to 70709-// find more completion candidates. 70710-type deepCompletionState struct { 70711- // enabled indicates whether deep completion is permitted. 70712- enabled bool 70713- 70714- // queueClosed is used to disable adding new sub-fields to search queue 70715- // once we're running out of our time budget. 70716- queueClosed bool 70717- 70718- // thisQueue holds the current breadth first search queue. 70719- thisQueue []candidate 70720- 70721- // nextQueue holds the next breadth first search iteration's queue. 70722- nextQueue []candidate 70723- 70724- // highScores tracks the highest deep candidate scores we have found 70725- // so far. This is used to avoid work for low scoring deep candidates. 70726- highScores [MaxDeepCompletions]float64 70727- 70728- // candidateCount is the count of unique deep candidates encountered 70729- // so far. 70730- candidateCount int 70731-} 70732- 70733-// enqueue adds a candidate to the search queue. 70734-func (s *deepCompletionState) enqueue(cand candidate) { 70735- s.nextQueue = append(s.nextQueue, cand) 70736-} 70737- 70738-// dequeue removes and returns the leftmost element from the search queue. 70739-func (s *deepCompletionState) dequeue() *candidate { 70740- var cand *candidate 70741- cand, s.thisQueue = &s.thisQueue[len(s.thisQueue)-1], s.thisQueue[:len(s.thisQueue)-1] 70742- return cand 70743-} 70744- 70745-// scorePenalty computes a deep candidate score penalty. A candidate is 70746-// penalized based on depth to favor shallower candidates. We also give a 70747-// slight bonus to unexported objects and a slight additional penalty to 70748-// function objects. 70749-func (s *deepCompletionState) scorePenalty(cand *candidate) float64 { 70750- var deepPenalty float64 70751- for _, dc := range cand.path { 70752- deepPenalty++ 70753- 70754- if !dc.Exported() { 70755- deepPenalty -= 0.1 70756- } 70757- 70758- if _, isSig := dc.Type().Underlying().(*types.Signature); isSig { 70759- deepPenalty += 0.1 70760- } 70761- } 70762- 70763- // Normalize penalty to a max depth of 10. 70764- return deepPenalty / 10 70765-} 70766- 70767-// isHighScore returns whether score is among the top MaxDeepCompletions deep 70768-// candidate scores encountered so far. If so, it adds score to highScores, 70769-// possibly displacing an existing high score. 70770-func (s *deepCompletionState) isHighScore(score float64) bool { 70771- // Invariant: s.highScores is sorted with highest score first. Unclaimed 70772- // positions are trailing zeros. 70773- 70774- // If we beat an existing score then take its spot. 70775- for i, deepScore := range s.highScores { 70776- if score <= deepScore { 70777- continue 70778- } 70779- 70780- if deepScore != 0 && i != len(s.highScores)-1 { 70781- // If this wasn't an empty slot then we need to scooch everyone 70782- // down one spot. 70783- copy(s.highScores[i+1:], s.highScores[i:]) 70784- } 70785- s.highScores[i] = score 70786- return true 70787- } 70788- 70789- return false 70790-} 70791- 70792-// newPath returns path from search root for an object following a given 70793-// candidate. 70794-func (s *deepCompletionState) newPath(cand candidate, obj types.Object) []types.Object { 70795- path := make([]types.Object, len(cand.path)+1) 70796- copy(path, cand.path) 70797- path[len(path)-1] = obj 70798- 70799- return path 70800-} 70801- 70802-// deepSearch searches a candidate and its subordinate objects for completion 70803-// items if deep completion is enabled and adds the valid candidates to 70804-// completion items. 70805-func (c *completer) deepSearch(ctx context.Context) { 70806- defer func() { 70807- // We can return early before completing the search, so be sure to 70808- // clear out our queues to not impact any further invocations. 70809- c.deepState.thisQueue = c.deepState.thisQueue[:0] 70810- c.deepState.nextQueue = c.deepState.nextQueue[:0] 70811- }() 70812- 70813- for len(c.deepState.nextQueue) > 0 { 70814- c.deepState.thisQueue, c.deepState.nextQueue = c.deepState.nextQueue, c.deepState.thisQueue[:0] 70815- 70816- outer: 70817- for _, cand := range c.deepState.thisQueue { 70818- obj := cand.obj 70819- 70820- if obj == nil { 70821- continue 70822- } 70823- 70824- // At the top level, dedupe by object. 70825- if len(cand.path) == 0 { 70826- if c.seen[obj] { 70827- continue 70828- } 70829- c.seen[obj] = true 70830- } 70831- 70832- // If obj is not accessible because it lives in another package and is 70833- // not exported, don't treat it as a completion candidate unless it's 70834- // a package completion candidate. 70835- if !c.completionContext.packageCompletion && 70836- obj.Pkg() != nil && obj.Pkg() != c.pkg.GetTypes() && !obj.Exported() { 70837- continue 70838- } 70839- 70840- // If we want a type name, don't offer non-type name candidates. 70841- // However, do offer package names since they can contain type names, 70842- // and do offer any candidate without a type since we aren't sure if it 70843- // is a type name or not (i.e. unimported candidate). 70844- if c.wantTypeName() && obj.Type() != nil && !isTypeName(obj) && !isPkgName(obj) { 70845- continue 70846- } 70847- 70848- // When searching deep, make sure we don't have a cycle in our chain. 70849- // We don't dedupe by object because we want to allow both "foo.Baz" 70850- // and "bar.Baz" even though "Baz" is represented the same types.Object 70851- // in both. 70852- for _, seenObj := range cand.path { 70853- if seenObj == obj { 70854- continue outer 70855- } 70856- } 70857- 70858- c.addCandidate(ctx, &cand) 70859- 70860- c.deepState.candidateCount++ 70861- if c.opts.budget > 0 && c.deepState.candidateCount%100 == 0 { 70862- spent := float64(time.Since(c.startTime)) / float64(c.opts.budget) 70863- select { 70864- case <-ctx.Done(): 70865- return 70866- default: 70867- // If we are almost out of budgeted time, no further elements 70868- // should be added to the queue. This ensures remaining time is 70869- // used for processing current queue. 70870- if !c.deepState.queueClosed && spent >= 0.85 { 70871- c.deepState.queueClosed = true 70872- } 70873- } 70874- } 70875- 70876- // if deep search is disabled, don't add any more candidates. 70877- if !c.deepState.enabled || c.deepState.queueClosed { 70878- continue 70879- } 70880- 70881- // Searching members for a type name doesn't make sense. 70882- if isTypeName(obj) { 70883- continue 70884- } 70885- if obj.Type() == nil { 70886- continue 70887- } 70888- 70889- // Don't search embedded fields because they were already included in their 70890- // parent's fields. 70891- if v, ok := obj.(*types.Var); ok && v.Embedded() { 70892- continue 70893- } 70894- 70895- if sig, ok := obj.Type().Underlying().(*types.Signature); ok { 70896- // If obj is a function that takes no arguments and returns one 70897- // value, keep searching across the function call. 70898- if sig.Params().Len() == 0 && sig.Results().Len() == 1 { 70899- path := c.deepState.newPath(cand, obj) 70900- // The result of a function call is not addressable. 70901- c.methodsAndFields(sig.Results().At(0).Type(), false, cand.imp, func(newCand candidate) { 70902- newCand.pathInvokeMask = cand.pathInvokeMask | (1 << uint64(len(cand.path))) 70903- newCand.path = path 70904- c.deepState.enqueue(newCand) 70905- }) 70906- } 70907- } 70908- 70909- path := c.deepState.newPath(cand, obj) 70910- switch obj := obj.(type) { 70911- case *types.PkgName: 70912- c.packageMembers(obj.Imported(), stdScore, cand.imp, func(newCand candidate) { 70913- newCand.pathInvokeMask = cand.pathInvokeMask 70914- newCand.path = path 70915- c.deepState.enqueue(newCand) 70916- }) 70917- default: 70918- c.methodsAndFields(obj.Type(), cand.addressable, cand.imp, func(newCand candidate) { 70919- newCand.pathInvokeMask = cand.pathInvokeMask 70920- newCand.path = path 70921- c.deepState.enqueue(newCand) 70922- }) 70923- } 70924- } 70925- } 70926-} 70927- 70928-// addCandidate adds a completion candidate to suggestions, without searching 70929-// its members for more candidates. 70930-func (c *completer) addCandidate(ctx context.Context, cand *candidate) { 70931- obj := cand.obj 70932- if c.matchingCandidate(cand) { 70933- cand.score *= highScore 70934- 70935- if p := c.penalty(cand); p > 0 { 70936- cand.score *= (1 - p) 70937- } 70938- } else if isTypeName(obj) { 70939- // If obj is a *types.TypeName that didn't otherwise match, check 70940- // if a literal object of this type makes a good candidate. 70941- 70942- // We only care about named types (i.e. don't want builtin types). 70943- if _, isNamed := obj.Type().(*types.Named); isNamed { 70944- c.literal(ctx, obj.Type(), cand.imp) 70945- } 70946- } 70947- 70948- // Lower score of method calls so we prefer fields and vars over calls. 70949- if cand.hasMod(invoke) { 70950- if sig, ok := obj.Type().Underlying().(*types.Signature); ok && sig.Recv() != nil { 70951- cand.score *= 0.9 70952- } 70953- } 70954- 70955- // Prefer private objects over public ones. 70956- if !obj.Exported() && obj.Parent() != types.Universe { 70957- cand.score *= 1.1 70958- } 70959- 70960- // Slight penalty for index modifier (e.g. changing "foo" to 70961- // "foo[]") to curb false positives. 70962- if cand.hasMod(index) { 70963- cand.score *= 0.9 70964- } 70965- 70966- // Favor shallow matches by lowering score according to depth. 70967- cand.score -= cand.score * c.deepState.scorePenalty(cand) 70968- 70969- if cand.score < 0 { 70970- cand.score = 0 70971- } 70972- 70973- cand.name = deepCandName(cand) 70974- if item, err := c.item(ctx, *cand); err == nil { 70975- c.items = append(c.items, item) 70976- } 70977-} 70978- 70979-// deepCandName produces the full candidate name including any 70980-// ancestor objects. For example, "foo.bar().baz" for candidate "baz". 70981-func deepCandName(cand *candidate) string { 70982- totalLen := len(cand.obj.Name()) 70983- for i, obj := range cand.path { 70984- totalLen += len(obj.Name()) + 1 70985- if cand.pathInvokeMask&(1<<uint16(i)) > 0 { 70986- totalLen += 2 70987- } 70988- } 70989- 70990- var buf strings.Builder 70991- buf.Grow(totalLen) 70992- 70993- for i, obj := range cand.path { 70994- buf.WriteString(obj.Name()) 70995- if cand.pathInvokeMask&(1<<uint16(i)) > 0 { 70996- buf.WriteByte('(') 70997- buf.WriteByte(')') 70998- } 70999- buf.WriteByte('.') 71000- } 71001- 71002- buf.WriteString(cand.obj.Name()) 71003- 71004- return buf.String() 71005-} 71006- 71007-// penalty reports a score penalty for cand in the range (0, 1). 71008-// For example, a candidate is penalized if it has already been used 71009-// in another switch case statement. 71010-func (c *completer) penalty(cand *candidate) float64 { 71011- for _, p := range c.inference.penalized { 71012- if c.objChainMatches(cand, p.objChain) { 71013- return p.penalty 71014- } 71015- } 71016- 71017- return 0 71018-} 71019- 71020-// objChainMatches reports whether cand combined with the surrounding 71021-// object prefix matches chain. 71022-func (c *completer) objChainMatches(cand *candidate, chain []types.Object) bool { 71023- // For example, when completing: 71024- // 71025- // foo.ba<> 71026- // 71027- // If we are considering the deep candidate "bar.baz", cand is baz, 71028- // objChain is [foo] and deepChain is [bar]. We would match the 71029- // chain [foo, bar, baz]. 71030- if len(chain) != len(c.inference.objChain)+len(cand.path)+1 { 71031- return false 71032- } 71033- 71034- if chain[len(chain)-1] != cand.obj { 71035- return false 71036- } 71037- 71038- for i, o := range c.inference.objChain { 71039- if chain[i] != o { 71040- return false 71041- } 71042- } 71043- 71044- for i, o := range cand.path { 71045- if chain[i+len(c.inference.objChain)] != o { 71046- return false 71047- } 71048- } 71049- 71050- return true 71051-} 71052diff -urN a/gopls/internal/lsp/source/completion/deep_completion_test.go b/gopls/internal/lsp/source/completion/deep_completion_test.go 71053--- a/gopls/internal/lsp/source/completion/deep_completion_test.go 2000-01-01 00:00:00.000000000 -0000 71054+++ b/gopls/internal/lsp/source/completion/deep_completion_test.go 1970-01-01 00:00:00.000000000 +0000 71055@@ -1,33 +0,0 @@ 71056-// Copyright 2020 The Go Authors. All rights reserved. 71057-// Use of this source code is governed by a BSD-style 71058-// license that can be found in the LICENSE file. 71059- 71060-package completion 71061- 71062-import ( 71063- "testing" 71064-) 71065- 71066-func TestDeepCompletionIsHighScore(t *testing.T) { 71067- // Test that deepCompletionState.isHighScore properly tracks the top 71068- // N=MaxDeepCompletions scores. 71069- 71070- var s deepCompletionState 71071- 71072- if !s.isHighScore(1) { 71073- // No other scores yet, anything is a winner. 71074- t.Error("1 should be high score") 71075- } 71076- 71077- // Fill up with higher scores. 71078- for i := 0; i < MaxDeepCompletions; i++ { 71079- if !s.isHighScore(10) { 71080- t.Error("10 should be high score") 71081- } 71082- } 71083- 71084- // High scores should be filled with 10s so 2 is not a high score. 71085- if s.isHighScore(2) { 71086- t.Error("2 shouldn't be high score") 71087- } 71088-} 71089diff -urN a/gopls/internal/lsp/source/completion/definition.go b/gopls/internal/lsp/source/completion/definition.go 71090--- a/gopls/internal/lsp/source/completion/definition.go 2000-01-01 00:00:00.000000000 -0000 71091+++ b/gopls/internal/lsp/source/completion/definition.go 1970-01-01 00:00:00.000000000 +0000 71092@@ -1,160 +0,0 @@ 71093-// Copyright 2022 The Go Authors. All rights reserved. 71094-// Use of this source code is governed by a BSD-style 71095-// license that can be found in the LICENSE file. 71096- 71097-package completion 71098- 71099-import ( 71100- "go/ast" 71101- "go/types" 71102- "strings" 71103- "unicode" 71104- "unicode/utf8" 71105- 71106- "golang.org/x/tools/gopls/internal/lsp/protocol" 71107- "golang.org/x/tools/gopls/internal/lsp/snippet" 71108- "golang.org/x/tools/gopls/internal/lsp/source" 71109-) 71110- 71111-// some function definitions in test files can be completed 71112-// So far, TestFoo(t *testing.T), TestMain(m *testing.M) 71113-// BenchmarkFoo(b *testing.B), FuzzFoo(f *testing.F) 71114- 71115-// path[0] is known to be *ast.Ident 71116-func definition(path []ast.Node, obj types.Object, pgf *source.ParsedGoFile) ([]CompletionItem, *Selection) { 71117- if _, ok := obj.(*types.Func); !ok { 71118- return nil, nil // not a function at all 71119- } 71120- if !strings.HasSuffix(pgf.URI.Filename(), "_test.go") { 71121- return nil, nil // not a test file 71122- } 71123- 71124- name := path[0].(*ast.Ident).Name 71125- if len(name) == 0 { 71126- // can't happen 71127- return nil, nil 71128- } 71129- start := path[0].Pos() 71130- end := path[0].End() 71131- sel := &Selection{ 71132- content: "", 71133- cursor: start, 71134- tokFile: pgf.Tok, 71135- start: start, 71136- end: end, 71137- mapper: pgf.Mapper, 71138- } 71139- var ans []CompletionItem 71140- var hasParens bool 71141- n, ok := path[1].(*ast.FuncDecl) 71142- if !ok { 71143- return nil, nil // can't happen 71144- } 71145- if n.Recv != nil { 71146- return nil, nil // a method, not a function 71147- } 71148- t := n.Type.Params 71149- if t.Closing != t.Opening { 71150- hasParens = true 71151- } 71152- 71153- // Always suggest TestMain, if possible 71154- if strings.HasPrefix("TestMain", name) { 71155- if hasParens { 71156- ans = append(ans, defItem("TestMain", obj)) 71157- } else { 71158- ans = append(ans, defItem("TestMain(m *testing.M)", obj)) 71159- } 71160- } 71161- 71162- // If a snippet is possible, suggest it 71163- if strings.HasPrefix("Test", name) { 71164- if hasParens { 71165- ans = append(ans, defItem("Test", obj)) 71166- } else { 71167- ans = append(ans, defSnippet("Test", "(t *testing.T)", obj)) 71168- } 71169- return ans, sel 71170- } else if strings.HasPrefix("Benchmark", name) { 71171- if hasParens { 71172- ans = append(ans, defItem("Benchmark", obj)) 71173- } else { 71174- ans = append(ans, defSnippet("Benchmark", "(b *testing.B)", obj)) 71175- } 71176- return ans, sel 71177- } else if strings.HasPrefix("Fuzz", name) { 71178- if hasParens { 71179- ans = append(ans, defItem("Fuzz", obj)) 71180- } else { 71181- ans = append(ans, defSnippet("Fuzz", "(f *testing.F)", obj)) 71182- } 71183- return ans, sel 71184- } 71185- 71186- // Fill in the argument for what the user has already typed 71187- if got := defMatches(name, "Test", path, "(t *testing.T)"); got != "" { 71188- ans = append(ans, defItem(got, obj)) 71189- } else if got := defMatches(name, "Benchmark", path, "(b *testing.B)"); got != "" { 71190- ans = append(ans, defItem(got, obj)) 71191- } else if got := defMatches(name, "Fuzz", path, "(f *testing.F)"); got != "" { 71192- ans = append(ans, defItem(got, obj)) 71193- } 71194- return ans, sel 71195-} 71196- 71197-// defMatches returns text for defItem, never for defSnippet 71198-func defMatches(name, pat string, path []ast.Node, arg string) string { 71199- if !strings.HasPrefix(name, pat) { 71200- return "" 71201- } 71202- c, _ := utf8.DecodeRuneInString(name[len(pat):]) 71203- if unicode.IsLower(c) { 71204- return "" 71205- } 71206- fd, ok := path[1].(*ast.FuncDecl) 71207- if !ok { 71208- // we don't know what's going on 71209- return "" 71210- } 71211- fp := fd.Type.Params 71212- if len(fp.List) > 0 { 71213- // signature already there, nothing to suggest 71214- return "" 71215- } 71216- if fp.Opening != fp.Closing { 71217- // nothing: completion works on words, not easy to insert arg 71218- return "" 71219- } 71220- // suggesting signature too 71221- return name + arg 71222-} 71223- 71224-func defSnippet(prefix, suffix string, obj types.Object) CompletionItem { 71225- var sn snippet.Builder 71226- sn.WriteText(prefix) 71227- sn.WritePlaceholder(func(b *snippet.Builder) { b.WriteText("Xxx") }) 71228- sn.WriteText(suffix + " {\n\t") 71229- sn.WriteFinalTabstop() 71230- sn.WriteText("\n}") 71231- return CompletionItem{ 71232- Label: prefix + "Xxx" + suffix, 71233- Detail: "tab, type the rest of the name, then tab", 71234- Kind: protocol.FunctionCompletion, 71235- Depth: 0, 71236- Score: 10, 71237- snippet: &sn, 71238- Documentation: prefix + " test function", 71239- isSlice: isSlice(obj), 71240- } 71241-} 71242-func defItem(val string, obj types.Object) CompletionItem { 71243- return CompletionItem{ 71244- Label: val, 71245- InsertText: val, 71246- Kind: protocol.FunctionCompletion, 71247- Depth: 0, 71248- Score: 9, // prefer the snippets when available 71249- Documentation: "complete the function name", 71250- isSlice: isSlice(obj), 71251- } 71252-} 71253diff -urN a/gopls/internal/lsp/source/completion/format.go b/gopls/internal/lsp/source/completion/format.go 71254--- a/gopls/internal/lsp/source/completion/format.go 2000-01-01 00:00:00.000000000 -0000 71255+++ b/gopls/internal/lsp/source/completion/format.go 1970-01-01 00:00:00.000000000 +0000 71256@@ -1,338 +0,0 @@ 71257-// Copyright 2019 The Go Authors. All rights reserved. 71258-// Use of this source code is governed by a BSD-style 71259-// license that can be found in the LICENSE file. 71260- 71261-package completion 71262- 71263-import ( 71264- "context" 71265- "errors" 71266- "fmt" 71267- "go/ast" 71268- "go/doc" 71269- "go/types" 71270- "strings" 71271- 71272- "golang.org/x/tools/gopls/internal/lsp/protocol" 71273- "golang.org/x/tools/gopls/internal/lsp/safetoken" 71274- "golang.org/x/tools/gopls/internal/lsp/snippet" 71275- "golang.org/x/tools/gopls/internal/lsp/source" 71276- "golang.org/x/tools/gopls/internal/span" 71277- "golang.org/x/tools/internal/event" 71278- "golang.org/x/tools/internal/imports" 71279- "golang.org/x/tools/internal/typeparams" 71280-) 71281- 71282-var ( 71283- errNoMatch = errors.New("not a surrounding match") 71284- errLowScore = errors.New("not a high scoring candidate") 71285-) 71286- 71287-// item formats a candidate to a CompletionItem. 71288-func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, error) { 71289- obj := cand.obj 71290- 71291- // if the object isn't a valid match against the surrounding, return early. 71292- matchScore := c.matcher.Score(cand.name) 71293- if matchScore <= 0 { 71294- return CompletionItem{}, errNoMatch 71295- } 71296- cand.score *= float64(matchScore) 71297- 71298- // Ignore deep candidates that won't be in the MaxDeepCompletions anyway. 71299- if len(cand.path) != 0 && !c.deepState.isHighScore(cand.score) { 71300- return CompletionItem{}, errLowScore 71301- } 71302- 71303- // Handle builtin types separately. 71304- if obj.Parent() == types.Universe { 71305- return c.formatBuiltin(ctx, cand) 71306- } 71307- 71308- var ( 71309- label = cand.name 71310- detail = types.TypeString(obj.Type(), c.qf) 71311- insert = label 71312- kind = protocol.TextCompletion 71313- snip snippet.Builder 71314- protocolEdits []protocol.TextEdit 71315- ) 71316- if obj.Type() == nil { 71317- detail = "" 71318- } 71319- if isTypeName(obj) && c.wantTypeParams() { 71320- x := cand.obj.(*types.TypeName) 71321- if named, ok := x.Type().(*types.Named); ok { 71322- tp := typeparams.ForNamed(named) 71323- label += source.FormatTypeParams(tp) 71324- insert = label // maintain invariant above (label == insert) 71325- } 71326- } 71327- 71328- snip.WriteText(insert) 71329- 71330- switch obj := obj.(type) { 71331- case *types.TypeName: 71332- detail, kind = source.FormatType(obj.Type(), c.qf) 71333- case *types.Const: 71334- kind = protocol.ConstantCompletion 71335- case *types.Var: 71336- if _, ok := obj.Type().(*types.Struct); ok { 71337- detail = "struct{...}" // for anonymous structs 71338- } else if obj.IsField() { 71339- var err error 71340- detail, err = source.FormatVarType(ctx, c.snapshot, c.pkg, obj, c.qf, c.mq) 71341- if err != nil { 71342- return CompletionItem{}, err 71343- } 71344- } 71345- if obj.IsField() { 71346- kind = protocol.FieldCompletion 71347- c.structFieldSnippet(cand, detail, &snip) 71348- } else { 71349- kind = protocol.VariableCompletion 71350- } 71351- if obj.Type() == nil { 71352- break 71353- } 71354- case *types.Func: 71355- sig, ok := obj.Type().Underlying().(*types.Signature) 71356- if !ok { 71357- break 71358- } 71359- kind = protocol.FunctionCompletion 71360- if sig != nil && sig.Recv() != nil { 71361- kind = protocol.MethodCompletion 71362- } 71363- case *types.PkgName: 71364- kind = protocol.ModuleCompletion 71365- detail = fmt.Sprintf("%q", obj.Imported().Path()) 71366- case *types.Label: 71367- kind = protocol.ConstantCompletion 71368- detail = "label" 71369- } 71370- 71371- var prefix string 71372- for _, mod := range cand.mods { 71373- switch mod { 71374- case reference: 71375- prefix = "&" + prefix 71376- case dereference: 71377- prefix = "*" + prefix 71378- case chanRead: 71379- prefix = "<-" + prefix 71380- } 71381- } 71382- 71383- var ( 71384- suffix string 71385- funcType = obj.Type() 71386- ) 71387-Suffixes: 71388- for _, mod := range cand.mods { 71389- switch mod { 71390- case invoke: 71391- if sig, ok := funcType.Underlying().(*types.Signature); ok { 71392- s, err := source.NewSignature(ctx, c.snapshot, c.pkg, sig, nil, c.qf, c.mq) 71393- if err != nil { 71394- return CompletionItem{}, err 71395- } 71396- c.functionCallSnippet("", s.TypeParams(), s.Params(), &snip) 71397- if sig.Results().Len() == 1 { 71398- funcType = sig.Results().At(0).Type() 71399- } 71400- detail = "func" + s.Format() 71401- } 71402- 71403- if !c.opts.snippets { 71404- // Without snippets the candidate will not include "()". Don't 71405- // add further suffixes since they will be invalid. For 71406- // example, with snippets "foo()..." would become "foo..." 71407- // without snippets if we added the dotDotDot. 71408- break Suffixes 71409- } 71410- case takeSlice: 71411- suffix += "[:]" 71412- case takeDotDotDot: 71413- suffix += "..." 71414- case index: 71415- snip.WriteText("[") 71416- snip.WritePlaceholder(nil) 71417- snip.WriteText("]") 71418- } 71419- } 71420- 71421- // If this candidate needs an additional import statement, 71422- // add the additional text edits needed. 71423- if cand.imp != nil { 71424- addlEdits, err := c.importEdits(cand.imp) 71425- 71426- if err != nil { 71427- return CompletionItem{}, err 71428- } 71429- 71430- protocolEdits = append(protocolEdits, addlEdits...) 71431- if kind != protocol.ModuleCompletion { 71432- if detail != "" { 71433- detail += " " 71434- } 71435- detail += fmt.Sprintf("(from %q)", cand.imp.importPath) 71436- } 71437- } 71438- 71439- if cand.convertTo != nil { 71440- typeName := types.TypeString(cand.convertTo, c.qf) 71441- 71442- switch cand.convertTo.(type) { 71443- // We need extra parens when casting to these types. For example, 71444- // we need "(*int)(foo)", not "*int(foo)". 71445- case *types.Pointer, *types.Signature: 71446- typeName = "(" + typeName + ")" 71447- } 71448- 71449- prefix = typeName + "(" + prefix 71450- suffix = ")" 71451- } 71452- 71453- if prefix != "" { 71454- // If we are in a selector, add an edit to place prefix before selector. 71455- if sel := enclosingSelector(c.path, c.pos); sel != nil { 71456- edits, err := c.editText(sel.Pos(), sel.Pos(), prefix) 71457- if err != nil { 71458- return CompletionItem{}, err 71459- } 71460- protocolEdits = append(protocolEdits, edits...) 71461- } else { 71462- // If there is no selector, just stick the prefix at the start. 71463- insert = prefix + insert 71464- snip.PrependText(prefix) 71465- } 71466- } 71467- 71468- if suffix != "" { 71469- insert += suffix 71470- snip.WriteText(suffix) 71471- } 71472- 71473- detail = strings.TrimPrefix(detail, "untyped ") 71474- // override computed detail with provided detail, if something is provided. 71475- if cand.detail != "" { 71476- detail = cand.detail 71477- } 71478- item := CompletionItem{ 71479- Label: label, 71480- InsertText: insert, 71481- AdditionalTextEdits: protocolEdits, 71482- Detail: detail, 71483- Kind: kind, 71484- Score: cand.score, 71485- Depth: len(cand.path), 71486- snippet: &snip, 71487- isSlice: isSlice(obj), 71488- } 71489- // If the user doesn't want documentation for completion items. 71490- if !c.opts.documentation { 71491- return item, nil 71492- } 71493- pos := safetoken.StartPosition(c.pkg.FileSet(), obj.Pos()) 71494- 71495- // We ignore errors here, because some types, like "unsafe" or "error", 71496- // may not have valid positions that we can use to get documentation. 71497- if !pos.IsValid() { 71498- return item, nil 71499- } 71500- 71501- comment, err := source.HoverDocForObject(ctx, c.snapshot, c.pkg.FileSet(), obj) 71502- if err != nil { 71503- event.Error(ctx, fmt.Sprintf("failed to find Hover for %q", obj.Name()), err) 71504- return item, nil 71505- } 71506- if c.opts.fullDocumentation { 71507- item.Documentation = comment.Text() 71508- } else { 71509- item.Documentation = doc.Synopsis(comment.Text()) 71510- } 71511- // The desired pattern is `^// Deprecated`, but the prefix has been removed 71512- // TODO(rfindley): It doesn't look like this does the right thing for 71513- // multi-line comments. 71514- if strings.HasPrefix(comment.Text(), "Deprecated") { 71515- if c.snapshot.View().Options().CompletionTags { 71516- item.Tags = []protocol.CompletionItemTag{protocol.ComplDeprecated} 71517- } else if c.snapshot.View().Options().CompletionDeprecated { 71518- item.Deprecated = true 71519- } 71520- } 71521- 71522- return item, nil 71523-} 71524- 71525-// importEdits produces the text edits necessary to add the given import to the current file. 71526-func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) { 71527- if imp == nil { 71528- return nil, nil 71529- } 71530- 71531- pgf, err := c.pkg.File(span.URIFromPath(c.filename)) 71532- if err != nil { 71533- return nil, err 71534- } 71535- 71536- return source.ComputeOneImportFixEdits(c.snapshot, pgf, &imports.ImportFix{ 71537- StmtInfo: imports.ImportInfo{ 71538- ImportPath: imp.importPath, 71539- Name: imp.name, 71540- }, 71541- // IdentName is unused on this path and is difficult to get. 71542- FixType: imports.AddImport, 71543- }) 71544-} 71545- 71546-func (c *completer) formatBuiltin(ctx context.Context, cand candidate) (CompletionItem, error) { 71547- obj := cand.obj 71548- item := CompletionItem{ 71549- Label: obj.Name(), 71550- InsertText: obj.Name(), 71551- Score: cand.score, 71552- } 71553- switch obj.(type) { 71554- case *types.Const: 71555- item.Kind = protocol.ConstantCompletion 71556- case *types.Builtin: 71557- item.Kind = protocol.FunctionCompletion 71558- sig, err := source.NewBuiltinSignature(ctx, c.snapshot, obj.Name()) 71559- if err != nil { 71560- return CompletionItem{}, err 71561- } 71562- item.Detail = "func" + sig.Format() 71563- item.snippet = &snippet.Builder{} 71564- c.functionCallSnippet(obj.Name(), sig.TypeParams(), sig.Params(), item.snippet) 71565- case *types.TypeName: 71566- if types.IsInterface(obj.Type()) { 71567- item.Kind = protocol.InterfaceCompletion 71568- } else { 71569- item.Kind = protocol.ClassCompletion 71570- } 71571- case *types.Nil: 71572- item.Kind = protocol.VariableCompletion 71573- } 71574- return item, nil 71575-} 71576- 71577-// decide if the type params (if any) should be part of the completion 71578-// which only possible for types.Named and types.Signature 71579-// (so far, only in receivers, e.g.; func (s *GENERIC[K, V])..., which is a types.Named) 71580-func (c *completer) wantTypeParams() bool { 71581- // Need to be lexically in a receiver, and a child of an IndexListExpr 71582- // (but IndexListExpr only exists with go1.18) 71583- start := c.path[0].Pos() 71584- for i, nd := range c.path { 71585- if fd, ok := nd.(*ast.FuncDecl); ok { 71586- if i > 0 && fd.Recv != nil && start < fd.Recv.End() { 71587- return true 71588- } else { 71589- return false 71590- } 71591- } 71592- } 71593- return false 71594-} 71595diff -urN a/gopls/internal/lsp/source/completion/fuzz.go b/gopls/internal/lsp/source/completion/fuzz.go 71596--- a/gopls/internal/lsp/source/completion/fuzz.go 2000-01-01 00:00:00.000000000 -0000 71597+++ b/gopls/internal/lsp/source/completion/fuzz.go 1970-01-01 00:00:00.000000000 +0000 71598@@ -1,142 +0,0 @@ 71599-// Copyright 2022 The Go Authors. All rights reserved. 71600-// Use of this source code is governed by a BSD-style 71601-// license that can be found in the LICENSE file. 71602- 71603-package completion 71604- 71605-import ( 71606- "fmt" 71607- "go/ast" 71608- "go/token" 71609- "go/types" 71610- "strings" 71611- 71612- "golang.org/x/tools/gopls/internal/lsp/protocol" 71613-) 71614- 71615-// golang/go#51089 71616-// *testing.F deserves special treatment as member use is constrained: 71617-// The arguments to f.Fuzz are determined by the arguments to a previous f.Add 71618-// Inside f.Fuzz only f.Failed and f.Name are allowed. 71619-// PJW: are there other packages where we can deduce usage constraints? 71620- 71621-// if we find fuzz completions, then return true, as those are the only completions to offer 71622-func (c *completer) fuzz(typ types.Type, mset *types.MethodSet, imp *importInfo, cb func(candidate), fset *token.FileSet) bool { 71623- // 1. inside f.Fuzz? (only f.Failed and f.Name) 71624- // 2. possible completing f.Fuzz? 71625- // [Ident,SelectorExpr,Callexpr,ExprStmt,BlockiStmt,FuncDecl(Fuzz...)] 71626- // 3. before f.Fuzz, same (for 2., offer choice when looking at an F) 71627- 71628- // does the path contain FuncLit as arg to f.Fuzz CallExpr? 71629- inside := false 71630-Loop: 71631- for i, n := range c.path { 71632- switch v := n.(type) { 71633- case *ast.CallExpr: 71634- if len(v.Args) != 1 { 71635- continue Loop 71636- } 71637- if _, ok := v.Args[0].(*ast.FuncLit); !ok { 71638- continue 71639- } 71640- if s, ok := v.Fun.(*ast.SelectorExpr); !ok || s.Sel.Name != "Fuzz" { 71641- continue 71642- } 71643- if i > 2 { // avoid t.Fuzz itself in tests 71644- inside = true 71645- break Loop 71646- } 71647- } 71648- } 71649- if inside { 71650- for i := 0; i < mset.Len(); i++ { 71651- o := mset.At(i).Obj() 71652- if o.Name() == "Failed" || o.Name() == "Name" { 71653- cb(candidate{ 71654- obj: o, 71655- score: stdScore, 71656- imp: imp, 71657- addressable: true, 71658- }) 71659- } 71660- } 71661- return true 71662- } 71663- // if it could be t.Fuzz, look for the preceding t.Add 71664- id, ok := c.path[0].(*ast.Ident) 71665- if ok && strings.HasPrefix("Fuzz", id.Name) { 71666- var add *ast.CallExpr 71667- f := func(n ast.Node) bool { 71668- if n == nil { 71669- return true 71670- } 71671- call, ok := n.(*ast.CallExpr) 71672- if !ok { 71673- return true 71674- } 71675- s, ok := call.Fun.(*ast.SelectorExpr) 71676- if !ok { 71677- return true 71678- } 71679- if s.Sel.Name != "Add" { 71680- return true 71681- } 71682- // Sel.X should be of type *testing.F 71683- got := c.pkg.GetTypesInfo().Types[s.X] 71684- if got.Type.String() == "*testing.F" { 71685- add = call 71686- } 71687- return false // because we're done... 71688- } 71689- // look at the enclosing FuzzFoo functions 71690- if len(c.path) < 2 { 71691- return false 71692- } 71693- n := c.path[len(c.path)-2] 71694- if _, ok := n.(*ast.FuncDecl); !ok { 71695- // the path should start with ast.File, ast.FuncDecl, ... 71696- // but it didn't, so give up 71697- return false 71698- } 71699- ast.Inspect(n, f) 71700- if add == nil { 71701- // looks like f.Fuzz without a preceding f.Add. 71702- // let the regular completion handle it. 71703- return false 71704- } 71705- 71706- lbl := "Fuzz(func(t *testing.T" 71707- for i, a := range add.Args { 71708- info := c.pkg.GetTypesInfo().TypeOf(a) 71709- if info == nil { 71710- return false // How could this happen, but better safe than panic. 71711- } 71712- lbl += fmt.Sprintf(", %c %s", 'a'+i, info) 71713- } 71714- lbl += ")" 71715- xx := CompletionItem{ 71716- Label: lbl, 71717- InsertText: lbl, 71718- Kind: protocol.FunctionCompletion, 71719- Depth: 0, 71720- Score: 10, // pretty confident the user should see this 71721- Documentation: "argument types from f.Add", 71722- isSlice: false, 71723- } 71724- c.items = append(c.items, xx) 71725- for i := 0; i < mset.Len(); i++ { 71726- o := mset.At(i).Obj() 71727- if o.Name() != "Fuzz" { 71728- cb(candidate{ 71729- obj: o, 71730- score: stdScore, 71731- imp: imp, 71732- addressable: true, 71733- }) 71734- } 71735- } 71736- return true // done 71737- } 71738- // let the standard processing take care of it instead 71739- return false 71740-} 71741diff -urN a/gopls/internal/lsp/source/completion/keywords.go b/gopls/internal/lsp/source/completion/keywords.go 71742--- a/gopls/internal/lsp/source/completion/keywords.go 2000-01-01 00:00:00.000000000 -0000 71743+++ b/gopls/internal/lsp/source/completion/keywords.go 1970-01-01 00:00:00.000000000 +0000 71744@@ -1,154 +0,0 @@ 71745-// Copyright 2020 The Go Authors. All rights reserved. 71746-// Use of this source code is governed by a BSD-style 71747-// license that can be found in the LICENSE file. 71748- 71749-package completion 71750- 71751-import ( 71752- "go/ast" 71753- 71754- "golang.org/x/tools/gopls/internal/lsp/protocol" 71755- "golang.org/x/tools/gopls/internal/lsp/source" 71756-) 71757- 71758-const ( 71759- BREAK = "break" 71760- CASE = "case" 71761- CHAN = "chan" 71762- CONST = "const" 71763- CONTINUE = "continue" 71764- DEFAULT = "default" 71765- DEFER = "defer" 71766- ELSE = "else" 71767- FALLTHROUGH = "fallthrough" 71768- FOR = "for" 71769- FUNC = "func" 71770- GO = "go" 71771- GOTO = "goto" 71772- IF = "if" 71773- IMPORT = "import" 71774- INTERFACE = "interface" 71775- MAP = "map" 71776- PACKAGE = "package" 71777- RANGE = "range" 71778- RETURN = "return" 71779- SELECT = "select" 71780- STRUCT = "struct" 71781- SWITCH = "switch" 71782- TYPE = "type" 71783- VAR = "var" 71784-) 71785- 71786-// addKeywordCompletions offers keyword candidates appropriate at the position. 71787-func (c *completer) addKeywordCompletions() { 71788- seen := make(map[string]bool) 71789- 71790- if c.wantTypeName() && c.inference.objType == nil { 71791- // If we want a type name but don't have an expected obj type, 71792- // include "interface", "struct", "func", "chan", and "map". 71793- 71794- // "interface" and "struct" are more common declaring named types. 71795- // Give them a higher score if we are in a type declaration. 71796- structIntf, funcChanMap := stdScore, highScore 71797- if len(c.path) > 1 { 71798- if _, namedDecl := c.path[1].(*ast.TypeSpec); namedDecl { 71799- structIntf, funcChanMap = highScore, stdScore 71800- } 71801- } 71802- 71803- c.addKeywordItems(seen, structIntf, STRUCT, INTERFACE) 71804- c.addKeywordItems(seen, funcChanMap, FUNC, CHAN, MAP) 71805- } 71806- 71807- // If we are at the file scope, only offer decl keywords. We don't 71808- // get *ast.Idents at the file scope because non-keyword identifiers 71809- // turn into *ast.BadDecl, not *ast.Ident. 71810- if len(c.path) == 1 || isASTFile(c.path[1]) { 71811- c.addKeywordItems(seen, stdScore, TYPE, CONST, VAR, FUNC, IMPORT) 71812- return 71813- } else if _, ok := c.path[0].(*ast.Ident); !ok { 71814- // Otherwise only offer keywords if the client is completing an identifier. 71815- return 71816- } 71817- 71818- if len(c.path) > 2 { 71819- // Offer "range" if we are in ast.ForStmt.Init. This is what the 71820- // AST looks like before "range" is typed, e.g. "for i := r<>". 71821- if loop, ok := c.path[2].(*ast.ForStmt); ok && source.NodeContains(loop.Init, c.pos) { 71822- c.addKeywordItems(seen, stdScore, RANGE) 71823- } 71824- } 71825- 71826- // Only suggest keywords if we are beginning a statement. 71827- switch n := c.path[1].(type) { 71828- case *ast.BlockStmt, *ast.ExprStmt: 71829- // OK - our ident must be at beginning of statement. 71830- case *ast.CommClause: 71831- // Make sure we aren't in the Comm statement. 71832- if !n.Colon.IsValid() || c.pos <= n.Colon { 71833- return 71834- } 71835- case *ast.CaseClause: 71836- // Make sure we aren't in the case List. 71837- if !n.Colon.IsValid() || c.pos <= n.Colon { 71838- return 71839- } 71840- default: 71841- return 71842- } 71843- 71844- // Filter out keywords depending on scope 71845- // Skip the first one because we want to look at the enclosing scopes 71846- path := c.path[1:] 71847- for i, n := range path { 71848- switch node := n.(type) { 71849- case *ast.CaseClause: 71850- // only recommend "fallthrough" and "break" within the bodies of a case clause 71851- if c.pos > node.Colon { 71852- c.addKeywordItems(seen, stdScore, BREAK) 71853- // "fallthrough" is only valid in switch statements. 71854- // A case clause is always nested within a block statement in a switch statement, 71855- // that block statement is nested within either a TypeSwitchStmt or a SwitchStmt. 71856- if i+2 >= len(path) { 71857- continue 71858- } 71859- if _, ok := path[i+2].(*ast.SwitchStmt); ok { 71860- c.addKeywordItems(seen, stdScore, FALLTHROUGH) 71861- } 71862- } 71863- case *ast.CommClause: 71864- if c.pos > node.Colon { 71865- c.addKeywordItems(seen, stdScore, BREAK) 71866- } 71867- case *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.SwitchStmt: 71868- c.addKeywordItems(seen, stdScore, CASE, DEFAULT) 71869- case *ast.ForStmt, *ast.RangeStmt: 71870- c.addKeywordItems(seen, stdScore, BREAK, CONTINUE) 71871- // This is a bit weak, functions allow for many keywords 71872- case *ast.FuncDecl: 71873- if node.Body != nil && c.pos > node.Body.Lbrace { 71874- c.addKeywordItems(seen, stdScore, DEFER, RETURN, FOR, GO, SWITCH, SELECT, IF, ELSE, VAR, CONST, GOTO, TYPE) 71875- } 71876- } 71877- } 71878-} 71879- 71880-// addKeywordItems dedupes and adds completion items for the specified 71881-// keywords with the specified score. 71882-func (c *completer) addKeywordItems(seen map[string]bool, score float64, kws ...string) { 71883- for _, kw := range kws { 71884- if seen[kw] { 71885- continue 71886- } 71887- seen[kw] = true 71888- 71889- if matchScore := c.matcher.Score(kw); matchScore > 0 { 71890- c.items = append(c.items, CompletionItem{ 71891- Label: kw, 71892- Kind: protocol.KeywordCompletion, 71893- InsertText: kw, 71894- Score: score * float64(matchScore), 71895- }) 71896- } 71897- } 71898-} 71899diff -urN a/gopls/internal/lsp/source/completion/labels.go b/gopls/internal/lsp/source/completion/labels.go 71900--- a/gopls/internal/lsp/source/completion/labels.go 2000-01-01 00:00:00.000000000 -0000 71901+++ b/gopls/internal/lsp/source/completion/labels.go 1970-01-01 00:00:00.000000000 +0000 71902@@ -1,112 +0,0 @@ 71903-// Copyright 2019 The Go Authors. All rights reserved. 71904-// Use of this source code is governed by a BSD-style 71905-// license that can be found in the LICENSE file. 71906- 71907-package completion 71908- 71909-import ( 71910- "go/ast" 71911- "go/token" 71912- "math" 71913-) 71914- 71915-type labelType int 71916- 71917-const ( 71918- labelNone labelType = iota 71919- labelBreak 71920- labelContinue 71921- labelGoto 71922-) 71923- 71924-// wantLabelCompletion returns true if we want (only) label 71925-// completions at the position. 71926-func (c *completer) wantLabelCompletion() labelType { 71927- if _, ok := c.path[0].(*ast.Ident); ok && len(c.path) > 1 { 71928- // We want a label if we are an *ast.Ident child of a statement 71929- // that accepts a label, e.g. "break Lo<>". 71930- return takesLabel(c.path[1]) 71931- } 71932- 71933- return labelNone 71934-} 71935- 71936-// takesLabel returns the corresponding labelType if n is a statement 71937-// that accepts a label, otherwise labelNone. 71938-func takesLabel(n ast.Node) labelType { 71939- if bs, ok := n.(*ast.BranchStmt); ok { 71940- switch bs.Tok { 71941- case token.BREAK: 71942- return labelBreak 71943- case token.CONTINUE: 71944- return labelContinue 71945- case token.GOTO: 71946- return labelGoto 71947- } 71948- } 71949- return labelNone 71950-} 71951- 71952-// labels adds completion items for labels defined in the enclosing 71953-// function. 71954-func (c *completer) labels(lt labelType) { 71955- if c.enclosingFunc == nil { 71956- return 71957- } 71958- 71959- addLabel := func(score float64, l *ast.LabeledStmt) { 71960- labelObj := c.pkg.GetTypesInfo().ObjectOf(l.Label) 71961- if labelObj != nil { 71962- c.deepState.enqueue(candidate{obj: labelObj, score: score}) 71963- } 71964- } 71965- 71966- switch lt { 71967- case labelBreak, labelContinue: 71968- // "break" and "continue" only accept labels from enclosing statements. 71969- 71970- for i, p := range c.path { 71971- switch p := p.(type) { 71972- case *ast.FuncLit: 71973- // Labels are function scoped, so don't continue out of functions. 71974- return 71975- case *ast.LabeledStmt: 71976- switch p.Stmt.(type) { 71977- case *ast.ForStmt, *ast.RangeStmt: 71978- // Loop labels can be used for "break" or "continue". 71979- addLabel(highScore*math.Pow(.99, float64(i)), p) 71980- case *ast.SwitchStmt, *ast.SelectStmt, *ast.TypeSwitchStmt: 71981- // Switch and select labels can be used only for "break". 71982- if lt == labelBreak { 71983- addLabel(highScore*math.Pow(.99, float64(i)), p) 71984- } 71985- } 71986- } 71987- } 71988- case labelGoto: 71989- // Goto accepts any label in the same function not in a nested 71990- // block. It also doesn't take labels that would jump across 71991- // variable definitions, but ignore that case for now. 71992- ast.Inspect(c.enclosingFunc.body, func(n ast.Node) bool { 71993- if n == nil { 71994- return false 71995- } 71996- 71997- switch n := n.(type) { 71998- // Only search into block-like nodes enclosing our "goto". 71999- // This prevents us from finding labels in nested blocks. 72000- case *ast.BlockStmt, *ast.CommClause, *ast.CaseClause: 72001- for _, p := range c.path { 72002- if n == p { 72003- return true 72004- } 72005- } 72006- return false 72007- case *ast.LabeledStmt: 72008- addLabel(highScore, n) 72009- } 72010- 72011- return true 72012- }) 72013- } 72014-} 72015diff -urN a/gopls/internal/lsp/source/completion/literal.go b/gopls/internal/lsp/source/completion/literal.go 72016--- a/gopls/internal/lsp/source/completion/literal.go 2000-01-01 00:00:00.000000000 -0000 72017+++ b/gopls/internal/lsp/source/completion/literal.go 1970-01-01 00:00:00.000000000 +0000 72018@@ -1,592 +0,0 @@ 72019-// Copyright 2019 The Go Authors. All rights reserved. 72020-// Use of this source code is governed by a BSD-style 72021-// license that can be found in the LICENSE file. 72022- 72023-package completion 72024- 72025-import ( 72026- "context" 72027- "fmt" 72028- "go/types" 72029- "strings" 72030- "unicode" 72031- 72032- "golang.org/x/tools/gopls/internal/lsp/protocol" 72033- "golang.org/x/tools/gopls/internal/lsp/snippet" 72034- "golang.org/x/tools/gopls/internal/lsp/source" 72035- "golang.org/x/tools/internal/event" 72036- "golang.org/x/tools/internal/typeparams" 72037-) 72038- 72039-// literal generates composite literal, function literal, and make() 72040-// completion items. 72041-func (c *completer) literal(ctx context.Context, literalType types.Type, imp *importInfo) { 72042- if !c.opts.literal { 72043- return 72044- } 72045- 72046- expType := c.inference.objType 72047- 72048- if c.inference.matchesVariadic(literalType) { 72049- // Don't offer literal slice candidates for variadic arguments. 72050- // For example, don't offer "[]interface{}{}" in "fmt.Print(<>)". 72051- return 72052- } 72053- 72054- // Avoid literal candidates if the expected type is an empty 72055- // interface. It isn't very useful to suggest a literal candidate of 72056- // every possible type. 72057- if expType != nil && isEmptyInterface(expType) { 72058- return 72059- } 72060- 72061- // We handle unnamed literal completions explicitly before searching 72062- // for candidates. Avoid named-type literal completions for 72063- // unnamed-type expected type since that results in duplicate 72064- // candidates. For example, in 72065- // 72066- // type mySlice []int 72067- // var []int = <> 72068- // 72069- // don't offer "mySlice{}" since we have already added a candidate 72070- // of "[]int{}". 72071- if _, named := literalType.(*types.Named); named && expType != nil { 72072- if _, named := source.Deref(expType).(*types.Named); !named { 72073- return 72074- } 72075- } 72076- 72077- // Check if an object of type literalType would match our expected type. 72078- cand := candidate{ 72079- obj: c.fakeObj(literalType), 72080- } 72081- 72082- switch literalType.Underlying().(type) { 72083- // These literal types are addressable (e.g. "&[]int{}"), others are 72084- // not (e.g. can't do "&(func(){})"). 72085- case *types.Struct, *types.Array, *types.Slice, *types.Map: 72086- cand.addressable = true 72087- } 72088- 72089- if !c.matchingCandidate(&cand) || cand.convertTo != nil { 72090- return 72091- } 72092- 72093- var ( 72094- qf = c.qf 72095- sel = enclosingSelector(c.path, c.pos) 72096- ) 72097- 72098- // Don't qualify the type name if we are in a selector expression 72099- // since the package name is already present. 72100- if sel != nil { 72101- qf = func(_ *types.Package) string { return "" } 72102- } 72103- 72104- snip, typeName := c.typeNameSnippet(literalType, qf) 72105- 72106- // A type name of "[]int" doesn't work very will with the matcher 72107- // since "[" isn't a valid identifier prefix. Here we strip off the 72108- // slice (and array) prefix yielding just "int". 72109- matchName := typeName 72110- switch t := literalType.(type) { 72111- case *types.Slice: 72112- matchName = types.TypeString(t.Elem(), qf) 72113- case *types.Array: 72114- matchName = types.TypeString(t.Elem(), qf) 72115- } 72116- 72117- addlEdits, err := c.importEdits(imp) 72118- if err != nil { 72119- event.Error(ctx, "error adding import for literal candidate", err) 72120- return 72121- } 72122- 72123- // If prefix matches the type name, client may want a composite literal. 72124- if score := c.matcher.Score(matchName); score > 0 { 72125- if cand.hasMod(reference) { 72126- if sel != nil { 72127- // If we are in a selector we must place the "&" before the selector. 72128- // For example, "foo.B<>" must complete to "&foo.Bar{}", not 72129- // "foo.&Bar{}". 72130- edits, err := c.editText(sel.Pos(), sel.Pos(), "&") 72131- if err != nil { 72132- event.Error(ctx, "error making edit for literal pointer completion", err) 72133- return 72134- } 72135- addlEdits = append(addlEdits, edits...) 72136- } else { 72137- // Otherwise we can stick the "&" directly before the type name. 72138- typeName = "&" + typeName 72139- snip.PrependText("&") 72140- } 72141- } 72142- 72143- switch t := literalType.Underlying().(type) { 72144- case *types.Struct, *types.Array, *types.Slice, *types.Map: 72145- c.compositeLiteral(t, snip.Clone(), typeName, float64(score), addlEdits) 72146- case *types.Signature: 72147- // Add a literal completion for a signature type that implements 72148- // an interface. For example, offer "http.HandlerFunc()" when 72149- // expected type is "http.Handler". 72150- if expType != nil && types.IsInterface(expType) { 72151- c.basicLiteral(t, snip.Clone(), typeName, float64(score), addlEdits) 72152- } 72153- case *types.Basic: 72154- // Add a literal completion for basic types that implement our 72155- // expected interface (e.g. named string type http.Dir 72156- // implements http.FileSystem), or are identical to our expected 72157- // type (i.e. yielding a type conversion such as "float64()"). 72158- if expType != nil && (types.IsInterface(expType) || types.Identical(expType, literalType)) { 72159- c.basicLiteral(t, snip.Clone(), typeName, float64(score), addlEdits) 72160- } 72161- } 72162- } 72163- 72164- // If prefix matches "make", client may want a "make()" 72165- // invocation. We also include the type name to allow for more 72166- // flexible fuzzy matching. 72167- if score := c.matcher.Score("make." + matchName); !cand.hasMod(reference) && score > 0 { 72168- switch literalType.Underlying().(type) { 72169- case *types.Slice: 72170- // The second argument to "make()" for slices is required, so default to "0". 72171- c.makeCall(snip.Clone(), typeName, "0", float64(score), addlEdits) 72172- case *types.Map, *types.Chan: 72173- // Maps and channels don't require the second argument, so omit 72174- // to keep things simple for now. 72175- c.makeCall(snip.Clone(), typeName, "", float64(score), addlEdits) 72176- } 72177- } 72178- 72179- // If prefix matches "func", client may want a function literal. 72180- if score := c.matcher.Score("func"); !cand.hasMod(reference) && score > 0 && (expType == nil || !types.IsInterface(expType)) { 72181- switch t := literalType.Underlying().(type) { 72182- case *types.Signature: 72183- c.functionLiteral(ctx, t, float64(score)) 72184- } 72185- } 72186-} 72187- 72188-// literalCandidateScore is the base score for literal candidates. 72189-// Literal candidates match the expected type so they should be high 72190-// scoring, but we want them ranked below lexical objects of the 72191-// correct type, so scale down highScore. 72192-const literalCandidateScore = highScore / 2 72193- 72194-// functionLiteral adds a function literal completion item for the 72195-// given signature. 72196-func (c *completer) functionLiteral(ctx context.Context, sig *types.Signature, matchScore float64) { 72197- snip := &snippet.Builder{} 72198- snip.WriteText("func(") 72199- 72200- // First we generate names for each param and keep a seen count so 72201- // we know if we need to uniquify param names. For example, 72202- // "func(int)" will become "func(i int)", but "func(int, int64)" 72203- // will become "func(i1 int, i2 int64)". 72204- var ( 72205- paramNames = make([]string, sig.Params().Len()) 72206- paramNameCount = make(map[string]int) 72207- hasTypeParams bool 72208- ) 72209- for i := 0; i < sig.Params().Len(); i++ { 72210- var ( 72211- p = sig.Params().At(i) 72212- name = p.Name() 72213- ) 72214- 72215- if tp, _ := p.Type().(*typeparams.TypeParam); tp != nil && !c.typeParamInScope(tp) { 72216- hasTypeParams = true 72217- } 72218- 72219- if name == "" { 72220- // If the param has no name in the signature, guess a name based 72221- // on the type. Use an empty qualifier to ignore the package. 72222- // For example, we want to name "http.Request" "r", not "hr". 72223- typeName, err := source.FormatVarType(ctx, c.snapshot, c.pkg, p, 72224- func(p *types.Package) string { return "" }, 72225- func(source.PackageName, source.ImportPath, source.PackagePath) string { return "" }) 72226- if err != nil { 72227- // In general, the only error we should encounter while formatting is 72228- // context cancellation. 72229- if ctx.Err() == nil { 72230- event.Error(ctx, "formatting var type", err) 72231- } 72232- return 72233- } 72234- name = abbreviateTypeName(typeName) 72235- } 72236- paramNames[i] = name 72237- if name != "_" { 72238- paramNameCount[name]++ 72239- } 72240- } 72241- 72242- for n, c := range paramNameCount { 72243- // Any names we saw more than once will need a unique suffix added 72244- // on. Reset the count to 1 to act as the suffix for the first 72245- // name. 72246- if c >= 2 { 72247- paramNameCount[n] = 1 72248- } else { 72249- delete(paramNameCount, n) 72250- } 72251- } 72252- 72253- for i := 0; i < sig.Params().Len(); i++ { 72254- if hasTypeParams && !c.opts.placeholders { 72255- // If there are type params in the args then the user must 72256- // choose the concrete types. If placeholders are disabled just 72257- // drop them between the parens and let them fill things in. 72258- snip.WritePlaceholder(nil) 72259- break 72260- } 72261- 72262- if i > 0 { 72263- snip.WriteText(", ") 72264- } 72265- 72266- var ( 72267- p = sig.Params().At(i) 72268- name = paramNames[i] 72269- ) 72270- 72271- // Uniquify names by adding on an incrementing numeric suffix. 72272- if idx, found := paramNameCount[name]; found { 72273- paramNameCount[name]++ 72274- name = fmt.Sprintf("%s%d", name, idx) 72275- } 72276- 72277- if name != p.Name() && c.opts.placeholders { 72278- // If we didn't use the signature's param name verbatim then we 72279- // may have chosen a poor name. Give the user a placeholder so 72280- // they can easily fix the name. 72281- snip.WritePlaceholder(func(b *snippet.Builder) { 72282- b.WriteText(name) 72283- }) 72284- } else { 72285- snip.WriteText(name) 72286- } 72287- 72288- // If the following param's type is identical to this one, omit 72289- // this param's type string. For example, emit "i, j int" instead 72290- // of "i int, j int". 72291- if i == sig.Params().Len()-1 || !types.Identical(p.Type(), sig.Params().At(i+1).Type()) { 72292- snip.WriteText(" ") 72293- typeStr, err := source.FormatVarType(ctx, c.snapshot, c.pkg, p, c.qf, c.mq) 72294- if err != nil { 72295- // In general, the only error we should encounter while formatting is 72296- // context cancellation. 72297- if ctx.Err() == nil { 72298- event.Error(ctx, "formatting var type", err) 72299- } 72300- return 72301- } 72302- if sig.Variadic() && i == sig.Params().Len()-1 { 72303- typeStr = strings.Replace(typeStr, "[]", "...", 1) 72304- } 72305- 72306- if tp, _ := p.Type().(*typeparams.TypeParam); tp != nil && !c.typeParamInScope(tp) { 72307- snip.WritePlaceholder(func(snip *snippet.Builder) { 72308- snip.WriteText(typeStr) 72309- }) 72310- } else { 72311- snip.WriteText(typeStr) 72312- } 72313- } 72314- } 72315- snip.WriteText(")") 72316- 72317- results := sig.Results() 72318- if results.Len() > 0 { 72319- snip.WriteText(" ") 72320- } 72321- 72322- resultsNeedParens := results.Len() > 1 || 72323- results.Len() == 1 && results.At(0).Name() != "" 72324- 72325- var resultHasTypeParams bool 72326- for i := 0; i < results.Len(); i++ { 72327- if tp, _ := results.At(i).Type().(*typeparams.TypeParam); tp != nil && !c.typeParamInScope(tp) { 72328- resultHasTypeParams = true 72329- } 72330- } 72331- 72332- if resultsNeedParens { 72333- snip.WriteText("(") 72334- } 72335- for i := 0; i < results.Len(); i++ { 72336- if resultHasTypeParams && !c.opts.placeholders { 72337- // Leave an empty tabstop if placeholders are disabled and there 72338- // are type args that need specificying. 72339- snip.WritePlaceholder(nil) 72340- break 72341- } 72342- 72343- if i > 0 { 72344- snip.WriteText(", ") 72345- } 72346- r := results.At(i) 72347- if name := r.Name(); name != "" { 72348- snip.WriteText(name + " ") 72349- } 72350- 72351- text, err := source.FormatVarType(ctx, c.snapshot, c.pkg, r, c.qf, c.mq) 72352- if err != nil { 72353- // In general, the only error we should encounter while formatting is 72354- // context cancellation. 72355- if ctx.Err() == nil { 72356- event.Error(ctx, "formatting var type", err) 72357- } 72358- return 72359- } 72360- if tp, _ := r.Type().(*typeparams.TypeParam); tp != nil && !c.typeParamInScope(tp) { 72361- snip.WritePlaceholder(func(snip *snippet.Builder) { 72362- snip.WriteText(text) 72363- }) 72364- } else { 72365- snip.WriteText(text) 72366- } 72367- } 72368- if resultsNeedParens { 72369- snip.WriteText(")") 72370- } 72371- 72372- snip.WriteText(" {") 72373- snip.WriteFinalTabstop() 72374- snip.WriteText("}") 72375- 72376- c.items = append(c.items, CompletionItem{ 72377- Label: "func(...) {}", 72378- Score: matchScore * literalCandidateScore, 72379- Kind: protocol.VariableCompletion, 72380- snippet: snip, 72381- }) 72382-} 72383- 72384-// conventionalAcronyms contains conventional acronyms for type names 72385-// in lower case. For example, "ctx" for "context" and "err" for "error". 72386-var conventionalAcronyms = map[string]string{ 72387- "context": "ctx", 72388- "error": "err", 72389- "tx": "tx", 72390- "responsewriter": "w", 72391-} 72392- 72393-// abbreviateTypeName abbreviates type names into acronyms. For 72394-// example, "fooBar" is abbreviated "fb". Care is taken to ignore 72395-// non-identifier runes. For example, "[]int" becomes "i", and 72396-// "struct { i int }" becomes "s". 72397-func abbreviateTypeName(s string) string { 72398- var ( 72399- b strings.Builder 72400- useNextUpper bool 72401- ) 72402- 72403- // Trim off leading non-letters. We trim everything between "[" and 72404- // "]" to handle array types like "[someConst]int". 72405- var inBracket bool 72406- s = strings.TrimFunc(s, func(r rune) bool { 72407- if inBracket { 72408- inBracket = r != ']' 72409- return true 72410- } 72411- 72412- if r == '[' { 72413- inBracket = true 72414- } 72415- 72416- return !unicode.IsLetter(r) 72417- }) 72418- 72419- if acr, ok := conventionalAcronyms[strings.ToLower(s)]; ok { 72420- return acr 72421- } 72422- 72423- for i, r := range s { 72424- // Stop if we encounter a non-identifier rune. 72425- if !unicode.IsLetter(r) && !unicode.IsNumber(r) { 72426- break 72427- } 72428- 72429- if i == 0 { 72430- b.WriteRune(unicode.ToLower(r)) 72431- } 72432- 72433- if unicode.IsUpper(r) { 72434- if useNextUpper { 72435- b.WriteRune(unicode.ToLower(r)) 72436- useNextUpper = false 72437- } 72438- } else { 72439- useNextUpper = true 72440- } 72441- } 72442- 72443- return b.String() 72444-} 72445- 72446-// compositeLiteral adds a composite literal completion item for the given typeName. 72447-func (c *completer) compositeLiteral(T types.Type, snip *snippet.Builder, typeName string, matchScore float64, edits []protocol.TextEdit) { 72448- snip.WriteText("{") 72449- // Don't put the tab stop inside the composite literal curlies "{}" 72450- // for structs that have no accessible fields. 72451- if strct, ok := T.(*types.Struct); !ok || fieldsAccessible(strct, c.pkg.GetTypes()) { 72452- snip.WriteFinalTabstop() 72453- } 72454- snip.WriteText("}") 72455- 72456- nonSnippet := typeName + "{}" 72457- 72458- c.items = append(c.items, CompletionItem{ 72459- Label: nonSnippet, 72460- InsertText: nonSnippet, 72461- Score: matchScore * literalCandidateScore, 72462- Kind: protocol.VariableCompletion, 72463- AdditionalTextEdits: edits, 72464- snippet: snip, 72465- }) 72466-} 72467- 72468-// basicLiteral adds a literal completion item for the given basic 72469-// type name typeName. 72470-func (c *completer) basicLiteral(T types.Type, snip *snippet.Builder, typeName string, matchScore float64, edits []protocol.TextEdit) { 72471- // Never give type conversions like "untyped int()". 72472- if isUntyped(T) { 72473- return 72474- } 72475- 72476- snip.WriteText("(") 72477- snip.WriteFinalTabstop() 72478- snip.WriteText(")") 72479- 72480- nonSnippet := typeName + "()" 72481- 72482- c.items = append(c.items, CompletionItem{ 72483- Label: nonSnippet, 72484- InsertText: nonSnippet, 72485- Detail: T.String(), 72486- Score: matchScore * literalCandidateScore, 72487- Kind: protocol.VariableCompletion, 72488- AdditionalTextEdits: edits, 72489- snippet: snip, 72490- }) 72491-} 72492- 72493-// makeCall adds a completion item for a "make()" call given a specific type. 72494-func (c *completer) makeCall(snip *snippet.Builder, typeName string, secondArg string, matchScore float64, edits []protocol.TextEdit) { 72495- // Keep it simple and don't add any placeholders for optional "make()" arguments. 72496- 72497- snip.PrependText("make(") 72498- if secondArg != "" { 72499- snip.WriteText(", ") 72500- snip.WritePlaceholder(func(b *snippet.Builder) { 72501- if c.opts.placeholders { 72502- b.WriteText(secondArg) 72503- } 72504- }) 72505- } 72506- snip.WriteText(")") 72507- 72508- var nonSnippet strings.Builder 72509- nonSnippet.WriteString("make(" + typeName) 72510- if secondArg != "" { 72511- nonSnippet.WriteString(", ") 72512- nonSnippet.WriteString(secondArg) 72513- } 72514- nonSnippet.WriteByte(')') 72515- 72516- c.items = append(c.items, CompletionItem{ 72517- Label: nonSnippet.String(), 72518- InsertText: nonSnippet.String(), 72519- Score: matchScore * literalCandidateScore, 72520- Kind: protocol.FunctionCompletion, 72521- AdditionalTextEdits: edits, 72522- snippet: snip, 72523- }) 72524-} 72525- 72526-// Create a snippet for a type name where type params become placeholders. 72527-func (c *completer) typeNameSnippet(literalType types.Type, qf types.Qualifier) (*snippet.Builder, string) { 72528- var ( 72529- snip snippet.Builder 72530- typeName string 72531- named, _ = literalType.(*types.Named) 72532- ) 72533- 72534- if named != nil && named.Obj() != nil && typeparams.ForNamed(named).Len() > 0 && !c.fullyInstantiated(named) { 72535- // We are not "fully instantiated" meaning we have type params that must be specified. 72536- if pkg := qf(named.Obj().Pkg()); pkg != "" { 72537- typeName = pkg + "." 72538- } 72539- 72540- // We do this to get "someType" instead of "someType[T]". 72541- typeName += named.Obj().Name() 72542- snip.WriteText(typeName + "[") 72543- 72544- if c.opts.placeholders { 72545- for i := 0; i < typeparams.ForNamed(named).Len(); i++ { 72546- if i > 0 { 72547- snip.WriteText(", ") 72548- } 72549- snip.WritePlaceholder(func(snip *snippet.Builder) { 72550- snip.WriteText(types.TypeString(typeparams.ForNamed(named).At(i), qf)) 72551- }) 72552- } 72553- } else { 72554- snip.WritePlaceholder(nil) 72555- } 72556- snip.WriteText("]") 72557- typeName += "[...]" 72558- } else { 72559- // We don't have unspecified type params so use default type formatting. 72560- typeName = types.TypeString(literalType, qf) 72561- snip.WriteText(typeName) 72562- } 72563- 72564- return &snip, typeName 72565-} 72566- 72567-// fullyInstantiated reports whether all of t's type params have 72568-// specified type args. 72569-func (c *completer) fullyInstantiated(t *types.Named) bool { 72570- tps := typeparams.ForNamed(t) 72571- tas := typeparams.NamedTypeArgs(t) 72572- 72573- if tps.Len() != tas.Len() { 72574- return false 72575- } 72576- 72577- for i := 0; i < tas.Len(); i++ { 72578- switch ta := tas.At(i).(type) { 72579- case *typeparams.TypeParam: 72580- // A *TypeParam only counts as specified if it is currently in 72581- // scope (i.e. we are in a generic definition). 72582- if !c.typeParamInScope(ta) { 72583- return false 72584- } 72585- case *types.Named: 72586- if !c.fullyInstantiated(ta) { 72587- return false 72588- } 72589- } 72590- } 72591- return true 72592-} 72593- 72594-// typeParamInScope returns whether tp's object is in scope at c.pos. 72595-// This tells you whether you are in a generic definition and can 72596-// assume tp has been specified. 72597-func (c *completer) typeParamInScope(tp *typeparams.TypeParam) bool { 72598- obj := tp.Obj() 72599- if obj == nil { 72600- return false 72601- } 72602- 72603- scope := c.innermostScope() 72604- if scope == nil { 72605- return false 72606- } 72607- 72608- _, foundObj := scope.LookupParent(obj.Name(), c.pos) 72609- return obj == foundObj 72610-} 72611diff -urN a/gopls/internal/lsp/source/completion/package.go b/gopls/internal/lsp/source/completion/package.go 72612--- a/gopls/internal/lsp/source/completion/package.go 2000-01-01 00:00:00.000000000 -0000 72613+++ b/gopls/internal/lsp/source/completion/package.go 1970-01-01 00:00:00.000000000 +0000 72614@@ -1,351 +0,0 @@ 72615-// Copyright 2020 The Go Authors. All rights reserved. 72616-// Use of this source code is governed by a BSD-style 72617-// license that can be found in the LICENSE file. 72618- 72619-package completion 72620- 72621-import ( 72622- "bytes" 72623- "context" 72624- "errors" 72625- "fmt" 72626- "go/ast" 72627- "go/parser" 72628- "go/scanner" 72629- "go/token" 72630- "go/types" 72631- "path/filepath" 72632- "strings" 72633- "unicode" 72634- 72635- "golang.org/x/tools/gopls/internal/lsp/protocol" 72636- "golang.org/x/tools/gopls/internal/lsp/safetoken" 72637- "golang.org/x/tools/gopls/internal/lsp/source" 72638- "golang.org/x/tools/gopls/internal/span" 72639- "golang.org/x/tools/internal/fuzzy" 72640-) 72641- 72642-// packageClauseCompletions offers completions for a package declaration when 72643-// one is not present in the given file. 72644-func packageClauseCompletions(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) ([]CompletionItem, *Selection, error) { 72645- // We know that the AST for this file will be empty due to the missing 72646- // package declaration, but parse it anyway to get a mapper. 72647- // TODO(adonovan): opt: there's no need to parse just to get a mapper. 72648- pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull) 72649- if err != nil { 72650- return nil, nil, err 72651- } 72652- 72653- offset, err := pgf.Mapper.PositionOffset(position) 72654- if err != nil { 72655- return nil, nil, err 72656- } 72657- surrounding, err := packageCompletionSurrounding(pgf, offset) 72658- if err != nil { 72659- return nil, nil, fmt.Errorf("invalid position for package completion: %w", err) 72660- } 72661- 72662- packageSuggestions, err := packageSuggestions(ctx, snapshot, fh.URI(), "") 72663- if err != nil { 72664- return nil, nil, err 72665- } 72666- 72667- var items []CompletionItem 72668- for _, pkg := range packageSuggestions { 72669- insertText := fmt.Sprintf("package %s", pkg.name) 72670- items = append(items, CompletionItem{ 72671- Label: insertText, 72672- Kind: protocol.ModuleCompletion, 72673- InsertText: insertText, 72674- Score: pkg.score, 72675- }) 72676- } 72677- 72678- return items, surrounding, nil 72679-} 72680- 72681-// packageCompletionSurrounding returns surrounding for package completion if a 72682-// package completions can be suggested at a given cursor offset. A valid location 72683-// for package completion is above any declarations or import statements. 72684-func packageCompletionSurrounding(pgf *source.ParsedGoFile, offset int) (*Selection, error) { 72685- m := pgf.Mapper 72686- // If the file lacks a package declaration, the parser will return an empty 72687- // AST. As a work-around, try to parse an expression from the file contents. 72688- fset := token.NewFileSet() 72689- expr, _ := parser.ParseExprFrom(fset, m.URI.Filename(), pgf.Src, parser.Mode(0)) 72690- if expr == nil { 72691- return nil, fmt.Errorf("unparseable file (%s)", m.URI) 72692- } 72693- tok := fset.File(expr.Pos()) 72694- cursor := tok.Pos(offset) 72695- 72696- // If we were able to parse out an identifier as the first expression from 72697- // the file, it may be the beginning of a package declaration ("pack "). 72698- // We can offer package completions if the cursor is in the identifier. 72699- if name, ok := expr.(*ast.Ident); ok { 72700- if cursor >= name.Pos() && cursor <= name.End() { 72701- if !strings.HasPrefix(PACKAGE, name.Name) { 72702- return nil, fmt.Errorf("cursor in non-matching ident") 72703- } 72704- return &Selection{ 72705- content: name.Name, 72706- cursor: cursor, 72707- tokFile: tok, 72708- start: name.Pos(), 72709- end: name.End(), 72710- mapper: m, 72711- }, nil 72712- } 72713- } 72714- 72715- // The file is invalid, but it contains an expression that we were able to 72716- // parse. We will use this expression to construct the cursor's 72717- // "surrounding". 72718- 72719- // First, consider the possibility that we have a valid "package" keyword 72720- // with an empty package name ("package "). "package" is parsed as an 72721- // *ast.BadDecl since it is a keyword. This logic would allow "package" to 72722- // appear on any line of the file as long as it's the first code expression 72723- // in the file. 72724- lines := strings.Split(string(pgf.Src), "\n") 72725- cursorLine := tok.Line(cursor) 72726- if cursorLine <= 0 || cursorLine > len(lines) { 72727- return nil, fmt.Errorf("invalid line number") 72728- } 72729- if safetoken.StartPosition(fset, expr.Pos()).Line == cursorLine { 72730- words := strings.Fields(lines[cursorLine-1]) 72731- if len(words) > 0 && words[0] == PACKAGE { 72732- content := PACKAGE 72733- // Account for spaces if there are any. 72734- if len(words) > 1 { 72735- content += " " 72736- } 72737- 72738- start := expr.Pos() 72739- end := token.Pos(int(expr.Pos()) + len(content) + 1) 72740- // We have verified that we have a valid 'package' keyword as our 72741- // first expression. Ensure that cursor is in this keyword or 72742- // otherwise fallback to the general case. 72743- if cursor >= start && cursor <= end { 72744- return &Selection{ 72745- content: content, 72746- cursor: cursor, 72747- tokFile: tok, 72748- start: start, 72749- end: end, 72750- mapper: m, 72751- }, nil 72752- } 72753- } 72754- } 72755- 72756- // If the cursor is after the start of the expression, no package 72757- // declaration will be valid. 72758- if cursor > expr.Pos() { 72759- return nil, fmt.Errorf("cursor after expression") 72760- } 72761- 72762- // If the cursor is in a comment, don't offer any completions. 72763- if cursorInComment(tok, cursor, m.Content) { 72764- return nil, fmt.Errorf("cursor in comment") 72765- } 72766- 72767- // The surrounding range in this case is the cursor. 72768- return &Selection{ 72769- content: "", 72770- tokFile: tok, 72771- start: cursor, 72772- end: cursor, 72773- cursor: cursor, 72774- mapper: m, 72775- }, nil 72776-} 72777- 72778-func cursorInComment(file *token.File, cursor token.Pos, src []byte) bool { 72779- var s scanner.Scanner 72780- s.Init(file, src, func(_ token.Position, _ string) {}, scanner.ScanComments) 72781- for { 72782- pos, tok, lit := s.Scan() 72783- if pos <= cursor && cursor <= token.Pos(int(pos)+len(lit)) { 72784- return tok == token.COMMENT 72785- } 72786- if tok == token.EOF { 72787- break 72788- } 72789- } 72790- return false 72791-} 72792- 72793-// packageNameCompletions returns name completions for a package clause using 72794-// the current name as prefix. 72795-func (c *completer) packageNameCompletions(ctx context.Context, fileURI span.URI, name *ast.Ident) error { 72796- cursor := int(c.pos - name.NamePos) 72797- if cursor < 0 || cursor > len(name.Name) { 72798- return errors.New("cursor is not in package name identifier") 72799- } 72800- 72801- c.completionContext.packageCompletion = true 72802- 72803- prefix := name.Name[:cursor] 72804- packageSuggestions, err := packageSuggestions(ctx, c.snapshot, fileURI, prefix) 72805- if err != nil { 72806- return err 72807- } 72808- 72809- for _, pkg := range packageSuggestions { 72810- c.deepState.enqueue(pkg) 72811- } 72812- return nil 72813-} 72814- 72815-// packageSuggestions returns a list of packages from workspace packages that 72816-// have the given prefix and are used in the same directory as the given 72817-// file. This also includes test packages for these packages (<pkg>_test) and 72818-// the directory name itself. 72819-func packageSuggestions(ctx context.Context, snapshot source.Snapshot, fileURI span.URI, prefix string) (packages []candidate, err error) { 72820- active, err := snapshot.ActiveMetadata(ctx) 72821- if err != nil { 72822- return nil, err 72823- } 72824- 72825- toCandidate := func(name string, score float64) candidate { 72826- obj := types.NewPkgName(0, nil, name, types.NewPackage("", name)) 72827- return candidate{obj: obj, name: name, detail: name, score: score} 72828- } 72829- 72830- matcher := fuzzy.NewMatcher(prefix) 72831- 72832- // Always try to suggest a main package 72833- defer func() { 72834- if score := float64(matcher.Score("main")); score > 0 { 72835- packages = append(packages, toCandidate("main", score*lowScore)) 72836- } 72837- }() 72838- 72839- dirPath := filepath.Dir(fileURI.Filename()) 72840- dirName := filepath.Base(dirPath) 72841- if !isValidDirName(dirName) { 72842- return packages, nil 72843- } 72844- pkgName := convertDirNameToPkgName(dirName) 72845- 72846- seenPkgs := make(map[source.PackageName]struct{}) 72847- 72848- // The `go` command by default only allows one package per directory but we 72849- // support multiple package suggestions since gopls is build system agnostic. 72850- for _, m := range active { 72851- if m.Name == "main" || m.Name == "" { 72852- continue 72853- } 72854- if _, ok := seenPkgs[m.Name]; ok { 72855- continue 72856- } 72857- 72858- // Only add packages that are previously used in the current directory. 72859- var relevantPkg bool 72860- for _, uri := range m.CompiledGoFiles { 72861- if filepath.Dir(uri.Filename()) == dirPath { 72862- relevantPkg = true 72863- break 72864- } 72865- } 72866- if !relevantPkg { 72867- continue 72868- } 72869- 72870- // Add a found package used in current directory as a high relevance 72871- // suggestion and the test package for it as a medium relevance 72872- // suggestion. 72873- if score := float64(matcher.Score(string(m.Name))); score > 0 { 72874- packages = append(packages, toCandidate(string(m.Name), score*highScore)) 72875- } 72876- seenPkgs[m.Name] = struct{}{} 72877- 72878- testPkgName := m.Name + "_test" 72879- if _, ok := seenPkgs[testPkgName]; ok || strings.HasSuffix(string(m.Name), "_test") { 72880- continue 72881- } 72882- if score := float64(matcher.Score(string(testPkgName))); score > 0 { 72883- packages = append(packages, toCandidate(string(testPkgName), score*stdScore)) 72884- } 72885- seenPkgs[testPkgName] = struct{}{} 72886- } 72887- 72888- // Add current directory name as a low relevance suggestion. 72889- if _, ok := seenPkgs[pkgName]; !ok { 72890- if score := float64(matcher.Score(string(pkgName))); score > 0 { 72891- packages = append(packages, toCandidate(string(pkgName), score*lowScore)) 72892- } 72893- 72894- testPkgName := pkgName + "_test" 72895- if score := float64(matcher.Score(string(testPkgName))); score > 0 { 72896- packages = append(packages, toCandidate(string(testPkgName), score*lowScore)) 72897- } 72898- } 72899- 72900- return packages, nil 72901-} 72902- 72903-// isValidDirName checks whether the passed directory name can be used in 72904-// a package path. Requirements for a package path can be found here: 72905-// https://golang.org/ref/mod#go-mod-file-ident. 72906-func isValidDirName(dirName string) bool { 72907- if dirName == "" { 72908- return false 72909- } 72910- 72911- for i, ch := range dirName { 72912- if isLetter(ch) || isDigit(ch) { 72913- continue 72914- } 72915- if i == 0 { 72916- // Directory name can start only with '_'. '.' is not allowed in module paths. 72917- // '-' and '~' are not allowed because elements of package paths must be 72918- // safe command-line arguments. 72919- if ch == '_' { 72920- continue 72921- } 72922- } else { 72923- // Modules path elements can't end with '.' 72924- if isAllowedPunctuation(ch) && (i != len(dirName)-1 || ch != '.') { 72925- continue 72926- } 72927- } 72928- 72929- return false 72930- } 72931- return true 72932-} 72933- 72934-// convertDirNameToPkgName converts a valid directory name to a valid package name. 72935-// It leaves only letters and digits. All letters are mapped to lower case. 72936-func convertDirNameToPkgName(dirName string) source.PackageName { 72937- var buf bytes.Buffer 72938- for _, ch := range dirName { 72939- switch { 72940- case isLetter(ch): 72941- buf.WriteRune(unicode.ToLower(ch)) 72942- 72943- case buf.Len() != 0 && isDigit(ch): 72944- buf.WriteRune(ch) 72945- } 72946- } 72947- return source.PackageName(buf.String()) 72948-} 72949- 72950-// isLetter and isDigit allow only ASCII characters because 72951-// "Each path element is a non-empty string made of up ASCII letters, 72952-// ASCII digits, and limited ASCII punctuation" 72953-// (see https://golang.org/ref/mod#go-mod-file-ident). 72954- 72955-func isLetter(ch rune) bool { 72956- return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' 72957-} 72958- 72959-func isDigit(ch rune) bool { 72960- return '0' <= ch && ch <= '9' 72961-} 72962- 72963-func isAllowedPunctuation(ch rune) bool { 72964- return ch == '_' || ch == '-' || ch == '~' || ch == '.' 72965-} 72966diff -urN a/gopls/internal/lsp/source/completion/package_test.go b/gopls/internal/lsp/source/completion/package_test.go 72967--- a/gopls/internal/lsp/source/completion/package_test.go 2000-01-01 00:00:00.000000000 -0000 72968+++ b/gopls/internal/lsp/source/completion/package_test.go 1970-01-01 00:00:00.000000000 +0000 72969@@ -1,81 +0,0 @@ 72970-// Copyright 2021 The Go Authors. All rights reserved. 72971-// Use of this source code is governed by a BSD-style 72972-// license that can be found in the LICENSE file. 72973- 72974-package completion 72975- 72976-import ( 72977- "testing" 72978- 72979- "golang.org/x/tools/gopls/internal/lsp/source" 72980-) 72981- 72982-func TestIsValidDirName(t *testing.T) { 72983- tests := []struct { 72984- dirName string 72985- valid bool 72986- }{ 72987- {dirName: "", valid: false}, 72988- // 72989- {dirName: "a", valid: true}, 72990- {dirName: "abcdef", valid: true}, 72991- {dirName: "AbCdEf", valid: true}, 72992- // 72993- {dirName: "1a35", valid: true}, 72994- {dirName: "a16", valid: true}, 72995- // 72996- {dirName: "_a", valid: true}, 72997- {dirName: "a_", valid: true}, 72998- // 72999- {dirName: "~a", valid: false}, 73000- {dirName: "a~", valid: true}, 73001- // 73002- {dirName: "-a", valid: false}, 73003- {dirName: "a-", valid: true}, 73004- // 73005- {dirName: ".a", valid: false}, 73006- {dirName: "a.", valid: false}, 73007- // 73008- {dirName: "a~_b--c.-e", valid: true}, 73009- {dirName: "~a~_b--c.-e", valid: false}, 73010- {dirName: "a~_b--c.-e--~", valid: true}, 73011- {dirName: "a~_b--2134dc42.-e6--~", valid: true}, 73012- {dirName: "abc`def", valid: false}, 73013- {dirName: "тест", valid: false}, 73014- {dirName: "你好", valid: false}, 73015- } 73016- for _, tt := range tests { 73017- valid := isValidDirName(tt.dirName) 73018- if tt.valid != valid { 73019- t.Errorf("%s: expected %v, got %v", tt.dirName, tt.valid, valid) 73020- } 73021- } 73022-} 73023- 73024-func TestConvertDirNameToPkgName(t *testing.T) { 73025- tests := []struct { 73026- dirName string 73027- pkgName source.PackageName 73028- }{ 73029- {dirName: "a", pkgName: "a"}, 73030- {dirName: "abcdef", pkgName: "abcdef"}, 73031- {dirName: "AbCdEf", pkgName: "abcdef"}, 73032- {dirName: "1a35", pkgName: "a35"}, 73033- {dirName: "14a35", pkgName: "a35"}, 73034- {dirName: "a16", pkgName: "a16"}, 73035- {dirName: "_a", pkgName: "a"}, 73036- {dirName: "a_", pkgName: "a"}, 73037- {dirName: "a~", pkgName: "a"}, 73038- {dirName: "a-", pkgName: "a"}, 73039- {dirName: "a~_b--c.-e", pkgName: "abce"}, 73040- {dirName: "a~_b--c.-e--~", pkgName: "abce"}, 73041- {dirName: "a~_b--2134dc42.-e6--~", pkgName: "ab2134dc42e6"}, 73042- } 73043- for _, tt := range tests { 73044- pkgName := convertDirNameToPkgName(tt.dirName) 73045- if tt.pkgName != pkgName { 73046- t.Errorf("%s: expected %v, got %v", tt.dirName, tt.pkgName, pkgName) 73047- continue 73048- } 73049- } 73050-} 73051diff -urN a/gopls/internal/lsp/source/completion/postfix_snippets.go b/gopls/internal/lsp/source/completion/postfix_snippets.go 73052--- a/gopls/internal/lsp/source/completion/postfix_snippets.go 2000-01-01 00:00:00.000000000 -0000 73053+++ b/gopls/internal/lsp/source/completion/postfix_snippets.go 1970-01-01 00:00:00.000000000 +0000 73054@@ -1,471 +0,0 @@ 73055-// Copyright 2020 The Go Authors. All rights reserved. 73056-// Use of this source code is governed by a BSD-style 73057-// license that can be found in the LICENSE file. 73058- 73059-package completion 73060- 73061-import ( 73062- "context" 73063- "fmt" 73064- "go/ast" 73065- "go/token" 73066- "go/types" 73067- "log" 73068- "reflect" 73069- "strings" 73070- "sync" 73071- "text/template" 73072- 73073- "golang.org/x/tools/gopls/internal/lsp/protocol" 73074- "golang.org/x/tools/gopls/internal/lsp/snippet" 73075- "golang.org/x/tools/gopls/internal/lsp/source" 73076- "golang.org/x/tools/internal/event" 73077- "golang.org/x/tools/internal/imports" 73078-) 73079- 73080-// Postfix snippets are artificial methods that allow the user to 73081-// compose common operations in an "argument oriented" fashion. For 73082-// example, instead of "sort.Slice(someSlice, ...)" a user can expand 73083-// "someSlice.sort!". 73084- 73085-// postfixTmpl represents a postfix snippet completion candidate. 73086-type postfixTmpl struct { 73087- // label is the completion candidate's label presented to the user. 73088- label string 73089- 73090- // details is passed along to the client as the candidate's details. 73091- details string 73092- 73093- // body is the template text. See postfixTmplArgs for details on the 73094- // facilities available to the template. 73095- body string 73096- 73097- tmpl *template.Template 73098-} 73099- 73100-// postfixTmplArgs are the template execution arguments available to 73101-// the postfix snippet templates. 73102-type postfixTmplArgs struct { 73103- // StmtOK is true if it is valid to replace the selector with a 73104- // statement. For example: 73105- // 73106- // func foo() { 73107- // bar.sort! // statement okay 73108- // 73109- // someMethod(bar.sort!) // statement not okay 73110- // } 73111- StmtOK bool 73112- 73113- // X is the textual SelectorExpr.X. For example, when completing 73114- // "foo.bar.print!", "X" is "foo.bar". 73115- X string 73116- 73117- // Obj is the types.Object of SelectorExpr.X, if any. 73118- Obj types.Object 73119- 73120- // Type is the type of "foo.bar" in "foo.bar.print!". 73121- Type types.Type 73122- 73123- scope *types.Scope 73124- snip snippet.Builder 73125- importIfNeeded func(pkgPath string, scope *types.Scope) (name string, edits []protocol.TextEdit, err error) 73126- edits []protocol.TextEdit 73127- qf types.Qualifier 73128- varNames map[string]bool 73129-} 73130- 73131-var postfixTmpls = []postfixTmpl{{ 73132- label: "sort", 73133- details: "sort.Slice()", 73134- body: `{{if and (eq .Kind "slice") .StmtOK -}} 73135-{{.Import "sort"}}.Slice({{.X}}, func({{.VarName nil "i"}}, {{.VarName nil "j"}} int) bool { 73136- {{.Cursor}} 73137-}) 73138-{{- end}}`, 73139-}, { 73140- label: "last", 73141- details: "s[len(s)-1]", 73142- body: `{{if and (eq .Kind "slice") .Obj -}} 73143-{{.X}}[len({{.X}})-1] 73144-{{- end}}`, 73145-}, { 73146- label: "reverse", 73147- details: "reverse slice", 73148- body: `{{if and (eq .Kind "slice") .StmtOK -}} 73149-{{$i := .VarName nil "i"}}{{$j := .VarName nil "j" -}} 73150-for {{$i}}, {{$j}} := 0, len({{.X}})-1; {{$i}} < {{$j}}; {{$i}}, {{$j}} = {{$i}}+1, {{$j}}-1 { 73151- {{.X}}[{{$i}}], {{.X}}[{{$j}}] = {{.X}}[{{$j}}], {{.X}}[{{$i}}] 73152-} 73153-{{end}}`, 73154-}, { 73155- label: "range", 73156- details: "range over slice", 73157- body: `{{if and (eq .Kind "slice") .StmtOK -}} 73158-for {{.VarName nil "i"}}, {{.VarName .ElemType "v"}} := range {{.X}} { 73159- {{.Cursor}} 73160-} 73161-{{- end}}`, 73162-}, { 73163- label: "append", 73164- details: "append and re-assign slice", 73165- body: `{{if and (eq .Kind "slice") .StmtOK .Obj -}} 73166-{{.X}} = append({{.X}}, {{.Cursor}}) 73167-{{- end}}`, 73168-}, { 73169- label: "append", 73170- details: "append to slice", 73171- body: `{{if and (eq .Kind "slice") (not .StmtOK) -}} 73172-append({{.X}}, {{.Cursor}}) 73173-{{- end}}`, 73174-}, { 73175- label: "copy", 73176- details: "duplicate slice", 73177- body: `{{if and (eq .Kind "slice") .StmtOK .Obj -}} 73178-{{$v := (.VarName nil (printf "%sCopy" .X))}}{{$v}} := make([]{{.TypeName .ElemType}}, len({{.X}})) 73179-copy({{$v}}, {{.X}}) 73180-{{end}}`, 73181-}, { 73182- label: "range", 73183- details: "range over map", 73184- body: `{{if and (eq .Kind "map") .StmtOK -}} 73185-for {{.VarName .KeyType "k"}}, {{.VarName .ElemType "v"}} := range {{.X}} { 73186- {{.Cursor}} 73187-} 73188-{{- end}}`, 73189-}, { 73190- label: "clear", 73191- details: "clear map contents", 73192- body: `{{if and (eq .Kind "map") .StmtOK -}} 73193-{{$k := (.VarName .KeyType "k")}}for {{$k}} := range {{.X}} { 73194- delete({{.X}}, {{$k}}) 73195-} 73196-{{end}}`, 73197-}, { 73198- label: "keys", 73199- details: "create slice of keys", 73200- body: `{{if and (eq .Kind "map") .StmtOK -}} 73201-{{$keysVar := (.VarName nil "keys")}}{{$keysVar}} := make([]{{.TypeName .KeyType}}, 0, len({{.X}})) 73202-{{$k := (.VarName .KeyType "k")}}for {{$k}} := range {{.X}} { 73203- {{$keysVar}} = append({{$keysVar}}, {{$k}}) 73204-} 73205-{{end}}`, 73206-}, { 73207- label: "range", 73208- details: "range over channel", 73209- body: `{{if and (eq .Kind "chan") .StmtOK -}} 73210-for {{.VarName .ElemType "e"}} := range {{.X}} { 73211- {{.Cursor}} 73212-} 73213-{{- end}}`, 73214-}, { 73215- label: "var", 73216- details: "assign to variables", 73217- body: `{{if and (eq .Kind "tuple") .StmtOK -}} 73218-{{$a := .}}{{range $i, $v := .Tuple}}{{if $i}}, {{end}}{{$a.VarName $v.Type $v.Name}}{{end}} := {{.X}} 73219-{{- end}}`, 73220-}, { 73221- label: "var", 73222- details: "assign to variable", 73223- body: `{{if and (ne .Kind "tuple") .StmtOK -}} 73224-{{.VarName .Type ""}} := {{.X}} 73225-{{- end}}`, 73226-}, { 73227- label: "print", 73228- details: "print to stdout", 73229- body: `{{if and (ne .Kind "tuple") .StmtOK -}} 73230-{{.Import "fmt"}}.Printf("{{.EscapeQuotes .X}}: %v\n", {{.X}}) 73231-{{- end}}`, 73232-}, { 73233- label: "print", 73234- details: "print to stdout", 73235- body: `{{if and (eq .Kind "tuple") .StmtOK -}} 73236-{{.Import "fmt"}}.Println({{.X}}) 73237-{{- end}}`, 73238-}, { 73239- label: "split", 73240- details: "split string", 73241- body: `{{if (eq (.TypeName .Type) "string") -}} 73242-{{.Import "strings"}}.Split({{.X}}, "{{.Cursor}}") 73243-{{- end}}`, 73244-}, { 73245- label: "join", 73246- details: "join string slice", 73247- body: `{{if and (eq .Kind "slice") (eq (.TypeName .ElemType) "string") -}} 73248-{{.Import "strings"}}.Join({{.X}}, "{{.Cursor}}") 73249-{{- end}}`, 73250-}} 73251- 73252-// Cursor indicates where the client's cursor should end up after the 73253-// snippet is done. 73254-func (a *postfixTmplArgs) Cursor() string { 73255- a.snip.WriteFinalTabstop() 73256- return "" 73257-} 73258- 73259-// Import makes sure the package corresponding to path is imported, 73260-// returning the identifier to use to refer to the package. 73261-func (a *postfixTmplArgs) Import(path string) (string, error) { 73262- name, edits, err := a.importIfNeeded(path, a.scope) 73263- if err != nil { 73264- return "", fmt.Errorf("couldn't import %q: %w", path, err) 73265- } 73266- a.edits = append(a.edits, edits...) 73267- return name, nil 73268-} 73269- 73270-func (a *postfixTmplArgs) EscapeQuotes(v string) string { 73271- return strings.ReplaceAll(v, `"`, `\\"`) 73272-} 73273- 73274-// ElemType returns the Elem() type of xType, if applicable. 73275-func (a *postfixTmplArgs) ElemType() types.Type { 73276- if e, _ := a.Type.(interface{ Elem() types.Type }); e != nil { 73277- return e.Elem() 73278- } 73279- return nil 73280-} 73281- 73282-// Kind returns the underlying kind of type, e.g. "slice", "struct", 73283-// etc. 73284-func (a *postfixTmplArgs) Kind() string { 73285- t := reflect.TypeOf(a.Type.Underlying()) 73286- return strings.ToLower(strings.TrimPrefix(t.String(), "*types.")) 73287-} 73288- 73289-// KeyType returns the type of X's key. KeyType panics if X is not a 73290-// map. 73291-func (a *postfixTmplArgs) KeyType() types.Type { 73292- return a.Type.Underlying().(*types.Map).Key() 73293-} 73294- 73295-// Tuple returns the tuple result vars if X is a call expression. 73296-func (a *postfixTmplArgs) Tuple() []*types.Var { 73297- tuple, _ := a.Type.(*types.Tuple) 73298- if tuple == nil { 73299- return nil 73300- } 73301- 73302- typs := make([]*types.Var, 0, tuple.Len()) 73303- for i := 0; i < tuple.Len(); i++ { 73304- typs = append(typs, tuple.At(i)) 73305- } 73306- return typs 73307-} 73308- 73309-// TypeName returns the textual representation of type t. 73310-func (a *postfixTmplArgs) TypeName(t types.Type) (string, error) { 73311- if t == nil || t == types.Typ[types.Invalid] { 73312- return "", fmt.Errorf("invalid type: %v", t) 73313- } 73314- return types.TypeString(t, a.qf), nil 73315-} 73316- 73317-// VarName returns a suitable variable name for the type t. If t 73318-// implements the error interface, "err" is used. If t is not a named 73319-// type then nonNamedDefault is used. Otherwise a name is made by 73320-// abbreviating the type name. If the resultant name is already in 73321-// scope, an integer is appended to make a unique name. 73322-func (a *postfixTmplArgs) VarName(t types.Type, nonNamedDefault string) string { 73323- if t == nil { 73324- t = types.Typ[types.Invalid] 73325- } 73326- 73327- var name string 73328- // go/types predicates are undefined on types.Typ[types.Invalid]. 73329- if !types.Identical(t, types.Typ[types.Invalid]) && types.Implements(t, errorIntf) { 73330- name = "err" 73331- } else if _, isNamed := source.Deref(t).(*types.Named); !isNamed { 73332- name = nonNamedDefault 73333- } 73334- 73335- if name == "" { 73336- name = types.TypeString(t, func(p *types.Package) string { 73337- return "" 73338- }) 73339- name = abbreviateTypeName(name) 73340- } 73341- 73342- if dot := strings.LastIndex(name, "."); dot > -1 { 73343- name = name[dot+1:] 73344- } 73345- 73346- uniqueName := name 73347- for i := 2; ; i++ { 73348- if s, _ := a.scope.LookupParent(uniqueName, token.NoPos); s == nil && !a.varNames[uniqueName] { 73349- break 73350- } 73351- uniqueName = fmt.Sprintf("%s%d", name, i) 73352- } 73353- 73354- a.varNames[uniqueName] = true 73355- 73356- return uniqueName 73357-} 73358- 73359-func (c *completer) addPostfixSnippetCandidates(ctx context.Context, sel *ast.SelectorExpr) { 73360- if !c.opts.postfix { 73361- return 73362- } 73363- 73364- initPostfixRules() 73365- 73366- if sel == nil || sel.Sel == nil { 73367- return 73368- } 73369- 73370- selType := c.pkg.GetTypesInfo().TypeOf(sel.X) 73371- if selType == nil { 73372- return 73373- } 73374- 73375- // Skip empty tuples since there is no value to operate on. 73376- if tuple, ok := selType.Underlying().(*types.Tuple); ok && tuple == nil { 73377- return 73378- } 73379- 73380- tokFile := c.pkg.FileSet().File(c.pos) 73381- 73382- // Only replace sel with a statement if sel is already a statement. 73383- var stmtOK bool 73384- for i, n := range c.path { 73385- if n == sel && i < len(c.path)-1 { 73386- switch p := c.path[i+1].(type) { 73387- case *ast.ExprStmt: 73388- stmtOK = true 73389- case *ast.AssignStmt: 73390- // In cases like: 73391- // 73392- // foo.<> 73393- // bar = 123 73394- // 73395- // detect that "foo." makes up the entire statement since the 73396- // apparent selector spans lines. 73397- stmtOK = tokFile.Line(c.pos) < tokFile.Line(p.TokPos) 73398- } 73399- break 73400- } 73401- } 73402- 73403- scope := c.pkg.GetTypes().Scope().Innermost(c.pos) 73404- if scope == nil { 73405- return 73406- } 73407- 73408- // afterDot is the position after selector dot, e.g. "|" in 73409- // "foo.|print". 73410- afterDot := sel.Sel.Pos() 73411- 73412- // We must detect dangling selectors such as: 73413- // 73414- // foo.<> 73415- // bar 73416- // 73417- // and adjust afterDot so that we don't mistakenly delete the 73418- // newline thinking "bar" is part of our selector. 73419- if startLine := tokFile.Line(sel.Pos()); startLine != tokFile.Line(afterDot) { 73420- if tokFile.Line(c.pos) != startLine { 73421- return 73422- } 73423- afterDot = c.pos 73424- } 73425- 73426- for _, rule := range postfixTmpls { 73427- // When completing foo.print<>, "print" is naturally overwritten, 73428- // but we need to also remove "foo." so the snippet has a clean 73429- // slate. 73430- edits, err := c.editText(sel.Pos(), afterDot, "") 73431- if err != nil { 73432- event.Error(ctx, "error calculating postfix edits", err) 73433- return 73434- } 73435- 73436- tmplArgs := postfixTmplArgs{ 73437- X: source.FormatNode(c.pkg.FileSet(), sel.X), 73438- StmtOK: stmtOK, 73439- Obj: exprObj(c.pkg.GetTypesInfo(), sel.X), 73440- Type: selType, 73441- qf: c.qf, 73442- importIfNeeded: c.importIfNeeded, 73443- scope: scope, 73444- varNames: make(map[string]bool), 73445- } 73446- 73447- // Feed the template straight into the snippet builder. This 73448- // allows templates to build snippets as they are executed. 73449- err = rule.tmpl.Execute(&tmplArgs.snip, &tmplArgs) 73450- if err != nil { 73451- event.Error(ctx, "error executing postfix template", err) 73452- continue 73453- } 73454- 73455- if strings.TrimSpace(tmplArgs.snip.String()) == "" { 73456- continue 73457- } 73458- 73459- score := c.matcher.Score(rule.label) 73460- if score <= 0 { 73461- continue 73462- } 73463- 73464- c.items = append(c.items, CompletionItem{ 73465- Label: rule.label + "!", 73466- Detail: rule.details, 73467- Score: float64(score) * 0.01, 73468- Kind: protocol.SnippetCompletion, 73469- snippet: &tmplArgs.snip, 73470- AdditionalTextEdits: append(edits, tmplArgs.edits...), 73471- }) 73472- } 73473-} 73474- 73475-var postfixRulesOnce sync.Once 73476- 73477-func initPostfixRules() { 73478- postfixRulesOnce.Do(func() { 73479- var idx int 73480- for _, rule := range postfixTmpls { 73481- var err error 73482- rule.tmpl, err = template.New("postfix_snippet").Parse(rule.body) 73483- if err != nil { 73484- log.Panicf("error parsing postfix snippet template: %v", err) 73485- } 73486- postfixTmpls[idx] = rule 73487- idx++ 73488- } 73489- postfixTmpls = postfixTmpls[:idx] 73490- }) 73491-} 73492- 73493-// importIfNeeded returns the package identifier and any necessary 73494-// edits to import package pkgPath. 73495-func (c *completer) importIfNeeded(pkgPath string, scope *types.Scope) (string, []protocol.TextEdit, error) { 73496- defaultName := imports.ImportPathToAssumedName(pkgPath) 73497- 73498- // Check if file already imports pkgPath. 73499- for _, s := range c.file.Imports { 73500- // TODO(adonovan): what if pkgPath has a vendor/ suffix? 73501- // This may be the cause of go.dev/issue/56291. 73502- if source.UnquoteImportPath(s) == source.ImportPath(pkgPath) { 73503- if s.Name == nil { 73504- return defaultName, nil, nil 73505- } 73506- if s.Name.Name != "_" { 73507- return s.Name.Name, nil, nil 73508- } 73509- } 73510- } 73511- 73512- // Give up if the package's name is already in use by another object. 73513- if _, obj := scope.LookupParent(defaultName, token.NoPos); obj != nil { 73514- return "", nil, fmt.Errorf("import name %q of %q already in use", defaultName, pkgPath) 73515- } 73516- 73517- edits, err := c.importEdits(&importInfo{ 73518- importPath: pkgPath, 73519- }) 73520- if err != nil { 73521- return "", nil, err 73522- } 73523- 73524- return defaultName, edits, nil 73525-} 73526diff -urN a/gopls/internal/lsp/source/completion/printf.go b/gopls/internal/lsp/source/completion/printf.go 73527--- a/gopls/internal/lsp/source/completion/printf.go 2000-01-01 00:00:00.000000000 -0000 73528+++ b/gopls/internal/lsp/source/completion/printf.go 1970-01-01 00:00:00.000000000 +0000 73529@@ -1,172 +0,0 @@ 73530-// Copyright 2020 The Go Authors. All rights reserved. 73531-// Use of this source code is governed by a BSD-style 73532-// license that can be found in the LICENSE file. 73533- 73534-package completion 73535- 73536-import ( 73537- "go/ast" 73538- "go/constant" 73539- "go/types" 73540- "strconv" 73541- "strings" 73542- "unicode/utf8" 73543-) 73544- 73545-// printfArgKind returns the expected objKind when completing a 73546-// printf-like operand. call is the printf-like function call, and 73547-// argIdx is the index of call.Args being completed. 73548-func printfArgKind(info *types.Info, call *ast.CallExpr, argIdx int) objKind { 73549- // Printf-like function name must end in "f". 73550- fn := exprObj(info, call.Fun) 73551- if fn == nil || !strings.HasSuffix(fn.Name(), "f") { 73552- return kindAny 73553- } 73554- 73555- sig, _ := fn.Type().(*types.Signature) 73556- if sig == nil { 73557- return kindAny 73558- } 73559- 73560- // Must be variadic and take at least two params. 73561- numParams := sig.Params().Len() 73562- if !sig.Variadic() || numParams < 2 || argIdx < numParams-1 { 73563- return kindAny 73564- } 73565- 73566- // Param preceding variadic args must be a (format) string. 73567- if !types.Identical(sig.Params().At(numParams-2).Type(), types.Typ[types.String]) { 73568- return kindAny 73569- } 73570- 73571- // Format string must be a constant. 73572- strArg := info.Types[call.Args[numParams-2]].Value 73573- if strArg == nil || strArg.Kind() != constant.String { 73574- return kindAny 73575- } 73576- 73577- return formatOperandKind(constant.StringVal(strArg), argIdx-(numParams-1)+1) 73578-} 73579- 73580-// formatOperandKind returns the objKind corresponding to format's 73581-// operandIdx'th operand. 73582-func formatOperandKind(format string, operandIdx int) objKind { 73583- var ( 73584- prevOperandIdx int 73585- kind = kindAny 73586- ) 73587- for { 73588- i := strings.Index(format, "%") 73589- if i == -1 { 73590- break 73591- } 73592- 73593- var operands []formatOperand 73594- format, operands = parsePrintfVerb(format[i+1:], prevOperandIdx) 73595- 73596- // Check if any this verb's operands correspond to our target 73597- // operandIdx. 73598- for _, v := range operands { 73599- if v.idx == operandIdx { 73600- if kind == kindAny { 73601- kind = v.kind 73602- } else if v.kind != kindAny { 73603- // If multiple verbs refer to the same operand, take the 73604- // intersection of their kinds. 73605- kind &= v.kind 73606- } 73607- } 73608- 73609- prevOperandIdx = v.idx 73610- } 73611- } 73612- return kind 73613-} 73614- 73615-type formatOperand struct { 73616- // idx is the one-based printf operand index. 73617- idx int 73618- // kind is a mask of expected kinds of objects for this operand. 73619- kind objKind 73620-} 73621- 73622-// parsePrintfVerb parses the leading printf verb in f. The opening 73623-// "%" must already be trimmed from f. prevIdx is the previous 73624-// operand's index, or zero if this is the first verb. The format 73625-// string is returned with the leading verb removed. Multiple operands 73626-// can be returned in the case of dynamic widths such as "%*.*f". 73627-func parsePrintfVerb(f string, prevIdx int) (string, []formatOperand) { 73628- var verbs []formatOperand 73629- 73630- addVerb := func(k objKind) { 73631- verbs = append(verbs, formatOperand{ 73632- idx: prevIdx + 1, 73633- kind: k, 73634- }) 73635- prevIdx++ 73636- } 73637- 73638- for len(f) > 0 { 73639- // Trim first rune off of f so we are guaranteed to make progress. 73640- r, l := utf8.DecodeRuneInString(f) 73641- f = f[l:] 73642- 73643- // We care about three things: 73644- // 1. The verb, which maps directly to object kind. 73645- // 2. Explicit operand indices like "%[2]s". 73646- // 3. Dynamic widths using "*". 73647- switch r { 73648- case '%': 73649- return f, nil 73650- case '*': 73651- addVerb(kindInt) 73652- continue 73653- case '[': 73654- // Parse operand index as in "%[2]s". 73655- i := strings.Index(f, "]") 73656- if i == -1 { 73657- return f, nil 73658- } 73659- 73660- idx, err := strconv.Atoi(f[:i]) 73661- f = f[i+1:] 73662- if err != nil { 73663- return f, nil 73664- } 73665- 73666- prevIdx = idx - 1 73667- continue 73668- case 'v', 'T': 73669- addVerb(kindAny) 73670- case 't': 73671- addVerb(kindBool) 73672- case 'c', 'd', 'o', 'O', 'U': 73673- addVerb(kindInt) 73674- case 'e', 'E', 'f', 'F', 'g', 'G': 73675- addVerb(kindFloat | kindComplex) 73676- case 'b': 73677- addVerb(kindInt | kindFloat | kindComplex | kindBytes) 73678- case 'q', 's': 73679- addVerb(kindString | kindBytes | kindStringer | kindError) 73680- case 'x', 'X': 73681- // Omit kindStringer and kindError though technically allowed. 73682- addVerb(kindString | kindBytes | kindInt | kindFloat | kindComplex) 73683- case 'p': 73684- addVerb(kindPtr | kindSlice) 73685- case 'w': 73686- addVerb(kindError) 73687- case '+', '-', '#', ' ', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 73688- // Flag or numeric width/precision value. 73689- continue 73690- default: 73691- // Assume unrecognized rune is a custom fmt.Formatter verb. 73692- addVerb(kindAny) 73693- } 73694- 73695- if len(verbs) > 0 { 73696- break 73697- } 73698- } 73699- 73700- return f, verbs 73701-} 73702diff -urN a/gopls/internal/lsp/source/completion/printf_test.go b/gopls/internal/lsp/source/completion/printf_test.go 73703--- a/gopls/internal/lsp/source/completion/printf_test.go 2000-01-01 00:00:00.000000000 -0000 73704+++ b/gopls/internal/lsp/source/completion/printf_test.go 1970-01-01 00:00:00.000000000 +0000 73705@@ -1,72 +0,0 @@ 73706-// Copyright 2020 The Go Authors. All rights reserved. 73707-// Use of this source code is governed by a BSD-style 73708-// license that can be found in the LICENSE file. 73709- 73710-package completion 73711- 73712-import ( 73713- "fmt" 73714- "testing" 73715-) 73716- 73717-func TestFormatOperandKind(t *testing.T) { 73718- cases := []struct { 73719- f string 73720- idx int 73721- kind objKind 73722- }{ 73723- {"", 1, kindAny}, 73724- {"%", 1, kindAny}, 73725- {"%%%", 1, kindAny}, 73726- {"%[1", 1, kindAny}, 73727- {"%[?%s", 2, kindAny}, 73728- {"%[abc]v", 1, kindAny}, 73729- 73730- {"%v", 1, kindAny}, 73731- {"%T", 1, kindAny}, 73732- {"%t", 1, kindBool}, 73733- {"%d", 1, kindInt}, 73734- {"%c", 1, kindInt}, 73735- {"%o", 1, kindInt}, 73736- {"%O", 1, kindInt}, 73737- {"%U", 1, kindInt}, 73738- {"%e", 1, kindFloat | kindComplex}, 73739- {"%E", 1, kindFloat | kindComplex}, 73740- {"%f", 1, kindFloat | kindComplex}, 73741- {"%F", 1, kindFloat | kindComplex}, 73742- {"%g", 1, kindFloat | kindComplex}, 73743- {"%G", 1, kindFloat | kindComplex}, 73744- {"%b", 1, kindInt | kindFloat | kindComplex | kindBytes}, 73745- {"%q", 1, kindString | kindBytes | kindStringer | kindError}, 73746- {"%s", 1, kindString | kindBytes | kindStringer | kindError}, 73747- {"%x", 1, kindString | kindBytes | kindInt | kindFloat | kindComplex}, 73748- {"%X", 1, kindString | kindBytes | kindInt | kindFloat | kindComplex}, 73749- {"%p", 1, kindPtr | kindSlice}, 73750- {"%w", 1, kindError}, 73751- 73752- {"%1.2f", 1, kindFloat | kindComplex}, 73753- {"%*f", 1, kindInt}, 73754- {"%*f", 2, kindFloat | kindComplex}, 73755- {"%*.*f", 1, kindInt}, 73756- {"%*.*f", 2, kindInt}, 73757- {"%*.*f", 3, kindFloat | kindComplex}, 73758- {"%[3]*.[2]*[1]f", 1, kindFloat | kindComplex}, 73759- {"%[3]*.[2]*[1]f", 2, kindInt}, 73760- {"%[3]*.[2]*[1]f", 3, kindInt}, 73761- 73762- {"foo %% %d", 1, kindInt}, 73763- {"%#-12.34f", 1, kindFloat | kindComplex}, 73764- {"% d", 1, kindInt}, 73765- 73766- {"%s %[1]X %d", 1, kindString | kindBytes}, 73767- {"%s %[1]X %d", 2, kindInt}, 73768- } 73769- 73770- for _, c := range cases { 73771- t.Run(fmt.Sprintf("%q#%d", c.f, c.idx), func(t *testing.T) { 73772- if got := formatOperandKind(c.f, c.idx); got != c.kind { 73773- t.Errorf("expected %d (%[1]b), got %d (%[2]b)", c.kind, got) 73774- } 73775- }) 73776- } 73777-} 73778diff -urN a/gopls/internal/lsp/source/completion/snippet.go b/gopls/internal/lsp/source/completion/snippet.go 73779--- a/gopls/internal/lsp/source/completion/snippet.go 2000-01-01 00:00:00.000000000 -0000 73780+++ b/gopls/internal/lsp/source/completion/snippet.go 1970-01-01 00:00:00.000000000 +0000 73781@@ -1,116 +0,0 @@ 73782-// Copyright 2019 The Go Authors. All rights reserved. 73783-// Use of this source code is governed by a BSD-style 73784-// license that can be found in the LICENSE file. 73785- 73786-package completion 73787- 73788-import ( 73789- "go/ast" 73790- 73791- "golang.org/x/tools/gopls/internal/lsp/safetoken" 73792- "golang.org/x/tools/gopls/internal/lsp/snippet" 73793-) 73794- 73795-// structFieldSnippet calculates the snippet for struct literal field names. 73796-func (c *completer) structFieldSnippet(cand candidate, detail string, snip *snippet.Builder) { 73797- if !c.wantStructFieldCompletions() { 73798- return 73799- } 73800- 73801- // If we are in a deep completion then we can't be completing a field 73802- // name (e.g. "Foo{f<>}" completing to "Foo{f.Bar}" should not generate 73803- // a snippet). 73804- if len(cand.path) > 0 { 73805- return 73806- } 73807- 73808- clInfo := c.enclosingCompositeLiteral 73809- 73810- // If we are already in a key-value expression, we don't want a snippet. 73811- if clInfo.kv != nil { 73812- return 73813- } 73814- 73815- // A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>". 73816- snip.WriteText(": ") 73817- snip.WritePlaceholder(func(b *snippet.Builder) { 73818- // A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>". 73819- if c.opts.placeholders { 73820- b.WriteText(detail) 73821- } 73822- }) 73823- 73824- fset := c.pkg.FileSet() 73825- 73826- // If the cursor position is on a different line from the literal's opening brace, 73827- // we are in a multiline literal. Ignore line directives. 73828- if safetoken.StartPosition(fset, c.pos).Line != safetoken.StartPosition(fset, clInfo.cl.Lbrace).Line { 73829- snip.WriteText(",") 73830- } 73831-} 73832- 73833-// functionCallSnippet calculates the snippet for function calls. 73834-func (c *completer) functionCallSnippet(name string, tparams, params []string, snip *snippet.Builder) { 73835- // If there is no suffix then we need to reuse existing call parens 73836- // "()" if present. If there is an identifier suffix then we always 73837- // need to include "()" since we don't overwrite the suffix. 73838- if c.surrounding != nil && c.surrounding.Suffix() == "" && len(c.path) > 1 { 73839- // If we are the left side (i.e. "Fun") part of a call expression, 73840- // we don't want a snippet since there are already parens present. 73841- switch n := c.path[1].(type) { 73842- case *ast.CallExpr: 73843- // The Lparen != Rparen check detects fudged CallExprs we 73844- // inserted when fixing the AST. In this case, we do still need 73845- // to insert the calling "()" parens. 73846- if n.Fun == c.path[0] && n.Lparen != n.Rparen { 73847- return 73848- } 73849- case *ast.SelectorExpr: 73850- if len(c.path) > 2 { 73851- if call, ok := c.path[2].(*ast.CallExpr); ok && call.Fun == c.path[1] && call.Lparen != call.Rparen { 73852- return 73853- } 73854- } 73855- } 73856- } 73857- 73858- snip.WriteText(name) 73859- 73860- if len(tparams) > 0 { 73861- snip.WriteText("[") 73862- if c.opts.placeholders { 73863- for i, tp := range tparams { 73864- if i > 0 { 73865- snip.WriteText(", ") 73866- } 73867- snip.WritePlaceholder(func(b *snippet.Builder) { 73868- b.WriteText(tp) 73869- }) 73870- } 73871- } else { 73872- snip.WritePlaceholder(nil) 73873- } 73874- snip.WriteText("]") 73875- } 73876- 73877- snip.WriteText("(") 73878- 73879- if c.opts.placeholders { 73880- // A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)". 73881- for i, p := range params { 73882- if i > 0 { 73883- snip.WriteText(", ") 73884- } 73885- snip.WritePlaceholder(func(b *snippet.Builder) { 73886- b.WriteText(p) 73887- }) 73888- } 73889- } else { 73890- // A plain snippet turns "someFun<>" into "someFunc(<>)". 73891- if len(params) > 0 { 73892- snip.WritePlaceholder(nil) 73893- } 73894- } 73895- 73896- snip.WriteText(")") 73897-} 73898diff -urN a/gopls/internal/lsp/source/completion/statements.go b/gopls/internal/lsp/source/completion/statements.go 73899--- a/gopls/internal/lsp/source/completion/statements.go 2000-01-01 00:00:00.000000000 -0000 73900+++ b/gopls/internal/lsp/source/completion/statements.go 1970-01-01 00:00:00.000000000 +0000 73901@@ -1,361 +0,0 @@ 73902-// Copyright 2020 The Go Authors. All rights reserved. 73903-// Use of this source code is governed by a BSD-style 73904-// license that can be found in the LICENSE file. 73905- 73906-package completion 73907- 73908-import ( 73909- "fmt" 73910- "go/ast" 73911- "go/token" 73912- "go/types" 73913- 73914- "golang.org/x/tools/gopls/internal/lsp/protocol" 73915- "golang.org/x/tools/gopls/internal/lsp/snippet" 73916- "golang.org/x/tools/gopls/internal/lsp/source" 73917-) 73918- 73919-// addStatementCandidates adds full statement completion candidates 73920-// appropriate for the current context. 73921-func (c *completer) addStatementCandidates() { 73922- c.addErrCheck() 73923- c.addAssignAppend() 73924-} 73925- 73926-// addAssignAppend offers a completion candidate of the form: 73927-// 73928-// someSlice = append(someSlice, ) 73929-// 73930-// It will offer the "append" completion in either of two situations: 73931-// 73932-// 1. Position is in RHS of assign, prefix matches "append", and 73933-// corresponding LHS object is a slice. For example, 73934-// "foo = ap<>" completes to "foo = append(foo, )". 73935-// 73936-// 2. Prefix is an ident or selector in an *ast.ExprStmt (i.e. 73937-// beginning of statement), and our best matching candidate is a 73938-// slice. For example: "foo.ba" completes to "foo.bar = append(foo.bar, )". 73939-func (c *completer) addAssignAppend() { 73940- if len(c.path) < 3 { 73941- return 73942- } 73943- 73944- ident, _ := c.path[0].(*ast.Ident) 73945- if ident == nil { 73946- return 73947- } 73948- 73949- var ( 73950- // sliceText is the full name of our slice object, e.g. "s.abc" in 73951- // "s.abc = app<>". 73952- sliceText string 73953- // needsLHS is true if we need to prepend the LHS slice name and 73954- // "=" to our candidate. 73955- needsLHS = false 73956- fset = c.pkg.FileSet() 73957- ) 73958- 73959- switch n := c.path[1].(type) { 73960- case *ast.AssignStmt: 73961- // We are already in an assignment. Make sure our prefix matches "append". 73962- if c.matcher.Score("append") <= 0 { 73963- return 73964- } 73965- 73966- exprIdx := exprAtPos(c.pos, n.Rhs) 73967- if exprIdx == len(n.Rhs) || exprIdx > len(n.Lhs)-1 { 73968- return 73969- } 73970- 73971- lhsType := c.pkg.GetTypesInfo().TypeOf(n.Lhs[exprIdx]) 73972- if lhsType == nil { 73973- return 73974- } 73975- 73976- // Make sure our corresponding LHS object is a slice. 73977- if _, isSlice := lhsType.Underlying().(*types.Slice); !isSlice { 73978- return 73979- } 73980- 73981- // The name or our slice is whatever's in the LHS expression. 73982- sliceText = source.FormatNode(fset, n.Lhs[exprIdx]) 73983- case *ast.SelectorExpr: 73984- // Make sure we are a selector at the beginning of a statement. 73985- if _, parentIsExprtStmt := c.path[2].(*ast.ExprStmt); !parentIsExprtStmt { 73986- return 73987- } 73988- 73989- // So far we only know the first part of our slice name. For 73990- // example in "s.a<>" we only know our slice begins with "s." 73991- // since the user could still be typing. 73992- sliceText = source.FormatNode(fset, n.X) + "." 73993- needsLHS = true 73994- case *ast.ExprStmt: 73995- needsLHS = true 73996- default: 73997- return 73998- } 73999- 74000- var ( 74001- label string 74002- snip snippet.Builder 74003- score = highScore 74004- ) 74005- 74006- if needsLHS { 74007- // Offer the long form assign + append candidate if our best 74008- // candidate is a slice. 74009- bestItem := c.topCandidate() 74010- if bestItem == nil || !bestItem.isSlice { 74011- return 74012- } 74013- 74014- // Don't rank the full form assign + append candidate above the 74015- // slice itself. 74016- score = bestItem.Score - 0.01 74017- 74018- // Fill in rest of sliceText now that we have the object name. 74019- sliceText += bestItem.Label 74020- 74021- // Fill in the candidate's LHS bits. 74022- label = fmt.Sprintf("%s = ", bestItem.Label) 74023- snip.WriteText(label) 74024- } 74025- 74026- snip.WriteText(fmt.Sprintf("append(%s, ", sliceText)) 74027- snip.WritePlaceholder(nil) 74028- snip.WriteText(")") 74029- 74030- c.items = append(c.items, CompletionItem{ 74031- Label: label + fmt.Sprintf("append(%s, )", sliceText), 74032- Kind: protocol.FunctionCompletion, 74033- Score: score, 74034- snippet: &snip, 74035- }) 74036-} 74037- 74038-// topCandidate returns the strictly highest scoring candidate 74039-// collected so far. If the top two candidates have the same score, 74040-// nil is returned. 74041-func (c *completer) topCandidate() *CompletionItem { 74042- var bestItem, secondBestItem *CompletionItem 74043- for i := range c.items { 74044- if bestItem == nil || c.items[i].Score > bestItem.Score { 74045- bestItem = &c.items[i] 74046- } else if secondBestItem == nil || c.items[i].Score > secondBestItem.Score { 74047- secondBestItem = &c.items[i] 74048- } 74049- } 74050- 74051- // If secondBestItem has the same score, bestItem isn't 74052- // the strict best. 74053- if secondBestItem != nil && secondBestItem.Score == bestItem.Score { 74054- return nil 74055- } 74056- 74057- return bestItem 74058-} 74059- 74060-// addErrCheck offers a completion candidate of the form: 74061-// 74062-// if err != nil { 74063-// return nil, err 74064-// } 74065-// 74066-// In the case of test functions, it offers a completion candidate of the form: 74067-// 74068-// if err != nil { 74069-// t.Fatal(err) 74070-// } 74071-// 74072-// The position must be in a function that returns an error, and the 74073-// statement preceding the position must be an assignment where the 74074-// final LHS object is an error. addErrCheck will synthesize 74075-// zero values as necessary to make the return statement valid. 74076-func (c *completer) addErrCheck() { 74077- if len(c.path) < 2 || c.enclosingFunc == nil || !c.opts.placeholders { 74078- return 74079- } 74080- 74081- var ( 74082- errorType = types.Universe.Lookup("error").Type() 74083- result = c.enclosingFunc.sig.Results() 74084- testVar = getTestVar(c.enclosingFunc, c.pkg) 74085- isTest = testVar != "" 74086- doesNotReturnErr = result.Len() == 0 || !types.Identical(result.At(result.Len()-1).Type(), errorType) 74087- ) 74088- // Make sure our enclosing function is a Test func or returns an error. 74089- if !isTest && doesNotReturnErr { 74090- return 74091- } 74092- 74093- prevLine := prevStmt(c.pos, c.path) 74094- if prevLine == nil { 74095- return 74096- } 74097- 74098- // Make sure our preceding statement was as assignment. 74099- assign, _ := prevLine.(*ast.AssignStmt) 74100- if assign == nil || len(assign.Lhs) == 0 { 74101- return 74102- } 74103- 74104- lastAssignee := assign.Lhs[len(assign.Lhs)-1] 74105- 74106- // Make sure the final assignee is an error. 74107- if !types.Identical(c.pkg.GetTypesInfo().TypeOf(lastAssignee), errorType) { 74108- return 74109- } 74110- 74111- var ( 74112- // errVar is e.g. "err" in "foo, err := bar()". 74113- errVar = source.FormatNode(c.pkg.FileSet(), lastAssignee) 74114- 74115- // Whether we need to include the "if" keyword in our candidate. 74116- needsIf = true 74117- ) 74118- 74119- // If the returned error from the previous statement is "_", it is not a real object. 74120- // If we don't have an error, and the function signature takes a testing.TB that is either ignored 74121- // or an "_", then we also can't call t.Fatal(err). 74122- if errVar == "_" { 74123- return 74124- } 74125- 74126- // Below we try to detect if the user has already started typing "if 74127- // err" so we can replace what they've typed with our complete 74128- // statement. 74129- switch n := c.path[0].(type) { 74130- case *ast.Ident: 74131- switch c.path[1].(type) { 74132- case *ast.ExprStmt: 74133- // This handles: 74134- // 74135- // f, err := os.Open("foo") 74136- // i<> 74137- 74138- // Make sure they are typing "if". 74139- if c.matcher.Score("if") <= 0 { 74140- return 74141- } 74142- case *ast.IfStmt: 74143- // This handles: 74144- // 74145- // f, err := os.Open("foo") 74146- // if er<> 74147- 74148- // Make sure they are typing the error's name. 74149- if c.matcher.Score(errVar) <= 0 { 74150- return 74151- } 74152- 74153- needsIf = false 74154- default: 74155- return 74156- } 74157- case *ast.IfStmt: 74158- // This handles: 74159- // 74160- // f, err := os.Open("foo") 74161- // if <> 74162- 74163- // Avoid false positives by ensuring the if's cond is a bad 74164- // expression. For example, don't offer the completion in cases 74165- // like "if <> somethingElse". 74166- if _, bad := n.Cond.(*ast.BadExpr); !bad { 74167- return 74168- } 74169- 74170- // If "if" is our direct prefix, we need to include it in our 74171- // candidate since the existing "if" will be overwritten. 74172- needsIf = c.pos == n.Pos()+token.Pos(len("if")) 74173- } 74174- 74175- // Build up a snippet that looks like: 74176- // 74177- // if err != nil { 74178- // return <zero value>, ..., ${1:err} 74179- // } 74180- // 74181- // We make the error a placeholder so it is easy to alter the error. 74182- var snip snippet.Builder 74183- if needsIf { 74184- snip.WriteText("if ") 74185- } 74186- snip.WriteText(fmt.Sprintf("%s != nil {\n\t", errVar)) 74187- 74188- var label string 74189- if isTest { 74190- snip.WriteText(fmt.Sprintf("%s.Fatal(%s)", testVar, errVar)) 74191- label = fmt.Sprintf("%[1]s != nil { %[2]s.Fatal(%[1]s) }", errVar, testVar) 74192- } else { 74193- snip.WriteText("return ") 74194- for i := 0; i < result.Len()-1; i++ { 74195- snip.WriteText(formatZeroValue(result.At(i).Type(), c.qf)) 74196- snip.WriteText(", ") 74197- } 74198- snip.WritePlaceholder(func(b *snippet.Builder) { 74199- b.WriteText(errVar) 74200- }) 74201- label = fmt.Sprintf("%[1]s != nil { return %[1]s }", errVar) 74202- } 74203- 74204- snip.WriteText("\n}") 74205- 74206- if needsIf { 74207- label = "if " + label 74208- } 74209- 74210- c.items = append(c.items, CompletionItem{ 74211- Label: label, 74212- // There doesn't seem to be a more appropriate kind. 74213- Kind: protocol.KeywordCompletion, 74214- Score: highScore, 74215- snippet: &snip, 74216- }) 74217-} 74218- 74219-// getTestVar checks the function signature's input parameters and returns 74220-// the name of the first parameter that implements "testing.TB". For example, 74221-// func someFunc(t *testing.T) returns the string "t", func someFunc(b *testing.B) 74222-// returns "b" etc. An empty string indicates that the function signature 74223-// does not take a testing.TB parameter or does so but is ignored such 74224-// as func someFunc(*testing.T). 74225-func getTestVar(enclosingFunc *funcInfo, pkg source.Package) string { 74226- if enclosingFunc == nil || enclosingFunc.sig == nil { 74227- return "" 74228- } 74229- 74230- var testingPkg *types.Package 74231- for _, p := range pkg.GetTypes().Imports() { 74232- if p.Path() == "testing" { 74233- testingPkg = p 74234- break 74235- } 74236- } 74237- if testingPkg == nil { 74238- return "" 74239- } 74240- tbObj := testingPkg.Scope().Lookup("TB") 74241- if tbObj == nil { 74242- return "" 74243- } 74244- iface, ok := tbObj.Type().Underlying().(*types.Interface) 74245- if !ok { 74246- return "" 74247- } 74248- 74249- sig := enclosingFunc.sig 74250- for i := 0; i < sig.Params().Len(); i++ { 74251- param := sig.Params().At(i) 74252- if param.Name() == "_" { 74253- continue 74254- } 74255- if !types.Implements(param.Type(), iface) { 74256- continue 74257- } 74258- return param.Name() 74259- } 74260- 74261- return "" 74262-} 74263diff -urN a/gopls/internal/lsp/source/completion/util.go b/gopls/internal/lsp/source/completion/util.go 74264--- a/gopls/internal/lsp/source/completion/util.go 2000-01-01 00:00:00.000000000 -0000 74265+++ b/gopls/internal/lsp/source/completion/util.go 1970-01-01 00:00:00.000000000 +0000 74266@@ -1,344 +0,0 @@ 74267-// Copyright 2020 The Go Authors. All rights reserved. 74268-// Use of this source code is governed by a BSD-style 74269-// license that can be found in the LICENSE file. 74270- 74271-package completion 74272- 74273-import ( 74274- "go/ast" 74275- "go/token" 74276- "go/types" 74277- 74278- "golang.org/x/tools/go/types/typeutil" 74279- "golang.org/x/tools/gopls/internal/lsp/protocol" 74280- "golang.org/x/tools/gopls/internal/lsp/safetoken" 74281- "golang.org/x/tools/gopls/internal/lsp/source" 74282- "golang.org/x/tools/internal/diff" 74283- "golang.org/x/tools/internal/typeparams" 74284-) 74285- 74286-// exprAtPos returns the index of the expression containing pos. 74287-func exprAtPos(pos token.Pos, args []ast.Expr) int { 74288- for i, expr := range args { 74289- if expr.Pos() <= pos && pos <= expr.End() { 74290- return i 74291- } 74292- } 74293- return len(args) 74294-} 74295- 74296-// eachField invokes fn for each field that can be selected from a 74297-// value of type T. 74298-func eachField(T types.Type, fn func(*types.Var)) { 74299- // TODO(adonovan): this algorithm doesn't exclude ambiguous 74300- // selections that match more than one field/method. 74301- // types.NewSelectionSet should do that for us. 74302- 74303- // for termination on recursive types 74304- var seen typeutil.Map 74305- 74306- var visit func(T types.Type) 74307- visit = func(T types.Type) { 74308- if T, ok := source.Deref(T).Underlying().(*types.Struct); ok { 74309- if seen.At(T) != nil { 74310- return 74311- } 74312- 74313- for i := 0; i < T.NumFields(); i++ { 74314- f := T.Field(i) 74315- fn(f) 74316- if f.Anonymous() { 74317- seen.Set(T, true) 74318- visit(f.Type()) 74319- } 74320- } 74321- } 74322- } 74323- visit(T) 74324-} 74325- 74326-// typeIsValid reports whether typ doesn't contain any Invalid types. 74327-func typeIsValid(typ types.Type) bool { 74328- // Check named types separately, because we don't want 74329- // to call Underlying() on them to avoid problems with recursive types. 74330- if _, ok := typ.(*types.Named); ok { 74331- return true 74332- } 74333- 74334- switch typ := typ.Underlying().(type) { 74335- case *types.Basic: 74336- return typ.Kind() != types.Invalid 74337- case *types.Array: 74338- return typeIsValid(typ.Elem()) 74339- case *types.Slice: 74340- return typeIsValid(typ.Elem()) 74341- case *types.Pointer: 74342- return typeIsValid(typ.Elem()) 74343- case *types.Map: 74344- return typeIsValid(typ.Key()) && typeIsValid(typ.Elem()) 74345- case *types.Chan: 74346- return typeIsValid(typ.Elem()) 74347- case *types.Signature: 74348- return typeIsValid(typ.Params()) && typeIsValid(typ.Results()) 74349- case *types.Tuple: 74350- for i := 0; i < typ.Len(); i++ { 74351- if !typeIsValid(typ.At(i).Type()) { 74352- return false 74353- } 74354- } 74355- return true 74356- case *types.Struct, *types.Interface: 74357- // Don't bother checking structs, interfaces for validity. 74358- return true 74359- default: 74360- return false 74361- } 74362-} 74363- 74364-// resolveInvalid traverses the node of the AST that defines the scope 74365-// containing the declaration of obj, and attempts to find a user-friendly 74366-// name for its invalid type. The resulting Object and its Type are fake. 74367-func resolveInvalid(fset *token.FileSet, obj types.Object, node ast.Node, info *types.Info) types.Object { 74368- var resultExpr ast.Expr 74369- ast.Inspect(node, func(node ast.Node) bool { 74370- switch n := node.(type) { 74371- case *ast.ValueSpec: 74372- for _, name := range n.Names { 74373- if info.Defs[name] == obj { 74374- resultExpr = n.Type 74375- } 74376- } 74377- return false 74378- case *ast.Field: // This case handles parameters and results of a FuncDecl or FuncLit. 74379- for _, name := range n.Names { 74380- if info.Defs[name] == obj { 74381- resultExpr = n.Type 74382- } 74383- } 74384- return false 74385- default: 74386- return true 74387- } 74388- }) 74389- // Construct a fake type for the object and return a fake object with this type. 74390- typename := source.FormatNode(fset, resultExpr) 74391- typ := types.NewNamed(types.NewTypeName(token.NoPos, obj.Pkg(), typename, nil), types.Typ[types.Invalid], nil) 74392- return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ) 74393-} 74394- 74395-func isPointer(T types.Type) bool { 74396- _, ok := T.(*types.Pointer) 74397- return ok 74398-} 74399- 74400-func isVar(obj types.Object) bool { 74401- _, ok := obj.(*types.Var) 74402- return ok 74403-} 74404- 74405-func isTypeName(obj types.Object) bool { 74406- _, ok := obj.(*types.TypeName) 74407- return ok 74408-} 74409- 74410-func isFunc(obj types.Object) bool { 74411- _, ok := obj.(*types.Func) 74412- return ok 74413-} 74414- 74415-func isEmptyInterface(T types.Type) bool { 74416- intf, _ := T.(*types.Interface) 74417- return intf != nil && intf.NumMethods() == 0 && typeparams.IsMethodSet(intf) 74418-} 74419- 74420-func isUntyped(T types.Type) bool { 74421- if basic, ok := T.(*types.Basic); ok { 74422- return basic.Info()&types.IsUntyped > 0 74423- } 74424- return false 74425-} 74426- 74427-func isPkgName(obj types.Object) bool { 74428- _, ok := obj.(*types.PkgName) 74429- return ok 74430-} 74431- 74432-func isASTFile(n ast.Node) bool { 74433- _, ok := n.(*ast.File) 74434- return ok 74435-} 74436- 74437-func deslice(T types.Type) types.Type { 74438- if slice, ok := T.Underlying().(*types.Slice); ok { 74439- return slice.Elem() 74440- } 74441- return nil 74442-} 74443- 74444-// isSelector returns the enclosing *ast.SelectorExpr when pos is in the 74445-// selector. 74446-func enclosingSelector(path []ast.Node, pos token.Pos) *ast.SelectorExpr { 74447- if len(path) == 0 { 74448- return nil 74449- } 74450- 74451- if sel, ok := path[0].(*ast.SelectorExpr); ok { 74452- return sel 74453- } 74454- 74455- if _, ok := path[0].(*ast.Ident); ok && len(path) > 1 { 74456- if sel, ok := path[1].(*ast.SelectorExpr); ok && pos >= sel.Sel.Pos() { 74457- return sel 74458- } 74459- } 74460- 74461- return nil 74462-} 74463- 74464-// enclosingDeclLHS returns LHS idents from containing value spec or 74465-// assign statement. 74466-func enclosingDeclLHS(path []ast.Node) []*ast.Ident { 74467- for _, n := range path { 74468- switch n := n.(type) { 74469- case *ast.ValueSpec: 74470- return n.Names 74471- case *ast.AssignStmt: 74472- ids := make([]*ast.Ident, 0, len(n.Lhs)) 74473- for _, e := range n.Lhs { 74474- if id, ok := e.(*ast.Ident); ok { 74475- ids = append(ids, id) 74476- } 74477- } 74478- return ids 74479- } 74480- } 74481- 74482- return nil 74483-} 74484- 74485-// exprObj returns the types.Object associated with the *ast.Ident or 74486-// *ast.SelectorExpr e. 74487-func exprObj(info *types.Info, e ast.Expr) types.Object { 74488- var ident *ast.Ident 74489- switch expr := e.(type) { 74490- case *ast.Ident: 74491- ident = expr 74492- case *ast.SelectorExpr: 74493- ident = expr.Sel 74494- default: 74495- return nil 74496- } 74497- 74498- return info.ObjectOf(ident) 74499-} 74500- 74501-// typeConversion returns the type being converted to if call is a type 74502-// conversion expression. 74503-func typeConversion(call *ast.CallExpr, info *types.Info) types.Type { 74504- // Type conversion (e.g. "float64(foo)"). 74505- if fun, _ := exprObj(info, call.Fun).(*types.TypeName); fun != nil { 74506- return fun.Type() 74507- } 74508- 74509- return nil 74510-} 74511- 74512-// fieldsAccessible returns whether s has at least one field accessible by p. 74513-func fieldsAccessible(s *types.Struct, p *types.Package) bool { 74514- for i := 0; i < s.NumFields(); i++ { 74515- f := s.Field(i) 74516- if f.Exported() || f.Pkg() == p { 74517- return true 74518- } 74519- } 74520- return false 74521-} 74522- 74523-// prevStmt returns the statement that precedes the statement containing pos. 74524-// For example: 74525-// 74526-// foo := 1 74527-// bar(1 + 2<>) 74528-// 74529-// If "<>" is pos, prevStmt returns "foo := 1" 74530-func prevStmt(pos token.Pos, path []ast.Node) ast.Stmt { 74531- var blockLines []ast.Stmt 74532- for i := 0; i < len(path) && blockLines == nil; i++ { 74533- switch n := path[i].(type) { 74534- case *ast.BlockStmt: 74535- blockLines = n.List 74536- case *ast.CommClause: 74537- blockLines = n.Body 74538- case *ast.CaseClause: 74539- blockLines = n.Body 74540- } 74541- } 74542- 74543- for i := len(blockLines) - 1; i >= 0; i-- { 74544- if blockLines[i].End() < pos { 74545- return blockLines[i] 74546- } 74547- } 74548- 74549- return nil 74550-} 74551- 74552-// formatZeroValue produces Go code representing the zero value of T. It 74553-// returns the empty string if T is invalid. 74554-func formatZeroValue(T types.Type, qf types.Qualifier) string { 74555- switch u := T.Underlying().(type) { 74556- case *types.Basic: 74557- switch { 74558- case u.Info()&types.IsNumeric > 0: 74559- return "0" 74560- case u.Info()&types.IsString > 0: 74561- return `""` 74562- case u.Info()&types.IsBoolean > 0: 74563- return "false" 74564- default: 74565- return "" 74566- } 74567- case *types.Pointer, *types.Interface, *types.Chan, *types.Map, *types.Slice, *types.Signature: 74568- return "nil" 74569- default: 74570- return types.TypeString(T, qf) + "{}" 74571- } 74572-} 74573- 74574-// isBasicKind returns whether t is a basic type of kind k. 74575-func isBasicKind(t types.Type, k types.BasicInfo) bool { 74576- b, _ := t.Underlying().(*types.Basic) 74577- return b != nil && b.Info()&k > 0 74578-} 74579- 74580-func (c *completer) editText(from, to token.Pos, newText string) ([]protocol.TextEdit, error) { 74581- start, end, err := safetoken.Offsets(c.tokFile, from, to) 74582- if err != nil { 74583- return nil, err // can't happen: from/to came from c 74584- } 74585- return source.ToProtocolEdits(c.mapper, []diff.Edit{{ 74586- Start: start, 74587- End: end, 74588- New: newText, 74589- }}) 74590-} 74591- 74592-// assignableTo is like types.AssignableTo, but returns false if 74593-// either type is invalid. 74594-func assignableTo(x, to types.Type) bool { 74595- if x == types.Typ[types.Invalid] || to == types.Typ[types.Invalid] { 74596- return false 74597- } 74598- 74599- return types.AssignableTo(x, to) 74600-} 74601- 74602-// convertibleTo is like types.ConvertibleTo, but returns false if 74603-// either type is invalid. 74604-func convertibleTo(x, to types.Type) bool { 74605- if x == types.Typ[types.Invalid] || to == types.Typ[types.Invalid] { 74606- return false 74607- } 74608- 74609- return types.ConvertibleTo(x, to) 74610-} 74611diff -urN a/gopls/internal/lsp/source/completion/util_test.go b/gopls/internal/lsp/source/completion/util_test.go 74612--- a/gopls/internal/lsp/source/completion/util_test.go 2000-01-01 00:00:00.000000000 -0000 74613+++ b/gopls/internal/lsp/source/completion/util_test.go 1970-01-01 00:00:00.000000000 +0000 74614@@ -1,28 +0,0 @@ 74615-// Copyright 2020 The Go Authors. All rights reserved. 74616-// Use of this source code is governed by a BSD-style 74617-// license that can be found in the LICENSE file. 74618- 74619-package completion 74620- 74621-import ( 74622- "go/types" 74623- "testing" 74624-) 74625- 74626-func TestFormatZeroValue(t *testing.T) { 74627- tests := []struct { 74628- typ types.Type 74629- want string 74630- }{ 74631- {types.Typ[types.String], `""`}, 74632- {types.Typ[types.Byte], "0"}, 74633- {types.Typ[types.Invalid], ""}, 74634- {types.Universe.Lookup("error").Type(), "nil"}, 74635- } 74636- 74637- for _, test := range tests { 74638- if got := formatZeroValue(test.typ, nil); got != test.want { 74639- t.Errorf("formatZeroValue(%v) = %q, want %q", test.typ, got, test.want) 74640- } 74641- } 74642-} 74643diff -urN a/gopls/internal/lsp/source/definition.go b/gopls/internal/lsp/source/definition.go 74644--- a/gopls/internal/lsp/source/definition.go 2000-01-01 00:00:00.000000000 -0000 74645+++ b/gopls/internal/lsp/source/definition.go 1970-01-01 00:00:00.000000000 +0000 74646@@ -1,229 +0,0 @@ 74647-// Copyright 2023 The Go Authors. All rights reserved. 74648-// Use of this source code is governed by a BSD-style 74649-// license that can be found in the LICENSE file. 74650- 74651-package source 74652- 74653-import ( 74654- "context" 74655- "fmt" 74656- "go/ast" 74657- "go/token" 74658- "go/types" 74659- 74660- "golang.org/x/tools/gopls/internal/lsp/protocol" 74661- "golang.org/x/tools/gopls/internal/span" 74662- "golang.org/x/tools/internal/bug" 74663- "golang.org/x/tools/internal/event" 74664-) 74665- 74666-// Definition handles the textDocument/definition request for Go files. 74667-func Definition(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) ([]protocol.Location, error) { 74668- ctx, done := event.Start(ctx, "source.Definition") 74669- defer done() 74670- 74671- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 74672- if err != nil { 74673- return nil, err 74674- } 74675- pos, err := pgf.PositionPos(position) 74676- if err != nil { 74677- return nil, err 74678- } 74679- 74680- // Handle the case where the cursor is in an import. 74681- importLocations, err := importDefinition(ctx, snapshot, pkg, pgf, pos) 74682- if err != nil { 74683- return nil, err 74684- } 74685- if len(importLocations) > 0 { 74686- return importLocations, nil 74687- } 74688- 74689- // Handle the case where the cursor is in the package name. 74690- // We use "<= End" to accept a query immediately after the package name. 74691- if pgf.File != nil && pgf.File.Name.Pos() <= pos && pos <= pgf.File.Name.End() { 74692- // If there's no package documentation, just use current file. 74693- declFile := pgf 74694- for _, pgf := range pkg.CompiledGoFiles() { 74695- if pgf.File.Name != nil && pgf.File.Doc != nil { 74696- declFile = pgf 74697- break 74698- } 74699- } 74700- loc, err := declFile.NodeLocation(declFile.File.Name) 74701- if err != nil { 74702- return nil, err 74703- } 74704- return []protocol.Location{loc}, nil 74705- } 74706- 74707- // The general case: the cursor is on an identifier. 74708- _, obj, _ := referencedObject(pkg, pgf, pos) 74709- if obj == nil { 74710- return nil, nil 74711- } 74712- 74713- // Handle built-in identifiers. 74714- if obj.Parent() == types.Universe { 74715- builtin, err := snapshot.BuiltinFile(ctx) 74716- if err != nil { 74717- return nil, err 74718- } 74719- // Note that builtinObj is an ast.Object, not types.Object :) 74720- builtinObj := builtin.File.Scope.Lookup(obj.Name()) 74721- if builtinObj == nil { 74722- // Every builtin should have documentation. 74723- return nil, bug.Errorf("internal error: no builtin object for %s", obj.Name()) 74724- } 74725- decl, ok := builtinObj.Decl.(ast.Node) 74726- if !ok { 74727- return nil, bug.Errorf("internal error: no declaration for %s", obj.Name()) 74728- } 74729- // The builtin package isn't in the dependency graph, so the usual 74730- // utilities won't work here. 74731- loc, err := builtin.PosLocation(decl.Pos(), decl.Pos()+token.Pos(len(obj.Name()))) 74732- if err != nil { 74733- return nil, err 74734- } 74735- return []protocol.Location{loc}, nil 74736- } 74737- 74738- // Finally, map the object position. 74739- var locs []protocol.Location 74740- if !obj.Pos().IsValid() { 74741- return nil, bug.Errorf("internal error: no position for %v", obj.Name()) 74742- } 74743- loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), adjustedObjEnd(obj)) 74744- if err != nil { 74745- return nil, err 74746- } 74747- locs = append(locs, loc) 74748- return locs, nil 74749-} 74750- 74751-// referencedObject returns the identifier and object referenced at the 74752-// specified position, which must be within the file pgf, for the purposes of 74753-// definition/hover/call hierarchy operations. It returns a nil object if no 74754-// object was found at the given position. 74755-// 74756-// If the returned identifier is a type-switch implicit (i.e. the x in x := 74757-// e.(type)), the third result will be the type of the expression being 74758-// switched on (the type of e in the example). This facilitates workarounds for 74759-// limitations of the go/types API, which does not report an object for the 74760-// identifier x. 74761-// 74762-// For embedded fields, referencedObject returns the type name object rather 74763-// than the var (field) object. 74764-// 74765-// TODO(rfindley): this function exists to preserve the pre-existing behavior 74766-// of source.Identifier. Eliminate this helper in favor of sharing 74767-// functionality with objectsAt, after choosing suitable primitives. 74768-func referencedObject(pkg Package, pgf *ParsedGoFile, pos token.Pos) (*ast.Ident, types.Object, types.Type) { 74769- path := pathEnclosingObjNode(pgf.File, pos) 74770- if len(path) == 0 { 74771- return nil, nil, nil 74772- } 74773- var obj types.Object 74774- info := pkg.GetTypesInfo() 74775- switch n := path[0].(type) { 74776- case *ast.Ident: 74777- obj = info.ObjectOf(n) 74778- // If n is the var's declaring ident in a type switch 74779- // [i.e. the x in x := foo.(type)], it will not have an object. In this 74780- // case, set obj to the first implicit object (if any), and return the type 74781- // of the expression being switched on. 74782- // 74783- // The type switch may have no case clauses and thus no 74784- // implicit objects; this is a type error ("unused x"), 74785- if obj == nil { 74786- if implicits, typ := typeSwitchImplicits(info, path); len(implicits) > 0 { 74787- return n, implicits[0], typ 74788- } 74789- } 74790- 74791- // If the original position was an embedded field, we want to jump 74792- // to the field's type definition, not the field's definition. 74793- if v, ok := obj.(*types.Var); ok && v.Embedded() { 74794- // types.Info.Uses contains the embedded field's *types.TypeName. 74795- if typeName := info.Uses[n]; typeName != nil { 74796- obj = typeName 74797- } 74798- } 74799- return n, obj, nil 74800- } 74801- return nil, nil, nil 74802-} 74803- 74804-// importDefinition returns locations defining a package referenced by the 74805-// import spec containing pos. 74806-// 74807-// If pos is not inside an import spec, it returns nil, nil. 74808-func importDefinition(ctx context.Context, s Snapshot, pkg Package, pgf *ParsedGoFile, pos token.Pos) ([]protocol.Location, error) { 74809- var imp *ast.ImportSpec 74810- for _, spec := range pgf.File.Imports { 74811- // We use "<= End" to accept a query immediately after an ImportSpec. 74812- if spec.Path.Pos() <= pos && pos <= spec.Path.End() { 74813- imp = spec 74814- } 74815- } 74816- if imp == nil { 74817- return nil, nil 74818- } 74819- 74820- importPath := UnquoteImportPath(imp) 74821- impID := pkg.Metadata().DepsByImpPath[importPath] 74822- if impID == "" { 74823- return nil, fmt.Errorf("failed to resolve import %q", importPath) 74824- } 74825- impMetadata := s.Metadata(impID) 74826- if impMetadata == nil { 74827- return nil, fmt.Errorf("missing information for package %q", impID) 74828- } 74829- 74830- var locs []protocol.Location 74831- for _, f := range impMetadata.CompiledGoFiles { 74832- fh, err := s.GetFile(ctx, f) 74833- if err != nil { 74834- if ctx.Err() != nil { 74835- return nil, ctx.Err() 74836- } 74837- continue 74838- } 74839- pgf, err := s.ParseGo(ctx, fh, ParseHeader) 74840- if err != nil { 74841- if ctx.Err() != nil { 74842- return nil, ctx.Err() 74843- } 74844- continue 74845- } 74846- loc, err := pgf.NodeLocation(pgf.File) 74847- if err != nil { 74848- return nil, err 74849- } 74850- locs = append(locs, loc) 74851- } 74852- 74853- if len(locs) == 0 { 74854- return nil, fmt.Errorf("package %q has no readable files", impID) // incl. unsafe 74855- } 74856- 74857- return locs, nil 74858-} 74859- 74860-// TODO(rfindley): avoid the duplicate column mapping here, by associating a 74861-// column mapper with each file handle. 74862-func mapPosition(ctx context.Context, fset *token.FileSet, s FileSource, start, end token.Pos) (protocol.Location, error) { 74863- file := fset.File(start) 74864- uri := span.URIFromPath(file.Name()) 74865- fh, err := s.GetFile(ctx, uri) 74866- if err != nil { 74867- return protocol.Location{}, err 74868- } 74869- content, err := fh.Read() 74870- if err != nil { 74871- return protocol.Location{}, err 74872- } 74873- m := protocol.NewMapper(fh.URI(), content) 74874- return m.PosLocation(file, start, end) 74875-} 74876diff -urN a/gopls/internal/lsp/source/diagnostics.go b/gopls/internal/lsp/source/diagnostics.go 74877--- a/gopls/internal/lsp/source/diagnostics.go 2000-01-01 00:00:00.000000000 -0000 74878+++ b/gopls/internal/lsp/source/diagnostics.go 1970-01-01 00:00:00.000000000 +0000 74879@@ -1,138 +0,0 @@ 74880-// Copyright 2018 The Go Authors. All rights reserved. 74881-// Use of this source code is governed by a BSD-style 74882-// license that can be found in the LICENSE file. 74883- 74884-package source 74885- 74886-import ( 74887- "context" 74888- 74889- "golang.org/x/tools/gopls/internal/lsp/protocol" 74890- "golang.org/x/tools/gopls/internal/span" 74891-) 74892- 74893-type SuggestedFix struct { 74894- Title string 74895- Edits map[span.URI][]protocol.TextEdit 74896- Command *protocol.Command 74897- ActionKind protocol.CodeActionKind 74898-} 74899- 74900-// Analyze reports go/analysis-framework diagnostics in the specified package. 74901-func Analyze(ctx context.Context, snapshot Snapshot, pkgid PackageID, includeConvenience bool) (map[span.URI][]*Diagnostic, error) { 74902- // Exit early if the context has been canceled. This also protects us 74903- // from a race on Options, see golang/go#36699. 74904- if ctx.Err() != nil { 74905- return nil, ctx.Err() 74906- } 74907- 74908- options := snapshot.View().Options() 74909- categories := []map[string]*Analyzer{ 74910- options.DefaultAnalyzers, 74911- options.StaticcheckAnalyzers, 74912- options.TypeErrorAnalyzers, 74913- } 74914- if includeConvenience { // e.g. for codeAction 74915- categories = append(categories, options.ConvenienceAnalyzers) // e.g. fillstruct 74916- } 74917- 74918- var analyzers []*Analyzer 74919- for _, cat := range categories { 74920- for _, a := range cat { 74921- analyzers = append(analyzers, a) 74922- } 74923- } 74924- 74925- analysisDiagnostics, err := snapshot.Analyze(ctx, pkgid, analyzers) 74926- if err != nil { 74927- return nil, err 74928- } 74929- 74930- // Report diagnostics and errors from root analyzers. 74931- reports := make(map[span.URI][]*Diagnostic) 74932- for _, diag := range analysisDiagnostics { 74933- reports[diag.URI] = append(reports[diag.URI], diag) 74934- } 74935- return reports, nil 74936-} 74937- 74938-// FileDiagnostics reports diagnostics in the specified file, 74939-// as used by the "gopls check" command. 74940-// 74941-// TODO(adonovan): factor in common with (*Server).codeAction, which 74942-// executes { PackageForFile; Analyze } too? 74943-// 74944-// TODO(adonovan): opt: this function is called in a loop from the 74945-// "gopls/diagnoseFiles" nonstandard request handler. It would be more 74946-// efficient to compute the set of packages and TypeCheck and 74947-// Analyze them all at once. 74948-func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (FileHandle, []*Diagnostic, error) { 74949- fh, err := snapshot.GetFile(ctx, uri) 74950- if err != nil { 74951- return nil, nil, err 74952- } 74953- pkg, _, err := PackageForFile(ctx, snapshot, uri, NarrowestPackage) 74954- if err != nil { 74955- return nil, nil, err 74956- } 74957- pkgDiags, err := pkg.DiagnosticsForFile(ctx, snapshot, uri) 74958- if err != nil { 74959- return nil, nil, err 74960- } 74961- adiags, err := Analyze(ctx, snapshot, pkg.Metadata().ID, false) 74962- if err != nil { 74963- return nil, nil, err 74964- } 74965- var fileDiags []*Diagnostic // combine load/parse/type + analysis diagnostics 74966- CombineDiagnostics(pkgDiags, adiags[uri], &fileDiags, &fileDiags) 74967- return fh, fileDiags, nil 74968-} 74969- 74970-// CombineDiagnostics combines and filters list/parse/type diagnostics from 74971-// tdiags with adiags, and appends the two lists to *outT and *outA, 74972-// respectively. 74973-// 74974-// Type-error analyzers produce diagnostics that are redundant 74975-// with type checker diagnostics, but more detailed (e.g. fixes). 74976-// Rather than report two diagnostics for the same problem, 74977-// we combine them by augmenting the type-checker diagnostic 74978-// and discarding the analyzer diagnostic. 74979-// 74980-// If an analysis diagnostic has the same range and message as 74981-// a list/parse/type diagnostic, the suggested fix information 74982-// (et al) of the latter is merged into a copy of the former. 74983-// This handles the case where a type-error analyzer suggests 74984-// a fix to a type error, and avoids duplication. 74985-// 74986-// The use of out-slices, though irregular, allows the caller to 74987-// easily choose whether to keep the results separate or combined. 74988-// 74989-// The arguments are not modified. 74990-func CombineDiagnostics(tdiags []*Diagnostic, adiags []*Diagnostic, outT, outA *[]*Diagnostic) { 74991- 74992- // Build index of (list+parse+)type errors. 74993- type key struct { 74994- Range protocol.Range 74995- message string 74996- } 74997- index := make(map[key]int) // maps (Range,Message) to index in tdiags slice 74998- for i, diag := range tdiags { 74999- index[key{diag.Range, diag.Message}] = i 75000- } 75001- 75002- // Filter out analysis diagnostics that match type errors, 75003- // retaining their suggested fix (etc) fields. 75004- for _, diag := range adiags { 75005- if i, ok := index[key{diag.Range, diag.Message}]; ok { 75006- copy := *tdiags[i] 75007- copy.SuggestedFixes = diag.SuggestedFixes 75008- copy.Tags = diag.Tags 75009- tdiags[i] = © 75010- continue 75011- } 75012- 75013- *outA = append(*outA, diag) 75014- } 75015- 75016- *outT = append(*outT, tdiags...) 75017-} 75018diff -urN a/gopls/internal/lsp/source/extract.go b/gopls/internal/lsp/source/extract.go 75019--- a/gopls/internal/lsp/source/extract.go 2000-01-01 00:00:00.000000000 -0000 75020+++ b/gopls/internal/lsp/source/extract.go 1970-01-01 00:00:00.000000000 +0000 75021@@ -1,1331 +0,0 @@ 75022-// Copyright 2020 The Go Authors. All rights reserved. 75023-// Use of this source code is governed by a BSD-style 75024-// license that can be found in the LICENSE file. 75025- 75026-package source 75027- 75028-import ( 75029- "bytes" 75030- "fmt" 75031- "go/ast" 75032- "go/format" 75033- "go/parser" 75034- "go/token" 75035- "go/types" 75036- "sort" 75037- "strings" 75038- "text/scanner" 75039- 75040- "golang.org/x/tools/go/analysis" 75041- "golang.org/x/tools/go/ast/astutil" 75042- "golang.org/x/tools/gopls/internal/lsp/safetoken" 75043- "golang.org/x/tools/internal/analysisinternal" 75044- "golang.org/x/tools/internal/bug" 75045-) 75046- 75047-func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, _ *types.Package, info *types.Info) (*analysis.SuggestedFix, error) { 75048- tokFile := fset.File(file.Pos()) 75049- expr, path, ok, err := CanExtractVariable(start, end, file) 75050- if !ok { 75051- return nil, fmt.Errorf("extractVariable: cannot extract %s: %v", safetoken.StartPosition(fset, start), err) 75052- } 75053- 75054- // Create new AST node for extracted code. 75055- var lhsNames []string 75056- switch expr := expr.(type) { 75057- // TODO: stricter rules for selectorExpr. 75058- case *ast.BasicLit, *ast.CompositeLit, *ast.IndexExpr, *ast.SliceExpr, 75059- *ast.UnaryExpr, *ast.BinaryExpr, *ast.SelectorExpr: 75060- lhsName, _ := generateAvailableIdentifier(expr.Pos(), file, path, info, "x", 0) 75061- lhsNames = append(lhsNames, lhsName) 75062- case *ast.CallExpr: 75063- tup, ok := info.TypeOf(expr).(*types.Tuple) 75064- if !ok { 75065- // If the call expression only has one return value, we can treat it the 75066- // same as our standard extract variable case. 75067- lhsName, _ := generateAvailableIdentifier(expr.Pos(), file, path, info, "x", 0) 75068- lhsNames = append(lhsNames, lhsName) 75069- break 75070- } 75071- idx := 0 75072- for i := 0; i < tup.Len(); i++ { 75073- // Generate a unique variable for each return value. 75074- var lhsName string 75075- lhsName, idx = generateAvailableIdentifier(expr.Pos(), file, path, info, "x", idx) 75076- lhsNames = append(lhsNames, lhsName) 75077- } 75078- default: 75079- return nil, fmt.Errorf("cannot extract %T", expr) 75080- } 75081- 75082- insertBeforeStmt := analysisinternal.StmtToInsertVarBefore(path) 75083- if insertBeforeStmt == nil { 75084- return nil, fmt.Errorf("cannot find location to insert extraction") 75085- } 75086- indent, err := calculateIndentation(src, tokFile, insertBeforeStmt) 75087- if err != nil { 75088- return nil, err 75089- } 75090- newLineIndent := "\n" + indent 75091- 75092- lhs := strings.Join(lhsNames, ", ") 75093- assignStmt := &ast.AssignStmt{ 75094- Lhs: []ast.Expr{ast.NewIdent(lhs)}, 75095- Tok: token.DEFINE, 75096- Rhs: []ast.Expr{expr}, 75097- } 75098- var buf bytes.Buffer 75099- if err := format.Node(&buf, fset, assignStmt); err != nil { 75100- return nil, err 75101- } 75102- assignment := strings.ReplaceAll(buf.String(), "\n", newLineIndent) + newLineIndent 75103- 75104- return &analysis.SuggestedFix{ 75105- TextEdits: []analysis.TextEdit{ 75106- { 75107- Pos: insertBeforeStmt.Pos(), 75108- End: insertBeforeStmt.Pos(), 75109- NewText: []byte(assignment), 75110- }, 75111- { 75112- Pos: start, 75113- End: end, 75114- NewText: []byte(lhs), 75115- }, 75116- }, 75117- }, nil 75118-} 75119- 75120-// CanExtractVariable reports whether the code in the given range can be 75121-// extracted to a variable. 75122-func CanExtractVariable(start, end token.Pos, file *ast.File) (ast.Expr, []ast.Node, bool, error) { 75123- if start == end { 75124- return nil, nil, false, fmt.Errorf("start and end are equal") 75125- } 75126- path, _ := astutil.PathEnclosingInterval(file, start, end) 75127- if len(path) == 0 { 75128- return nil, nil, false, fmt.Errorf("no path enclosing interval") 75129- } 75130- for _, n := range path { 75131- if _, ok := n.(*ast.ImportSpec); ok { 75132- return nil, nil, false, fmt.Errorf("cannot extract variable in an import block") 75133- } 75134- } 75135- node := path[0] 75136- if start != node.Pos() || end != node.End() { 75137- return nil, nil, false, fmt.Errorf("range does not map to an AST node") 75138- } 75139- expr, ok := node.(ast.Expr) 75140- if !ok { 75141- return nil, nil, false, fmt.Errorf("node is not an expression") 75142- } 75143- switch expr.(type) { 75144- case *ast.BasicLit, *ast.CompositeLit, *ast.IndexExpr, *ast.CallExpr, 75145- *ast.SliceExpr, *ast.UnaryExpr, *ast.BinaryExpr, *ast.SelectorExpr: 75146- return expr, path, true, nil 75147- } 75148- return nil, nil, false, fmt.Errorf("cannot extract an %T to a variable", expr) 75149-} 75150- 75151-// Calculate indentation for insertion. 75152-// When inserting lines of code, we must ensure that the lines have consistent 75153-// formatting (i.e. the proper indentation). To do so, we observe the indentation on the 75154-// line of code on which the insertion occurs. 75155-func calculateIndentation(content []byte, tok *token.File, insertBeforeStmt ast.Node) (string, error) { 75156- line := tok.Line(insertBeforeStmt.Pos()) 75157- lineOffset, stmtOffset, err := safetoken.Offsets(tok, tok.LineStart(line), insertBeforeStmt.Pos()) 75158- if err != nil { 75159- return "", err 75160- } 75161- return string(content[lineOffset:stmtOffset]), nil 75162-} 75163- 75164-// generateAvailableIdentifier adjusts the new function name until there are no collisions in scope. 75165-// Possible collisions include other function and variable names. Returns the next index to check for prefix. 75166-func generateAvailableIdentifier(pos token.Pos, file *ast.File, path []ast.Node, info *types.Info, prefix string, idx int) (string, int) { 75167- scopes := CollectScopes(info, path, pos) 75168- return generateIdentifier(idx, prefix, func(name string) bool { 75169- return file.Scope.Lookup(name) != nil || !isValidName(name, scopes) 75170- }) 75171-} 75172- 75173-func generateIdentifier(idx int, prefix string, hasCollision func(string) bool) (string, int) { 75174- name := prefix 75175- if idx != 0 { 75176- name += fmt.Sprintf("%d", idx) 75177- } 75178- for hasCollision(name) { 75179- idx++ 75180- name = fmt.Sprintf("%v%d", prefix, idx) 75181- } 75182- return name, idx + 1 75183-} 75184- 75185-// isValidName checks for variable collision in scope. 75186-func isValidName(name string, scopes []*types.Scope) bool { 75187- for _, scope := range scopes { 75188- if scope == nil { 75189- continue 75190- } 75191- if scope.Lookup(name) != nil { 75192- return false 75193- } 75194- } 75195- return true 75196-} 75197- 75198-// returnVariable keeps track of the information we need to properly introduce a new variable 75199-// that we will return in the extracted function. 75200-type returnVariable struct { 75201- // name is the identifier that is used on the left-hand side of the call to 75202- // the extracted function. 75203- name ast.Expr 75204- // decl is the declaration of the variable. It is used in the type signature of the 75205- // extracted function and for variable declarations. 75206- decl *ast.Field 75207- // zeroVal is the "zero value" of the type of the variable. It is used in a return 75208- // statement in the extracted function. 75209- zeroVal ast.Expr 75210-} 75211- 75212-// extractMethod refactors the selected block of code into a new method. 75213-func extractMethod(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) { 75214- return extractFunctionMethod(fset, start, end, src, file, pkg, info, true) 75215-} 75216- 75217-// extractFunction refactors the selected block of code into a new function. 75218-func extractFunction(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) { 75219- return extractFunctionMethod(fset, start, end, src, file, pkg, info, false) 75220-} 75221- 75222-// extractFunctionMethod refactors the selected block of code into a new function/method. 75223-// It also replaces the selected block of code with a call to the extracted 75224-// function. First, we manually adjust the selection range. We remove trailing 75225-// and leading whitespace characters to ensure the range is precisely bounded 75226-// by AST nodes. Next, we determine the variables that will be the parameters 75227-// and return values of the extracted function/method. Lastly, we construct the call 75228-// of the function/method and insert this call as well as the extracted function/method into 75229-// their proper locations. 75230-func extractFunctionMethod(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info, isMethod bool) (*analysis.SuggestedFix, error) { 75231- errorPrefix := "extractFunction" 75232- if isMethod { 75233- errorPrefix = "extractMethod" 75234- } 75235- 75236- tok := fset.File(file.Pos()) 75237- if tok == nil { 75238- return nil, bug.Errorf("no file for position") 75239- } 75240- p, ok, methodOk, err := CanExtractFunction(tok, start, end, src, file) 75241- if (!ok && !isMethod) || (!methodOk && isMethod) { 75242- return nil, fmt.Errorf("%s: cannot extract %s: %v", errorPrefix, 75243- safetoken.StartPosition(fset, start), err) 75244- } 75245- tok, path, start, end, outer, node := p.tok, p.path, p.start, p.end, p.outer, p.node 75246- fileScope := info.Scopes[file] 75247- if fileScope == nil { 75248- return nil, fmt.Errorf("%s: file scope is empty", errorPrefix) 75249- } 75250- pkgScope := fileScope.Parent() 75251- if pkgScope == nil { 75252- return nil, fmt.Errorf("%s: package scope is empty", errorPrefix) 75253- } 75254- 75255- // A return statement is non-nested if its parent node is equal to the parent node 75256- // of the first node in the selection. These cases must be handled separately because 75257- // non-nested return statements are guaranteed to execute. 75258- var retStmts []*ast.ReturnStmt 75259- var hasNonNestedReturn bool 75260- startParent := findParent(outer, node) 75261- ast.Inspect(outer, func(n ast.Node) bool { 75262- if n == nil { 75263- return false 75264- } 75265- if n.Pos() < start || n.End() > end { 75266- return n.Pos() <= end 75267- } 75268- ret, ok := n.(*ast.ReturnStmt) 75269- if !ok { 75270- return true 75271- } 75272- if findParent(outer, n) == startParent { 75273- hasNonNestedReturn = true 75274- } 75275- retStmts = append(retStmts, ret) 75276- return false 75277- }) 75278- containsReturnStatement := len(retStmts) > 0 75279- 75280- // Now that we have determined the correct range for the selection block, 75281- // we must determine the signature of the extracted function. We will then replace 75282- // the block with an assignment statement that calls the extracted function with 75283- // the appropriate parameters and return values. 75284- variables, err := collectFreeVars(info, file, fileScope, pkgScope, start, end, path[0]) 75285- if err != nil { 75286- return nil, err 75287- } 75288- 75289- var ( 75290- receiverUsed bool 75291- receiver *ast.Field 75292- receiverName string 75293- receiverObj types.Object 75294- ) 75295- if isMethod { 75296- if outer == nil || outer.Recv == nil || len(outer.Recv.List) == 0 { 75297- return nil, fmt.Errorf("%s: cannot extract need method receiver", errorPrefix) 75298- } 75299- receiver = outer.Recv.List[0] 75300- if len(receiver.Names) == 0 || receiver.Names[0] == nil { 75301- return nil, fmt.Errorf("%s: cannot extract need method receiver name", errorPrefix) 75302- } 75303- recvName := receiver.Names[0] 75304- receiverName = recvName.Name 75305- receiverObj = info.ObjectOf(recvName) 75306- } 75307- 75308- var ( 75309- params, returns []ast.Expr // used when calling the extracted function 75310- paramTypes, returnTypes []*ast.Field // used in the signature of the extracted function 75311- uninitialized []types.Object // vars we will need to initialize before the call 75312- ) 75313- 75314- // Avoid duplicates while traversing vars and uninitialized. 75315- seenVars := make(map[types.Object]ast.Expr) 75316- seenUninitialized := make(map[types.Object]struct{}) 75317- 75318- // Some variables on the left-hand side of our assignment statement may be free. If our 75319- // selection begins in the same scope in which the free variable is defined, we can 75320- // redefine it in our assignment statement. See the following example, where 'b' and 75321- // 'err' (both free variables) can be redefined in the second funcCall() while maintaining 75322- // correctness. 75323- // 75324- // 75325- // Not Redefined: 75326- // 75327- // a, err := funcCall() 75328- // var b int 75329- // b, err = funcCall() 75330- // 75331- // Redefined: 75332- // 75333- // a, err := funcCall() 75334- // b, err := funcCall() 75335- // 75336- // We track the number of free variables that can be redefined to maintain our preference 75337- // of using "x, y, z := fn()" style assignment statements. 75338- var canRedefineCount int 75339- 75340- // Each identifier in the selected block must become (1) a parameter to the 75341- // extracted function, (2) a return value of the extracted function, or (3) a local 75342- // variable in the extracted function. Determine the outcome(s) for each variable 75343- // based on whether it is free, altered within the selected block, and used outside 75344- // of the selected block. 75345- for _, v := range variables { 75346- if _, ok := seenVars[v.obj]; ok { 75347- continue 75348- } 75349- if v.obj.Name() == "_" { 75350- // The blank identifier is always a local variable 75351- continue 75352- } 75353- typ := analysisinternal.TypeExpr(file, pkg, v.obj.Type()) 75354- if typ == nil { 75355- return nil, fmt.Errorf("nil AST expression for type: %v", v.obj.Name()) 75356- } 75357- seenVars[v.obj] = typ 75358- identifier := ast.NewIdent(v.obj.Name()) 75359- // An identifier must meet three conditions to become a return value of the 75360- // extracted function. (1) its value must be defined or reassigned within 75361- // the selection (isAssigned), (2) it must be used at least once after the 75362- // selection (isUsed), and (3) its first use after the selection 75363- // cannot be its own reassignment or redefinition (objOverriden). 75364- if v.obj.Parent() == nil { 75365- return nil, fmt.Errorf("parent nil") 75366- } 75367- isUsed, firstUseAfter := objUsed(info, end, v.obj.Parent().End(), v.obj) 75368- if v.assigned && isUsed && !varOverridden(info, firstUseAfter, v.obj, v.free, outer) { 75369- returnTypes = append(returnTypes, &ast.Field{Type: typ}) 75370- returns = append(returns, identifier) 75371- if !v.free { 75372- uninitialized = append(uninitialized, v.obj) 75373- } else if v.obj.Parent().Pos() == startParent.Pos() { 75374- canRedefineCount++ 75375- } 75376- } 75377- // An identifier must meet two conditions to become a parameter of the 75378- // extracted function. (1) it must be free (isFree), and (2) its first 75379- // use within the selection cannot be its own definition (isDefined). 75380- if v.free && !v.defined { 75381- // Skip the selector for a method. 75382- if isMethod && v.obj == receiverObj { 75383- receiverUsed = true 75384- continue 75385- } 75386- params = append(params, identifier) 75387- paramTypes = append(paramTypes, &ast.Field{ 75388- Names: []*ast.Ident{identifier}, 75389- Type: typ, 75390- }) 75391- } 75392- } 75393- 75394- // Find the function literal that encloses the selection. The enclosing function literal 75395- // may not be the enclosing function declaration (i.e. 'outer'). For example, in the 75396- // following block: 75397- // 75398- // func main() { 75399- // ast.Inspect(node, func(n ast.Node) bool { 75400- // v := 1 // this line extracted 75401- // return true 75402- // }) 75403- // } 75404- // 75405- // 'outer' is main(). However, the extracted selection most directly belongs to 75406- // the anonymous function literal, the second argument of ast.Inspect(). We use the 75407- // enclosing function literal to determine the proper return types for return statements 75408- // within the selection. We still need the enclosing function declaration because this is 75409- // the top-level declaration. We inspect the top-level declaration to look for variables 75410- // as well as for code replacement. 75411- enclosing := outer.Type 75412- for _, p := range path { 75413- if p == enclosing { 75414- break 75415- } 75416- if fl, ok := p.(*ast.FuncLit); ok { 75417- enclosing = fl.Type 75418- break 75419- } 75420- } 75421- 75422- // We put the selection in a constructed file. We can then traverse and edit 75423- // the extracted selection without modifying the original AST. 75424- startOffset, endOffset, err := safetoken.Offsets(tok, start, end) 75425- if err != nil { 75426- return nil, err 75427- } 75428- selection := src[startOffset:endOffset] 75429- extractedBlock, err := parseBlockStmt(fset, selection) 75430- if err != nil { 75431- return nil, err 75432- } 75433- 75434- // We need to account for return statements in the selected block, as they will complicate 75435- // the logical flow of the extracted function. See the following example, where ** denotes 75436- // the range to be extracted. 75437- // 75438- // Before: 75439- // 75440- // func _() int { 75441- // a := 1 75442- // b := 2 75443- // **if a == b { 75444- // return a 75445- // }** 75446- // ... 75447- // } 75448- // 75449- // After: 75450- // 75451- // func _() int { 75452- // a := 1 75453- // b := 2 75454- // cond0, ret0 := x0(a, b) 75455- // if cond0 { 75456- // return ret0 75457- // } 75458- // ... 75459- // } 75460- // 75461- // func x0(a int, b int) (bool, int) { 75462- // if a == b { 75463- // return true, a 75464- // } 75465- // return false, 0 75466- // } 75467- // 75468- // We handle returns by adding an additional boolean return value to the extracted function. 75469- // This bool reports whether the original function would have returned. Because the 75470- // extracted selection contains a return statement, we must also add the types in the 75471- // return signature of the enclosing function to the return signature of the 75472- // extracted function. We then add an extra if statement checking this boolean value 75473- // in the original function. If the condition is met, the original function should 75474- // return a value, mimicking the functionality of the original return statement(s) 75475- // in the selection. 75476- // 75477- // If there is a return that is guaranteed to execute (hasNonNestedReturns=true), then 75478- // we don't need to include this additional condition check and can simply return. 75479- // 75480- // Before: 75481- // 75482- // func _() int { 75483- // a := 1 75484- // b := 2 75485- // **if a == b { 75486- // return a 75487- // } 75488- // return b** 75489- // } 75490- // 75491- // After: 75492- // 75493- // func _() int { 75494- // a := 1 75495- // b := 2 75496- // return x0(a, b) 75497- // } 75498- // 75499- // func x0(a int, b int) int { 75500- // if a == b { 75501- // return a 75502- // } 75503- // return b 75504- // } 75505- 75506- var retVars []*returnVariable 75507- var ifReturn *ast.IfStmt 75508- if containsReturnStatement { 75509- if !hasNonNestedReturn { 75510- // The selected block contained return statements, so we have to modify the 75511- // signature of the extracted function as described above. Adjust all of 75512- // the return statements in the extracted function to reflect this change in 75513- // signature. 75514- if err := adjustReturnStatements(returnTypes, seenVars, fset, file, 75515- pkg, extractedBlock); err != nil { 75516- return nil, err 75517- } 75518- } 75519- // Collect the additional return values and types needed to accommodate return 75520- // statements in the selection. Update the type signature of the extracted 75521- // function and construct the if statement that will be inserted in the enclosing 75522- // function. 75523- retVars, ifReturn, err = generateReturnInfo(enclosing, pkg, path, file, info, fset, start, hasNonNestedReturn) 75524- if err != nil { 75525- return nil, err 75526- } 75527- } 75528- 75529- // Add a return statement to the end of the new function. This return statement must include 75530- // the values for the types of the original extracted function signature and (if a return 75531- // statement is present in the selection) enclosing function signature. 75532- // This only needs to be done if the selections does not have a non-nested return, otherwise 75533- // it already terminates with a return statement. 75534- hasReturnValues := len(returns)+len(retVars) > 0 75535- if hasReturnValues && !hasNonNestedReturn { 75536- extractedBlock.List = append(extractedBlock.List, &ast.ReturnStmt{ 75537- Results: append(returns, getZeroVals(retVars)...), 75538- }) 75539- } 75540- 75541- // Construct the appropriate call to the extracted function. 75542- // We must meet two conditions to use ":=" instead of '='. (1) there must be at least 75543- // one variable on the lhs that is uninitialized (non-free) prior to the assignment. 75544- // (2) all of the initialized (free) variables on the lhs must be able to be redefined. 75545- sym := token.ASSIGN 75546- canDefineCount := len(uninitialized) + canRedefineCount 75547- canDefine := len(uninitialized)+len(retVars) > 0 && canDefineCount == len(returns) 75548- if canDefine { 75549- sym = token.DEFINE 75550- } 75551- var name, funName string 75552- if isMethod { 75553- name = "newMethod" 75554- // TODO(suzmue): generate a name that does not conflict for "newMethod". 75555- funName = name 75556- } else { 75557- name = "newFunction" 75558- funName, _ = generateAvailableIdentifier(start, file, path, info, name, 0) 75559- } 75560- extractedFunCall := generateFuncCall(hasNonNestedReturn, hasReturnValues, params, 75561- append(returns, getNames(retVars)...), funName, sym, receiverName) 75562- 75563- // Build the extracted function. 75564- newFunc := &ast.FuncDecl{ 75565- Name: ast.NewIdent(funName), 75566- Type: &ast.FuncType{ 75567- Params: &ast.FieldList{List: paramTypes}, 75568- Results: &ast.FieldList{List: append(returnTypes, getDecls(retVars)...)}, 75569- }, 75570- Body: extractedBlock, 75571- } 75572- if isMethod { 75573- var names []*ast.Ident 75574- if receiverUsed { 75575- names = append(names, ast.NewIdent(receiverName)) 75576- } 75577- newFunc.Recv = &ast.FieldList{ 75578- List: []*ast.Field{{ 75579- Names: names, 75580- Type: receiver.Type, 75581- }}, 75582- } 75583- } 75584- 75585- // Create variable declarations for any identifiers that need to be initialized prior to 75586- // calling the extracted function. We do not manually initialize variables if every return 75587- // value is uninitialized. We can use := to initialize the variables in this situation. 75588- var declarations []ast.Stmt 75589- if canDefineCount != len(returns) { 75590- declarations = initializeVars(uninitialized, retVars, seenUninitialized, seenVars) 75591- } 75592- 75593- var declBuf, replaceBuf, newFuncBuf, ifBuf, commentBuf bytes.Buffer 75594- if err := format.Node(&declBuf, fset, declarations); err != nil { 75595- return nil, err 75596- } 75597- if err := format.Node(&replaceBuf, fset, extractedFunCall); err != nil { 75598- return nil, err 75599- } 75600- if ifReturn != nil { 75601- if err := format.Node(&ifBuf, fset, ifReturn); err != nil { 75602- return nil, err 75603- } 75604- } 75605- if err := format.Node(&newFuncBuf, fset, newFunc); err != nil { 75606- return nil, err 75607- } 75608- // Find all the comments within the range and print them to be put somewhere. 75609- // TODO(suzmue): print these in the extracted function at the correct place. 75610- for _, cg := range file.Comments { 75611- if cg.Pos().IsValid() && cg.Pos() < end && cg.Pos() >= start { 75612- for _, c := range cg.List { 75613- fmt.Fprintln(&commentBuf, c.Text) 75614- } 75615- } 75616- } 75617- 75618- // We're going to replace the whole enclosing function, 75619- // so preserve the text before and after the selected block. 75620- outerStart, outerEnd, err := safetoken.Offsets(tok, outer.Pos(), outer.End()) 75621- if err != nil { 75622- return nil, err 75623- } 75624- before := src[outerStart:startOffset] 75625- after := src[endOffset:outerEnd] 75626- indent, err := calculateIndentation(src, tok, node) 75627- if err != nil { 75628- return nil, err 75629- } 75630- newLineIndent := "\n" + indent 75631- 75632- var fullReplacement strings.Builder 75633- fullReplacement.Write(before) 75634- if commentBuf.Len() > 0 { 75635- comments := strings.ReplaceAll(commentBuf.String(), "\n", newLineIndent) 75636- fullReplacement.WriteString(comments) 75637- } 75638- if declBuf.Len() > 0 { // add any initializations, if needed 75639- initializations := strings.ReplaceAll(declBuf.String(), "\n", newLineIndent) + 75640- newLineIndent 75641- fullReplacement.WriteString(initializations) 75642- } 75643- fullReplacement.Write(replaceBuf.Bytes()) // call the extracted function 75644- if ifBuf.Len() > 0 { // add the if statement below the function call, if needed 75645- ifstatement := newLineIndent + 75646- strings.ReplaceAll(ifBuf.String(), "\n", newLineIndent) 75647- fullReplacement.WriteString(ifstatement) 75648- } 75649- fullReplacement.Write(after) 75650- fullReplacement.WriteString("\n\n") // add newlines after the enclosing function 75651- fullReplacement.Write(newFuncBuf.Bytes()) // insert the extracted function 75652- 75653- return &analysis.SuggestedFix{ 75654- TextEdits: []analysis.TextEdit{{ 75655- Pos: outer.Pos(), 75656- End: outer.End(), 75657- NewText: []byte(fullReplacement.String()), 75658- }}, 75659- }, nil 75660-} 75661- 75662-// adjustRangeForCommentsAndWhiteSpace adjusts the given range to exclude unnecessary leading or 75663-// trailing whitespace characters from selection as well as leading or trailing comments. 75664-// In the following example, each line of the if statement is indented once. There are also two 75665-// extra spaces after the sclosing bracket before the line break and a comment. 75666-// 75667-// \tif (true) { 75668-// \t _ = 1 75669-// \t} // hello \n 75670-// 75671-// By default, a valid range begins at 'if' and ends at the first whitespace character 75672-// after the '}'. But, users are likely to highlight full lines rather than adjusting 75673-// their cursors for whitespace. To support this use case, we must manually adjust the 75674-// ranges to match the correct AST node. In this particular example, we would adjust 75675-// rng.Start forward to the start of 'if' and rng.End backward to after '}'. 75676-func adjustRangeForCommentsAndWhiteSpace(tok *token.File, start, end token.Pos, content []byte, file *ast.File) (token.Pos, token.Pos, error) { 75677- // Adjust the end of the range to after leading whitespace and comments. 75678- prevStart := token.NoPos 75679- startComment := sort.Search(len(file.Comments), func(i int) bool { 75680- // Find the index for the first comment that ends after range start. 75681- return file.Comments[i].End() > start 75682- }) 75683- for prevStart != start { 75684- prevStart = start 75685- // If start is within a comment, move start to the end 75686- // of the comment group. 75687- if startComment < len(file.Comments) && file.Comments[startComment].Pos() <= start && start < file.Comments[startComment].End() { 75688- start = file.Comments[startComment].End() 75689- startComment++ 75690- } 75691- // Move forwards to find a non-whitespace character. 75692- offset, err := safetoken.Offset(tok, start) 75693- if err != nil { 75694- return 0, 0, err 75695- } 75696- for offset < len(content) && isGoWhiteSpace(content[offset]) { 75697- offset++ 75698- } 75699- start = tok.Pos(offset) 75700- } 75701- 75702- // Adjust the end of the range to before trailing whitespace and comments. 75703- prevEnd := token.NoPos 75704- endComment := sort.Search(len(file.Comments), func(i int) bool { 75705- // Find the index for the first comment that ends after the range end. 75706- return file.Comments[i].End() >= end 75707- }) 75708- // Search will return n if not found, so we need to adjust if there are no 75709- // comments that would match. 75710- if endComment == len(file.Comments) { 75711- endComment = -1 75712- } 75713- for prevEnd != end { 75714- prevEnd = end 75715- // If end is within a comment, move end to the start 75716- // of the comment group. 75717- if endComment >= 0 && file.Comments[endComment].Pos() < end && end <= file.Comments[endComment].End() { 75718- end = file.Comments[endComment].Pos() 75719- endComment-- 75720- } 75721- // Move backwards to find a non-whitespace character. 75722- offset, err := safetoken.Offset(tok, end) 75723- if err != nil { 75724- return 0, 0, err 75725- } 75726- for offset > 0 && isGoWhiteSpace(content[offset-1]) { 75727- offset-- 75728- } 75729- end = tok.Pos(offset) 75730- } 75731- 75732- return start, end, nil 75733-} 75734- 75735-// isGoWhiteSpace returns true if b is a considered white space in 75736-// Go as defined by scanner.GoWhitespace. 75737-func isGoWhiteSpace(b byte) bool { 75738- return uint64(scanner.GoWhitespace)&(1<<uint(b)) != 0 75739-} 75740- 75741-// findParent finds the parent AST node of the given target node, if the target is a 75742-// descendant of the starting node. 75743-func findParent(start ast.Node, target ast.Node) ast.Node { 75744- var parent ast.Node 75745- analysisinternal.WalkASTWithParent(start, func(n, p ast.Node) bool { 75746- if n == target { 75747- parent = p 75748- return false 75749- } 75750- return true 75751- }) 75752- return parent 75753-} 75754- 75755-// variable describes the status of a variable within a selection. 75756-type variable struct { 75757- obj types.Object 75758- 75759- // free reports whether the variable is a free variable, meaning it should 75760- // be a parameter to the extracted function. 75761- free bool 75762- 75763- // assigned reports whether the variable is assigned to in the selection. 75764- assigned bool 75765- 75766- // defined reports whether the variable is defined in the selection. 75767- defined bool 75768-} 75769- 75770-// collectFreeVars maps each identifier in the given range to whether it is "free." 75771-// Given a range, a variable in that range is defined as "free" if it is declared 75772-// outside of the range and neither at the file scope nor package scope. These free 75773-// variables will be used as arguments in the extracted function. It also returns a 75774-// list of identifiers that may need to be returned by the extracted function. 75775-// Some of the code in this function has been adapted from tools/cmd/guru/freevars.go. 75776-func collectFreeVars(info *types.Info, file *ast.File, fileScope, pkgScope *types.Scope, start, end token.Pos, node ast.Node) ([]*variable, error) { 75777- // id returns non-nil if n denotes an object that is referenced by the span 75778- // and defined either within the span or in the lexical environment. The bool 75779- // return value acts as an indicator for where it was defined. 75780- id := func(n *ast.Ident) (types.Object, bool) { 75781- obj := info.Uses[n] 75782- if obj == nil { 75783- return info.Defs[n], false 75784- } 75785- if obj.Name() == "_" { 75786- return nil, false // exclude objects denoting '_' 75787- } 75788- if _, ok := obj.(*types.PkgName); ok { 75789- return nil, false // imported package 75790- } 75791- if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) { 75792- return nil, false // not defined in this file 75793- } 75794- scope := obj.Parent() 75795- if scope == nil { 75796- return nil, false // e.g. interface method, struct field 75797- } 75798- if scope == fileScope || scope == pkgScope { 75799- return nil, false // defined at file or package scope 75800- } 75801- if start <= obj.Pos() && obj.Pos() <= end { 75802- return obj, false // defined within selection => not free 75803- } 75804- return obj, true 75805- } 75806- // sel returns non-nil if n denotes a selection o.x.y that is referenced by the 75807- // span and defined either within the span or in the lexical environment. The bool 75808- // return value acts as an indicator for where it was defined. 75809- var sel func(n *ast.SelectorExpr) (types.Object, bool) 75810- sel = func(n *ast.SelectorExpr) (types.Object, bool) { 75811- switch x := astutil.Unparen(n.X).(type) { 75812- case *ast.SelectorExpr: 75813- return sel(x) 75814- case *ast.Ident: 75815- return id(x) 75816- } 75817- return nil, false 75818- } 75819- seen := make(map[types.Object]*variable) 75820- firstUseIn := make(map[types.Object]token.Pos) 75821- var vars []types.Object 75822- ast.Inspect(node, func(n ast.Node) bool { 75823- if n == nil { 75824- return false 75825- } 75826- if start <= n.Pos() && n.End() <= end { 75827- var obj types.Object 75828- var isFree, prune bool 75829- switch n := n.(type) { 75830- case *ast.Ident: 75831- obj, isFree = id(n) 75832- case *ast.SelectorExpr: 75833- obj, isFree = sel(n) 75834- prune = true 75835- } 75836- if obj != nil { 75837- seen[obj] = &variable{ 75838- obj: obj, 75839- free: isFree, 75840- } 75841- vars = append(vars, obj) 75842- // Find the first time that the object is used in the selection. 75843- first, ok := firstUseIn[obj] 75844- if !ok || n.Pos() < first { 75845- firstUseIn[obj] = n.Pos() 75846- } 75847- if prune { 75848- return false 75849- } 75850- } 75851- } 75852- return n.Pos() <= end 75853- }) 75854- 75855- // Find identifiers that are initialized or whose values are altered at some 75856- // point in the selected block. For example, in a selected block from lines 2-4, 75857- // variables x, y, and z are included in assigned. However, in a selected block 75858- // from lines 3-4, only variables y and z are included in assigned. 75859- // 75860- // 1: var a int 75861- // 2: var x int 75862- // 3: y := 3 75863- // 4: z := x + a 75864- // 75865- ast.Inspect(node, func(n ast.Node) bool { 75866- if n == nil { 75867- return false 75868- } 75869- if n.Pos() < start || n.End() > end { 75870- return n.Pos() <= end 75871- } 75872- switch n := n.(type) { 75873- case *ast.AssignStmt: 75874- for _, assignment := range n.Lhs { 75875- lhs, ok := assignment.(*ast.Ident) 75876- if !ok { 75877- continue 75878- } 75879- obj, _ := id(lhs) 75880- if obj == nil { 75881- continue 75882- } 75883- if _, ok := seen[obj]; !ok { 75884- continue 75885- } 75886- seen[obj].assigned = true 75887- if n.Tok != token.DEFINE { 75888- continue 75889- } 75890- // Find identifiers that are defined prior to being used 75891- // elsewhere in the selection. 75892- // TODO: Include identifiers that are assigned prior to being 75893- // used elsewhere in the selection. Then, change the assignment 75894- // to a definition in the extracted function. 75895- if firstUseIn[obj] != lhs.Pos() { 75896- continue 75897- } 75898- // Ensure that the object is not used in its own re-definition. 75899- // For example: 75900- // var f float64 75901- // f, e := math.Frexp(f) 75902- for _, expr := range n.Rhs { 75903- if referencesObj(info, expr, obj) { 75904- continue 75905- } 75906- if _, ok := seen[obj]; !ok { 75907- continue 75908- } 75909- seen[obj].defined = true 75910- break 75911- } 75912- } 75913- return false 75914- case *ast.DeclStmt: 75915- gen, ok := n.Decl.(*ast.GenDecl) 75916- if !ok { 75917- return false 75918- } 75919- for _, spec := range gen.Specs { 75920- vSpecs, ok := spec.(*ast.ValueSpec) 75921- if !ok { 75922- continue 75923- } 75924- for _, vSpec := range vSpecs.Names { 75925- obj, _ := id(vSpec) 75926- if obj == nil { 75927- continue 75928- } 75929- if _, ok := seen[obj]; !ok { 75930- continue 75931- } 75932- seen[obj].assigned = true 75933- } 75934- } 75935- return false 75936- case *ast.IncDecStmt: 75937- if ident, ok := n.X.(*ast.Ident); !ok { 75938- return false 75939- } else if obj, _ := id(ident); obj == nil { 75940- return false 75941- } else { 75942- if _, ok := seen[obj]; !ok { 75943- return false 75944- } 75945- seen[obj].assigned = true 75946- } 75947- } 75948- return true 75949- }) 75950- var variables []*variable 75951- for _, obj := range vars { 75952- v, ok := seen[obj] 75953- if !ok { 75954- return nil, fmt.Errorf("no seen types.Object for %v", obj) 75955- } 75956- variables = append(variables, v) 75957- } 75958- return variables, nil 75959-} 75960- 75961-// referencesObj checks whether the given object appears in the given expression. 75962-func referencesObj(info *types.Info, expr ast.Expr, obj types.Object) bool { 75963- var hasObj bool 75964- ast.Inspect(expr, func(n ast.Node) bool { 75965- if n == nil { 75966- return false 75967- } 75968- ident, ok := n.(*ast.Ident) 75969- if !ok { 75970- return true 75971- } 75972- objUse := info.Uses[ident] 75973- if obj == objUse { 75974- hasObj = true 75975- return false 75976- } 75977- return false 75978- }) 75979- return hasObj 75980-} 75981- 75982-type fnExtractParams struct { 75983- tok *token.File 75984- start, end token.Pos 75985- path []ast.Node 75986- outer *ast.FuncDecl 75987- node ast.Node 75988-} 75989- 75990-// CanExtractFunction reports whether the code in the given range can be 75991-// extracted to a function. 75992-func CanExtractFunction(tok *token.File, start, end token.Pos, src []byte, file *ast.File) (*fnExtractParams, bool, bool, error) { 75993- if start == end { 75994- return nil, false, false, fmt.Errorf("start and end are equal") 75995- } 75996- var err error 75997- start, end, err = adjustRangeForCommentsAndWhiteSpace(tok, start, end, src, file) 75998- if err != nil { 75999- return nil, false, false, err 76000- } 76001- path, _ := astutil.PathEnclosingInterval(file, start, end) 76002- if len(path) == 0 { 76003- return nil, false, false, fmt.Errorf("no path enclosing interval") 76004- } 76005- // Node that encloses the selection must be a statement. 76006- // TODO: Support function extraction for an expression. 76007- _, ok := path[0].(ast.Stmt) 76008- if !ok { 76009- return nil, false, false, fmt.Errorf("node is not a statement") 76010- } 76011- 76012- // Find the function declaration that encloses the selection. 76013- var outer *ast.FuncDecl 76014- for _, p := range path { 76015- if p, ok := p.(*ast.FuncDecl); ok { 76016- outer = p 76017- break 76018- } 76019- } 76020- if outer == nil { 76021- return nil, false, false, fmt.Errorf("no enclosing function") 76022- } 76023- 76024- // Find the nodes at the start and end of the selection. 76025- var startNode, endNode ast.Node 76026- ast.Inspect(outer, func(n ast.Node) bool { 76027- if n == nil { 76028- return false 76029- } 76030- // Do not override 'start' with a node that begins at the same location 76031- // but is nested further from 'outer'. 76032- if startNode == nil && n.Pos() == start && n.End() <= end { 76033- startNode = n 76034- } 76035- if endNode == nil && n.End() == end && n.Pos() >= start { 76036- endNode = n 76037- } 76038- return n.Pos() <= end 76039- }) 76040- if startNode == nil || endNode == nil { 76041- return nil, false, false, fmt.Errorf("range does not map to AST nodes") 76042- } 76043- // If the region is a blockStmt, use the first and last nodes in the block 76044- // statement. 76045- // <rng.start>{ ... }<rng.end> => { <rng.start>...<rng.end> } 76046- if blockStmt, ok := startNode.(*ast.BlockStmt); ok { 76047- if len(blockStmt.List) == 0 { 76048- return nil, false, false, fmt.Errorf("range maps to empty block statement") 76049- } 76050- startNode, endNode = blockStmt.List[0], blockStmt.List[len(blockStmt.List)-1] 76051- start, end = startNode.Pos(), endNode.End() 76052- } 76053- return &fnExtractParams{ 76054- tok: tok, 76055- start: start, 76056- end: end, 76057- path: path, 76058- outer: outer, 76059- node: startNode, 76060- }, true, outer.Recv != nil, nil 76061-} 76062- 76063-// objUsed checks if the object is used within the range. It returns the first 76064-// occurrence of the object in the range, if it exists. 76065-func objUsed(info *types.Info, start, end token.Pos, obj types.Object) (bool, *ast.Ident) { 76066- var firstUse *ast.Ident 76067- for id, objUse := range info.Uses { 76068- if obj != objUse { 76069- continue 76070- } 76071- if id.Pos() < start || id.End() > end { 76072- continue 76073- } 76074- if firstUse == nil || id.Pos() < firstUse.Pos() { 76075- firstUse = id 76076- } 76077- } 76078- return firstUse != nil, firstUse 76079-} 76080- 76081-// varOverridden traverses the given AST node until we find the given identifier. Then, we 76082-// examine the occurrence of the given identifier and check for (1) whether the identifier 76083-// is being redefined. If the identifier is free, we also check for (2) whether the identifier 76084-// is being reassigned. We will not include an identifier in the return statement of the 76085-// extracted function if it meets one of the above conditions. 76086-func varOverridden(info *types.Info, firstUse *ast.Ident, obj types.Object, isFree bool, node ast.Node) bool { 76087- var isOverriden bool 76088- ast.Inspect(node, func(n ast.Node) bool { 76089- if n == nil { 76090- return false 76091- } 76092- assignment, ok := n.(*ast.AssignStmt) 76093- if !ok { 76094- return true 76095- } 76096- // A free variable is initialized prior to the selection. We can always reassign 76097- // this variable after the selection because it has already been defined. 76098- // Conversely, a non-free variable is initialized within the selection. Thus, we 76099- // cannot reassign this variable after the selection unless it is initialized and 76100- // returned by the extracted function. 76101- if !isFree && assignment.Tok == token.ASSIGN { 76102- return false 76103- } 76104- for _, assigned := range assignment.Lhs { 76105- ident, ok := assigned.(*ast.Ident) 76106- // Check if we found the first use of the identifier. 76107- if !ok || ident != firstUse { 76108- continue 76109- } 76110- objUse := info.Uses[ident] 76111- if objUse == nil || objUse != obj { 76112- continue 76113- } 76114- // Ensure that the object is not used in its own definition. 76115- // For example: 76116- // var f float64 76117- // f, e := math.Frexp(f) 76118- for _, expr := range assignment.Rhs { 76119- if referencesObj(info, expr, obj) { 76120- return false 76121- } 76122- } 76123- isOverriden = true 76124- return false 76125- } 76126- return false 76127- }) 76128- return isOverriden 76129-} 76130- 76131-// parseBlockStmt generates an AST file from the given text. We then return the portion of the 76132-// file that represents the text. 76133-func parseBlockStmt(fset *token.FileSet, src []byte) (*ast.BlockStmt, error) { 76134- text := "package main\nfunc _() { " + string(src) + " }" 76135- extract, err := parser.ParseFile(fset, "", text, 0) 76136- if err != nil { 76137- return nil, err 76138- } 76139- if len(extract.Decls) == 0 { 76140- return nil, fmt.Errorf("parsed file does not contain any declarations") 76141- } 76142- decl, ok := extract.Decls[0].(*ast.FuncDecl) 76143- if !ok { 76144- return nil, fmt.Errorf("parsed file does not contain expected function declaration") 76145- } 76146- if decl.Body == nil { 76147- return nil, fmt.Errorf("extracted function has no body") 76148- } 76149- return decl.Body, nil 76150-} 76151- 76152-// generateReturnInfo generates the information we need to adjust the return statements and 76153-// signature of the extracted function. We prepare names, signatures, and "zero values" that 76154-// represent the new variables. We also use this information to construct the if statement that 76155-// is inserted below the call to the extracted function. 76156-func generateReturnInfo(enclosing *ast.FuncType, pkg *types.Package, path []ast.Node, file *ast.File, info *types.Info, fset *token.FileSet, pos token.Pos, hasNonNestedReturns bool) ([]*returnVariable, *ast.IfStmt, error) { 76157- var retVars []*returnVariable 76158- var cond *ast.Ident 76159- if !hasNonNestedReturns { 76160- // Generate information for the added bool value. 76161- name, _ := generateAvailableIdentifier(pos, file, path, info, "shouldReturn", 0) 76162- cond = &ast.Ident{Name: name} 76163- retVars = append(retVars, &returnVariable{ 76164- name: cond, 76165- decl: &ast.Field{Type: ast.NewIdent("bool")}, 76166- zeroVal: ast.NewIdent("false"), 76167- }) 76168- } 76169- // Generate information for the values in the return signature of the enclosing function. 76170- if enclosing.Results != nil { 76171- idx := 0 76172- for _, field := range enclosing.Results.List { 76173- typ := info.TypeOf(field.Type) 76174- if typ == nil { 76175- return nil, nil, fmt.Errorf( 76176- "failed type conversion, AST expression: %T", field.Type) 76177- } 76178- expr := analysisinternal.TypeExpr(file, pkg, typ) 76179- if expr == nil { 76180- return nil, nil, fmt.Errorf("nil AST expression") 76181- } 76182- var name string 76183- name, idx = generateAvailableIdentifier(pos, file, 76184- path, info, "returnValue", idx) 76185- retVars = append(retVars, &returnVariable{ 76186- name: ast.NewIdent(name), 76187- decl: &ast.Field{Type: expr}, 76188- zeroVal: analysisinternal.ZeroValue(file, pkg, typ), 76189- }) 76190- } 76191- } 76192- var ifReturn *ast.IfStmt 76193- if !hasNonNestedReturns { 76194- // Create the return statement for the enclosing function. We must exclude the variable 76195- // for the condition of the if statement (cond) from the return statement. 76196- ifReturn = &ast.IfStmt{ 76197- Cond: cond, 76198- Body: &ast.BlockStmt{ 76199- List: []ast.Stmt{&ast.ReturnStmt{Results: getNames(retVars)[1:]}}, 76200- }, 76201- } 76202- } 76203- return retVars, ifReturn, nil 76204-} 76205- 76206-// adjustReturnStatements adds "zero values" of the given types to each return statement 76207-// in the given AST node. 76208-func adjustReturnStatements(returnTypes []*ast.Field, seenVars map[types.Object]ast.Expr, fset *token.FileSet, file *ast.File, pkg *types.Package, extractedBlock *ast.BlockStmt) error { 76209- var zeroVals []ast.Expr 76210- // Create "zero values" for each type. 76211- for _, returnType := range returnTypes { 76212- var val ast.Expr 76213- for obj, typ := range seenVars { 76214- if typ != returnType.Type { 76215- continue 76216- } 76217- val = analysisinternal.ZeroValue(file, pkg, obj.Type()) 76218- break 76219- } 76220- if val == nil { 76221- return fmt.Errorf( 76222- "could not find matching AST expression for %T", returnType.Type) 76223- } 76224- zeroVals = append(zeroVals, val) 76225- } 76226- // Add "zero values" to each return statement. 76227- // The bool reports whether the enclosing function should return after calling the 76228- // extracted function. We set the bool to 'true' because, if these return statements 76229- // execute, the extracted function terminates early, and the enclosing function must 76230- // return as well. 76231- zeroVals = append(zeroVals, ast.NewIdent("true")) 76232- ast.Inspect(extractedBlock, func(n ast.Node) bool { 76233- if n == nil { 76234- return false 76235- } 76236- if n, ok := n.(*ast.ReturnStmt); ok { 76237- n.Results = append(zeroVals, n.Results...) 76238- return false 76239- } 76240- return true 76241- }) 76242- return nil 76243-} 76244- 76245-// generateFuncCall constructs a call expression for the extracted function, described by the 76246-// given parameters and return variables. 76247-func generateFuncCall(hasNonNestedReturn, hasReturnVals bool, params, returns []ast.Expr, name string, token token.Token, selector string) ast.Node { 76248- var replace ast.Node 76249- callExpr := &ast.CallExpr{ 76250- Fun: ast.NewIdent(name), 76251- Args: params, 76252- } 76253- if selector != "" { 76254- callExpr = &ast.CallExpr{ 76255- Fun: &ast.SelectorExpr{ 76256- X: ast.NewIdent(selector), 76257- Sel: ast.NewIdent(name), 76258- }, 76259- Args: params, 76260- } 76261- } 76262- if hasReturnVals { 76263- if hasNonNestedReturn { 76264- // Create a return statement that returns the result of the function call. 76265- replace = &ast.ReturnStmt{ 76266- Return: 0, 76267- Results: []ast.Expr{callExpr}, 76268- } 76269- } else { 76270- // Assign the result of the function call. 76271- replace = &ast.AssignStmt{ 76272- Lhs: returns, 76273- Tok: token, 76274- Rhs: []ast.Expr{callExpr}, 76275- } 76276- } 76277- } else { 76278- replace = callExpr 76279- } 76280- return replace 76281-} 76282- 76283-// initializeVars creates variable declarations, if needed. 76284-// Our preference is to replace the selected block with an "x, y, z := fn()" style 76285-// assignment statement. We can use this style when all of the variables in the 76286-// extracted function's return statement are either not defined prior to the extracted block 76287-// or can be safely redefined. However, for example, if z is already defined 76288-// in a different scope, we replace the selected block with: 76289-// 76290-// var x int 76291-// var y string 76292-// x, y, z = fn() 76293-func initializeVars(uninitialized []types.Object, retVars []*returnVariable, seenUninitialized map[types.Object]struct{}, seenVars map[types.Object]ast.Expr) []ast.Stmt { 76294- var declarations []ast.Stmt 76295- for _, obj := range uninitialized { 76296- if _, ok := seenUninitialized[obj]; ok { 76297- continue 76298- } 76299- seenUninitialized[obj] = struct{}{} 76300- valSpec := &ast.ValueSpec{ 76301- Names: []*ast.Ident{ast.NewIdent(obj.Name())}, 76302- Type: seenVars[obj], 76303- } 76304- genDecl := &ast.GenDecl{ 76305- Tok: token.VAR, 76306- Specs: []ast.Spec{valSpec}, 76307- } 76308- declarations = append(declarations, &ast.DeclStmt{Decl: genDecl}) 76309- } 76310- // Each variable added from a return statement in the selection 76311- // must be initialized. 76312- for i, retVar := range retVars { 76313- n := retVar.name.(*ast.Ident) 76314- valSpec := &ast.ValueSpec{ 76315- Names: []*ast.Ident{n}, 76316- Type: retVars[i].decl.Type, 76317- } 76318- genDecl := &ast.GenDecl{ 76319- Tok: token.VAR, 76320- Specs: []ast.Spec{valSpec}, 76321- } 76322- declarations = append(declarations, &ast.DeclStmt{Decl: genDecl}) 76323- } 76324- return declarations 76325-} 76326- 76327-// getNames returns the names from the given list of returnVariable. 76328-func getNames(retVars []*returnVariable) []ast.Expr { 76329- var names []ast.Expr 76330- for _, retVar := range retVars { 76331- names = append(names, retVar.name) 76332- } 76333- return names 76334-} 76335- 76336-// getZeroVals returns the "zero values" from the given list of returnVariable. 76337-func getZeroVals(retVars []*returnVariable) []ast.Expr { 76338- var zvs []ast.Expr 76339- for _, retVar := range retVars { 76340- zvs = append(zvs, retVar.zeroVal) 76341- } 76342- return zvs 76343-} 76344- 76345-// getDecls returns the declarations from the given list of returnVariable. 76346-func getDecls(retVars []*returnVariable) []*ast.Field { 76347- var decls []*ast.Field 76348- for _, retVar := range retVars { 76349- decls = append(decls, retVar.decl) 76350- } 76351- return decls 76352-} 76353diff -urN a/gopls/internal/lsp/source/fix.go b/gopls/internal/lsp/source/fix.go 76354--- a/gopls/internal/lsp/source/fix.go 2000-01-01 00:00:00.000000000 -0000 76355+++ b/gopls/internal/lsp/source/fix.go 1970-01-01 00:00:00.000000000 +0000 76356@@ -1,138 +0,0 @@ 76357-// Copyright 2020 The Go Authors. All rights reserved. 76358-// Use of this source code is governed by a BSD-style 76359-// license that can be found in the LICENSE file. 76360- 76361-package source 76362- 76363-import ( 76364- "context" 76365- "fmt" 76366- "go/ast" 76367- "go/token" 76368- "go/types" 76369- 76370- "golang.org/x/tools/go/analysis" 76371- "golang.org/x/tools/gopls/internal/lsp/analysis/fillstruct" 76372- "golang.org/x/tools/gopls/internal/lsp/analysis/undeclaredname" 76373- "golang.org/x/tools/gopls/internal/lsp/protocol" 76374- "golang.org/x/tools/gopls/internal/span" 76375- "golang.org/x/tools/internal/bug" 76376-) 76377- 76378-type ( 76379- // SuggestedFixFunc is a function used to get the suggested fixes for a given 76380- // gopls command, some of which are provided by go/analysis.Analyzers. Some of 76381- // the analyzers in internal/lsp/analysis are not efficient enough to include 76382- // suggested fixes with their diagnostics, so we have to compute them 76383- // separately. Such analyzers should provide a function with a signature of 76384- // SuggestedFixFunc. 76385- // 76386- // The returned FileSet must map all token.Pos found in the suggested text 76387- // edits. 76388- SuggestedFixFunc func(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) 76389- singleFileFixFunc func(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) 76390-) 76391- 76392-const ( 76393- FillStruct = "fill_struct" 76394- StubMethods = "stub_methods" 76395- UndeclaredName = "undeclared_name" 76396- ExtractVariable = "extract_variable" 76397- ExtractFunction = "extract_function" 76398- ExtractMethod = "extract_method" 76399-) 76400- 76401-// suggestedFixes maps a suggested fix command id to its handler. 76402-var suggestedFixes = map[string]SuggestedFixFunc{ 76403- FillStruct: singleFile(fillstruct.SuggestedFix), 76404- UndeclaredName: singleFile(undeclaredname.SuggestedFix), 76405- ExtractVariable: singleFile(extractVariable), 76406- ExtractFunction: singleFile(extractFunction), 76407- ExtractMethod: singleFile(extractMethod), 76408- StubMethods: stubSuggestedFixFunc, 76409-} 76410- 76411-// singleFile calls analyzers that expect inputs for a single file 76412-func singleFile(sf singleFileFixFunc) SuggestedFixFunc { 76413- return func(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) { 76414- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 76415- if err != nil { 76416- return nil, nil, err 76417- } 76418- start, end, err := pgf.RangePos(pRng) 76419- if err != nil { 76420- return nil, nil, err 76421- } 76422- fix, err := sf(pkg.FileSet(), start, end, pgf.Src, pgf.File, pkg.GetTypes(), pkg.GetTypesInfo()) 76423- return pkg.FileSet(), fix, err 76424- } 76425-} 76426- 76427-func SuggestedFixFromCommand(cmd protocol.Command, kind protocol.CodeActionKind) SuggestedFix { 76428- return SuggestedFix{ 76429- Title: cmd.Title, 76430- Command: &cmd, 76431- ActionKind: kind, 76432- } 76433-} 76434- 76435-// ApplyFix applies the command's suggested fix to the given file and 76436-// range, returning the resulting edits. 76437-func ApplyFix(ctx context.Context, fix string, snapshot Snapshot, fh FileHandle, pRng protocol.Range) ([]protocol.TextDocumentEdit, error) { 76438- handler, ok := suggestedFixes[fix] 76439- if !ok { 76440- return nil, fmt.Errorf("no suggested fix function for %s", fix) 76441- } 76442- fset, suggestion, err := handler(ctx, snapshot, fh, pRng) 76443- if err != nil { 76444- return nil, err 76445- } 76446- if suggestion == nil { 76447- return nil, nil 76448- } 76449- editsPerFile := map[span.URI]*protocol.TextDocumentEdit{} 76450- for _, edit := range suggestion.TextEdits { 76451- tokFile := fset.File(edit.Pos) 76452- if tokFile == nil { 76453- return nil, bug.Errorf("no file for edit position") 76454- } 76455- end := edit.End 76456- if !end.IsValid() { 76457- end = edit.Pos 76458- } 76459- fh, err := snapshot.GetFile(ctx, span.URIFromPath(tokFile.Name())) 76460- if err != nil { 76461- return nil, err 76462- } 76463- te, ok := editsPerFile[fh.URI()] 76464- if !ok { 76465- te = &protocol.TextDocumentEdit{ 76466- TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{ 76467- Version: fh.Version(), 76468- TextDocumentIdentifier: protocol.TextDocumentIdentifier{ 76469- URI: protocol.URIFromSpanURI(fh.URI()), 76470- }, 76471- }, 76472- } 76473- editsPerFile[fh.URI()] = te 76474- } 76475- content, err := fh.Read() 76476- if err != nil { 76477- return nil, err 76478- } 76479- m := protocol.NewMapper(fh.URI(), content) 76480- rng, err := m.PosRange(tokFile, edit.Pos, end) 76481- if err != nil { 76482- return nil, err 76483- } 76484- te.Edits = append(te.Edits, protocol.TextEdit{ 76485- Range: rng, 76486- NewText: string(edit.NewText), 76487- }) 76488- } 76489- var edits []protocol.TextDocumentEdit 76490- for _, edit := range editsPerFile { 76491- edits = append(edits, *edit) 76492- } 76493- return edits, nil 76494-} 76495diff -urN a/gopls/internal/lsp/source/folding_range.go b/gopls/internal/lsp/source/folding_range.go 76496--- a/gopls/internal/lsp/source/folding_range.go 2000-01-01 00:00:00.000000000 -0000 76497+++ b/gopls/internal/lsp/source/folding_range.go 1970-01-01 00:00:00.000000000 +0000 76498@@ -1,193 +0,0 @@ 76499-// Copyright 2019 The Go Authors. All rights reserved. 76500-// Use of this source code is governed by a BSD-style 76501-// license that can be found in the LICENSE file. 76502- 76503-package source 76504- 76505-import ( 76506- "context" 76507- "go/ast" 76508- "go/token" 76509- "sort" 76510- "strings" 76511- 76512- "golang.org/x/tools/gopls/internal/lsp/protocol" 76513- "golang.org/x/tools/internal/bug" 76514-) 76515- 76516-// FoldingRangeInfo holds range and kind info of folding for an ast.Node 76517-type FoldingRangeInfo struct { 76518- MappedRange protocol.MappedRange 76519- Kind protocol.FoldingRangeKind 76520-} 76521- 76522-// FoldingRange gets all of the folding range for f. 76523-func FoldingRange(ctx context.Context, snapshot Snapshot, fh FileHandle, lineFoldingOnly bool) (ranges []*FoldingRangeInfo, err error) { 76524- // TODO(suzmue): consider limiting the number of folding ranges returned, and 76525- // implement a way to prioritize folding ranges in that case. 76526- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 76527- if err != nil { 76528- return nil, err 76529- } 76530- 76531- // With parse errors, we wouldn't be able to produce accurate folding info. 76532- // LSP protocol (3.16) currently does not have a way to handle this case 76533- // (https://github.com/microsoft/language-server-protocol/issues/1200). 76534- // We cannot return an error either because we are afraid some editors 76535- // may not handle errors nicely. As a workaround, we now return an empty 76536- // result and let the client handle this case by double check the file 76537- // contents (i.e. if the file is not empty and the folding range result 76538- // is empty, raise an internal error). 76539- if pgf.ParseErr != nil { 76540- return nil, nil 76541- } 76542- 76543- // Get folding ranges for comments separately as they are not walked by ast.Inspect. 76544- ranges = append(ranges, commentsFoldingRange(pgf)...) 76545- 76546- visit := func(n ast.Node) bool { 76547- rng := foldingRangeFunc(pgf, n, lineFoldingOnly) 76548- if rng != nil { 76549- ranges = append(ranges, rng) 76550- } 76551- return true 76552- } 76553- // Walk the ast and collect folding ranges. 76554- ast.Inspect(pgf.File, visit) 76555- 76556- sort.Slice(ranges, func(i, j int) bool { 76557- irng := ranges[i].MappedRange.Range() 76558- jrng := ranges[j].MappedRange.Range() 76559- return protocol.CompareRange(irng, jrng) < 0 76560- }) 76561- 76562- return ranges, nil 76563-} 76564- 76565-// foldingRangeFunc calculates the line folding range for ast.Node n 76566-func foldingRangeFunc(pgf *ParsedGoFile, n ast.Node, lineFoldingOnly bool) *FoldingRangeInfo { 76567- // TODO(suzmue): include trailing empty lines before the closing 76568- // parenthesis/brace. 76569- var kind protocol.FoldingRangeKind 76570- var start, end token.Pos 76571- switch n := n.(type) { 76572- case *ast.BlockStmt: 76573- // Fold between positions of or lines between "{" and "}". 76574- var startList, endList token.Pos 76575- if num := len(n.List); num != 0 { 76576- startList, endList = n.List[0].Pos(), n.List[num-1].End() 76577- } 76578- start, end = validLineFoldingRange(pgf.Tok, n.Lbrace, n.Rbrace, startList, endList, lineFoldingOnly) 76579- case *ast.CaseClause: 76580- // Fold from position of ":" to end. 76581- start, end = n.Colon+1, n.End() 76582- case *ast.CommClause: 76583- // Fold from position of ":" to end. 76584- start, end = n.Colon+1, n.End() 76585- case *ast.CallExpr: 76586- // Fold from position of "(" to position of ")". 76587- start, end = n.Lparen+1, n.Rparen 76588- case *ast.FieldList: 76589- // Fold between positions of or lines between opening parenthesis/brace and closing parenthesis/brace. 76590- var startList, endList token.Pos 76591- if num := len(n.List); num != 0 { 76592- startList, endList = n.List[0].Pos(), n.List[num-1].End() 76593- } 76594- start, end = validLineFoldingRange(pgf.Tok, n.Opening, n.Closing, startList, endList, lineFoldingOnly) 76595- case *ast.GenDecl: 76596- // If this is an import declaration, set the kind to be protocol.Imports. 76597- if n.Tok == token.IMPORT { 76598- kind = protocol.Imports 76599- } 76600- // Fold between positions of or lines between "(" and ")". 76601- var startSpecs, endSpecs token.Pos 76602- if num := len(n.Specs); num != 0 { 76603- startSpecs, endSpecs = n.Specs[0].Pos(), n.Specs[num-1].End() 76604- } 76605- start, end = validLineFoldingRange(pgf.Tok, n.Lparen, n.Rparen, startSpecs, endSpecs, lineFoldingOnly) 76606- case *ast.BasicLit: 76607- // Fold raw string literals from position of "`" to position of "`". 76608- if n.Kind == token.STRING && len(n.Value) >= 2 && n.Value[0] == '`' && n.Value[len(n.Value)-1] == '`' { 76609- start, end = n.Pos(), n.End() 76610- } 76611- case *ast.CompositeLit: 76612- // Fold between positions of or lines between "{" and "}". 76613- var startElts, endElts token.Pos 76614- if num := len(n.Elts); num != 0 { 76615- startElts, endElts = n.Elts[0].Pos(), n.Elts[num-1].End() 76616- } 76617- start, end = validLineFoldingRange(pgf.Tok, n.Lbrace, n.Rbrace, startElts, endElts, lineFoldingOnly) 76618- } 76619- 76620- // Check that folding positions are valid. 76621- if !start.IsValid() || !end.IsValid() { 76622- return nil 76623- } 76624- // in line folding mode, do not fold if the start and end lines are the same. 76625- if lineFoldingOnly && pgf.Tok.Line(start) == pgf.Tok.Line(end) { 76626- return nil 76627- } 76628- mrng, err := pgf.PosMappedRange(start, end) 76629- if err != nil { 76630- bug.Errorf("%w", err) // can't happen 76631- } 76632- return &FoldingRangeInfo{ 76633- MappedRange: mrng, 76634- Kind: kind, 76635- } 76636-} 76637- 76638-// validLineFoldingRange returns start and end token.Pos for folding range if the range is valid. 76639-// returns token.NoPos otherwise, which fails token.IsValid check 76640-func validLineFoldingRange(tokFile *token.File, open, close, start, end token.Pos, lineFoldingOnly bool) (token.Pos, token.Pos) { 76641- if lineFoldingOnly { 76642- if !open.IsValid() || !close.IsValid() { 76643- return token.NoPos, token.NoPos 76644- } 76645- 76646- // Don't want to fold if the start/end is on the same line as the open/close 76647- // as an example, the example below should *not* fold: 76648- // var x = [2]string{"d", 76649- // "e" } 76650- if tokFile.Line(open) == tokFile.Line(start) || 76651- tokFile.Line(close) == tokFile.Line(end) { 76652- return token.NoPos, token.NoPos 76653- } 76654- 76655- return open + 1, end 76656- } 76657- return open + 1, close 76658-} 76659- 76660-// commentsFoldingRange returns the folding ranges for all comment blocks in file. 76661-// The folding range starts at the end of the first line of the comment block, and ends at the end of the 76662-// comment block and has kind protocol.Comment. 76663-func commentsFoldingRange(pgf *ParsedGoFile) (comments []*FoldingRangeInfo) { 76664- tokFile := pgf.Tok 76665- for _, commentGrp := range pgf.File.Comments { 76666- startGrpLine, endGrpLine := tokFile.Line(commentGrp.Pos()), tokFile.Line(commentGrp.End()) 76667- if startGrpLine == endGrpLine { 76668- // Don't fold single line comments. 76669- continue 76670- } 76671- 76672- firstComment := commentGrp.List[0] 76673- startPos, endLinePos := firstComment.Pos(), firstComment.End() 76674- startCmmntLine, endCmmntLine := tokFile.Line(startPos), tokFile.Line(endLinePos) 76675- if startCmmntLine != endCmmntLine { 76676- // If the first comment spans multiple lines, then we want to have the 76677- // folding range start at the end of the first line. 76678- endLinePos = token.Pos(int(startPos) + len(strings.Split(firstComment.Text, "\n")[0])) 76679- } 76680- mrng, err := pgf.PosMappedRange(endLinePos, commentGrp.End()) 76681- if err != nil { 76682- bug.Errorf("%w", err) // can't happen 76683- } 76684- comments = append(comments, &FoldingRangeInfo{ 76685- // Fold from the end of the first line comment to the end of the comment block. 76686- MappedRange: mrng, 76687- Kind: protocol.Comment, 76688- }) 76689- } 76690- return comments 76691-} 76692diff -urN a/gopls/internal/lsp/source/format.go b/gopls/internal/lsp/source/format.go 76693--- a/gopls/internal/lsp/source/format.go 2000-01-01 00:00:00.000000000 -0000 76694+++ b/gopls/internal/lsp/source/format.go 1970-01-01 00:00:00.000000000 +0000 76695@@ -1,391 +0,0 @@ 76696-// Copyright 2018 The Go Authors. All rights reserved. 76697-// Use of this source code is governed by a BSD-style 76698-// license that can be found in the LICENSE file. 76699- 76700-// Package source provides core features for use by Go editors and tools. 76701-package source 76702- 76703-import ( 76704- "bytes" 76705- "context" 76706- "fmt" 76707- "go/ast" 76708- "go/format" 76709- "go/parser" 76710- "go/token" 76711- "strings" 76712- "text/scanner" 76713- 76714- "golang.org/x/tools/gopls/internal/lsp/protocol" 76715- "golang.org/x/tools/gopls/internal/lsp/safetoken" 76716- "golang.org/x/tools/internal/diff" 76717- "golang.org/x/tools/internal/event" 76718- "golang.org/x/tools/internal/imports" 76719-) 76720- 76721-// Format formats a file with a given range. 76722-func Format(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.TextEdit, error) { 76723- ctx, done := event.Start(ctx, "source.Format") 76724- defer done() 76725- 76726- // Generated files shouldn't be edited. So, don't format them 76727- if IsGenerated(ctx, snapshot, fh.URI()) { 76728- return nil, fmt.Errorf("can't format %q: file is generated", fh.URI().Filename()) 76729- } 76730- 76731- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 76732- if err != nil { 76733- return nil, err 76734- } 76735- // Even if this file has parse errors, it might still be possible to format it. 76736- // Using format.Node on an AST with errors may result in code being modified. 76737- // Attempt to format the source of this file instead. 76738- if pgf.ParseErr != nil { 76739- formatted, err := formatSource(ctx, fh) 76740- if err != nil { 76741- return nil, err 76742- } 76743- return computeTextEdits(ctx, snapshot, pgf, string(formatted)) 76744- } 76745- 76746- // format.Node changes slightly from one release to another, so the version 76747- // of Go used to build the LSP server will determine how it formats code. 76748- // This should be acceptable for all users, who likely be prompted to rebuild 76749- // the LSP server on each Go release. 76750- buf := &bytes.Buffer{} 76751- fset := FileSetFor(pgf.Tok) 76752- if err := format.Node(buf, fset, pgf.File); err != nil { 76753- return nil, err 76754- } 76755- formatted := buf.String() 76756- 76757- // Apply additional formatting, if any is supported. Currently, the only 76758- // supported additional formatter is gofumpt. 76759- if format := snapshot.View().Options().GofumptFormat; snapshot.View().Options().Gofumpt && format != nil { 76760- // gofumpt can customize formatting based on language version and module 76761- // path, if available. 76762- // 76763- // Try to derive this information, but fall-back on the default behavior. 76764- // 76765- // TODO: under which circumstances can we fail to find module information? 76766- // Can this, for example, result in inconsistent formatting across saves, 76767- // due to pending calls to packages.Load? 76768- var langVersion, modulePath string 76769- mds, err := snapshot.MetadataForFile(ctx, fh.URI()) 76770- if err == nil && len(mds) > 0 { 76771- if mi := mds[0].Module; mi != nil { 76772- langVersion = mi.GoVersion 76773- modulePath = mi.Path 76774- } 76775- } 76776- b, err := format(ctx, langVersion, modulePath, buf.Bytes()) 76777- if err != nil { 76778- return nil, err 76779- } 76780- formatted = string(b) 76781- } 76782- return computeTextEdits(ctx, snapshot, pgf, formatted) 76783-} 76784- 76785-func formatSource(ctx context.Context, fh FileHandle) ([]byte, error) { 76786- _, done := event.Start(ctx, "source.formatSource") 76787- defer done() 76788- 76789- data, err := fh.Read() 76790- if err != nil { 76791- return nil, err 76792- } 76793- return format.Source(data) 76794-} 76795- 76796-type ImportFix struct { 76797- Fix *imports.ImportFix 76798- Edits []protocol.TextEdit 76799-} 76800- 76801-// AllImportsFixes formats f for each possible fix to the imports. 76802-// In addition to returning the result of applying all edits, 76803-// it returns a list of fixes that could be applied to the file, with the 76804-// corresponding TextEdits that would be needed to apply that fix. 76805-func AllImportsFixes(ctx context.Context, snapshot Snapshot, fh FileHandle) (allFixEdits []protocol.TextEdit, editsPerFix []*ImportFix, err error) { 76806- ctx, done := event.Start(ctx, "source.AllImportsFixes") 76807- defer done() 76808- 76809- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 76810- if err != nil { 76811- return nil, nil, err 76812- } 76813- if err := snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error { 76814- allFixEdits, editsPerFix, err = computeImportEdits(snapshot, pgf, opts) 76815- return err 76816- }); err != nil { 76817- return nil, nil, fmt.Errorf("AllImportsFixes: %v", err) 76818- } 76819- return allFixEdits, editsPerFix, nil 76820-} 76821- 76822-// computeImportEdits computes a set of edits that perform one or all of the 76823-// necessary import fixes. 76824-func computeImportEdits(snapshot Snapshot, pgf *ParsedGoFile, options *imports.Options) (allFixEdits []protocol.TextEdit, editsPerFix []*ImportFix, err error) { 76825- filename := pgf.URI.Filename() 76826- 76827- // Build up basic information about the original file. 76828- allFixes, err := imports.FixImports(filename, pgf.Src, options) 76829- if err != nil { 76830- return nil, nil, err 76831- } 76832- 76833- allFixEdits, err = computeFixEdits(snapshot, pgf, options, allFixes) 76834- if err != nil { 76835- return nil, nil, err 76836- } 76837- 76838- // Apply all of the import fixes to the file. 76839- // Add the edits for each fix to the result. 76840- for _, fix := range allFixes { 76841- edits, err := computeFixEdits(snapshot, pgf, options, []*imports.ImportFix{fix}) 76842- if err != nil { 76843- return nil, nil, err 76844- } 76845- editsPerFix = append(editsPerFix, &ImportFix{ 76846- Fix: fix, 76847- Edits: edits, 76848- }) 76849- } 76850- return allFixEdits, editsPerFix, nil 76851-} 76852- 76853-// ComputeOneImportFixEdits returns text edits for a single import fix. 76854-func ComputeOneImportFixEdits(snapshot Snapshot, pgf *ParsedGoFile, fix *imports.ImportFix) ([]protocol.TextEdit, error) { 76855- options := &imports.Options{ 76856- LocalPrefix: snapshot.View().Options().Local, 76857- // Defaults. 76858- AllErrors: true, 76859- Comments: true, 76860- Fragment: true, 76861- FormatOnly: false, 76862- TabIndent: true, 76863- TabWidth: 8, 76864- } 76865- return computeFixEdits(snapshot, pgf, options, []*imports.ImportFix{fix}) 76866-} 76867- 76868-func computeFixEdits(snapshot Snapshot, pgf *ParsedGoFile, options *imports.Options, fixes []*imports.ImportFix) ([]protocol.TextEdit, error) { 76869- // trim the original data to match fixedData 76870- left, err := importPrefix(pgf.Src) 76871- if err != nil { 76872- return nil, err 76873- } 76874- extra := !strings.Contains(left, "\n") // one line may have more than imports 76875- if extra { 76876- left = string(pgf.Src) 76877- } 76878- if len(left) > 0 && left[len(left)-1] != '\n' { 76879- left += "\n" 76880- } 76881- // Apply the fixes and re-parse the file so that we can locate the 76882- // new imports. 76883- flags := parser.ImportsOnly 76884- if extra { 76885- // used all of origData above, use all of it here too 76886- flags = 0 76887- } 76888- fixedData, err := imports.ApplyFixes(fixes, "", pgf.Src, options, flags) 76889- if err != nil { 76890- return nil, err 76891- } 76892- if fixedData == nil || fixedData[len(fixedData)-1] != '\n' { 76893- fixedData = append(fixedData, '\n') // ApplyFixes may miss the newline, go figure. 76894- } 76895- edits := snapshot.View().Options().ComputeEdits(left, string(fixedData)) 76896- return protocolEditsFromSource([]byte(left), edits) 76897-} 76898- 76899-// importPrefix returns the prefix of the given file content through the final 76900-// import statement. If there are no imports, the prefix is the package 76901-// statement and any comment groups below it. 76902-func importPrefix(src []byte) (string, error) { 76903- fset := token.NewFileSet() 76904- // do as little parsing as possible 76905- f, err := parser.ParseFile(fset, "", src, parser.ImportsOnly|parser.ParseComments) 76906- if err != nil { // This can happen if 'package' is misspelled 76907- return "", fmt.Errorf("importPrefix: failed to parse: %s", err) 76908- } 76909- tok := fset.File(f.Pos()) 76910- var importEnd int 76911- for _, d := range f.Decls { 76912- if x, ok := d.(*ast.GenDecl); ok && x.Tok == token.IMPORT { 76913- if e, err := safetoken.Offset(tok, d.End()); err != nil { 76914- return "", fmt.Errorf("importPrefix: %s", err) 76915- } else if e > importEnd { 76916- importEnd = e 76917- } 76918- } 76919- } 76920- 76921- maybeAdjustToLineEnd := func(pos token.Pos, isCommentNode bool) int { 76922- offset, err := safetoken.Offset(tok, pos) 76923- if err != nil { 76924- return -1 76925- } 76926- 76927- // Don't go past the end of the file. 76928- if offset > len(src) { 76929- offset = len(src) 76930- } 76931- // The go/ast package does not account for different line endings, and 76932- // specifically, in the text of a comment, it will strip out \r\n line 76933- // endings in favor of \n. To account for these differences, we try to 76934- // return a position on the next line whenever possible. 76935- switch line := tok.Line(tok.Pos(offset)); { 76936- case line < tok.LineCount(): 76937- nextLineOffset, err := safetoken.Offset(tok, tok.LineStart(line+1)) 76938- if err != nil { 76939- return -1 76940- } 76941- // If we found a position that is at the end of a line, move the 76942- // offset to the start of the next line. 76943- if offset+1 == nextLineOffset { 76944- offset = nextLineOffset 76945- } 76946- case isCommentNode, offset+1 == tok.Size(): 76947- // If the last line of the file is a comment, or we are at the end 76948- // of the file, the prefix is the entire file. 76949- offset = len(src) 76950- } 76951- return offset 76952- } 76953- if importEnd == 0 { 76954- pkgEnd := f.Name.End() 76955- importEnd = maybeAdjustToLineEnd(pkgEnd, false) 76956- } 76957- for _, cgroup := range f.Comments { 76958- for _, c := range cgroup.List { 76959- if end, err := safetoken.Offset(tok, c.End()); err != nil { 76960- return "", err 76961- } else if end > importEnd { 76962- startLine := safetoken.Position(tok, c.Pos()).Line 76963- endLine := safetoken.Position(tok, c.End()).Line 76964- 76965- // Work around golang/go#41197 by checking if the comment might 76966- // contain "\r", and if so, find the actual end position of the 76967- // comment by scanning the content of the file. 76968- startOffset, err := safetoken.Offset(tok, c.Pos()) 76969- if err != nil { 76970- return "", err 76971- } 76972- if startLine != endLine && bytes.Contains(src[startOffset:], []byte("\r")) { 76973- if commentEnd := scanForCommentEnd(src[startOffset:]); commentEnd > 0 { 76974- end = startOffset + commentEnd 76975- } 76976- } 76977- importEnd = maybeAdjustToLineEnd(tok.Pos(end), true) 76978- } 76979- } 76980- } 76981- if importEnd > len(src) { 76982- importEnd = len(src) 76983- } 76984- return string(src[:importEnd]), nil 76985-} 76986- 76987-// scanForCommentEnd returns the offset of the end of the multi-line comment 76988-// at the start of the given byte slice. 76989-func scanForCommentEnd(src []byte) int { 76990- var s scanner.Scanner 76991- s.Init(bytes.NewReader(src)) 76992- s.Mode ^= scanner.SkipComments 76993- 76994- t := s.Scan() 76995- if t == scanner.Comment { 76996- return s.Pos().Offset 76997- } 76998- return 0 76999-} 77000- 77001-func computeTextEdits(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile, formatted string) ([]protocol.TextEdit, error) { 77002- _, done := event.Start(ctx, "source.computeTextEdits") 77003- defer done() 77004- 77005- edits := snapshot.View().Options().ComputeEdits(string(pgf.Src), formatted) 77006- return ToProtocolEdits(pgf.Mapper, edits) 77007-} 77008- 77009-// protocolEditsFromSource converts text edits to LSP edits using the original 77010-// source. 77011-func protocolEditsFromSource(src []byte, edits []diff.Edit) ([]protocol.TextEdit, error) { 77012- m := protocol.NewMapper("", src) 77013- var result []protocol.TextEdit 77014- for _, edit := range edits { 77015- rng, err := m.OffsetRange(edit.Start, edit.End) 77016- if err != nil { 77017- return nil, err 77018- } 77019- 77020- if rng.Start == rng.End && edit.New == "" { 77021- // Degenerate case, which may result from a diff tool wanting to delete 77022- // '\r' in line endings. Filter it out. 77023- continue 77024- } 77025- result = append(result, protocol.TextEdit{ 77026- Range: rng, 77027- NewText: edit.New, 77028- }) 77029- } 77030- return result, nil 77031-} 77032- 77033-// ToProtocolEdits converts diff.Edits to LSP TextEdits. 77034-// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray 77035-func ToProtocolEdits(m *protocol.Mapper, edits []diff.Edit) ([]protocol.TextEdit, error) { 77036- // LSP doesn't require TextEditArray to be sorted: 77037- // this is the receiver's concern. But govim, and perhaps 77038- // other clients have historically relied on the order. 77039- edits = append([]diff.Edit(nil), edits...) 77040- diff.SortEdits(edits) 77041- 77042- result := make([]protocol.TextEdit, len(edits)) 77043- for i, edit := range edits { 77044- rng, err := m.OffsetRange(edit.Start, edit.End) 77045- if err != nil { 77046- return nil, err 77047- } 77048- result[i] = protocol.TextEdit{ 77049- Range: rng, 77050- NewText: edit.New, 77051- } 77052- } 77053- return result, nil 77054-} 77055- 77056-// FromProtocolEdits converts LSP TextEdits to diff.Edits. 77057-// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray 77058-func FromProtocolEdits(m *protocol.Mapper, edits []protocol.TextEdit) ([]diff.Edit, error) { 77059- if edits == nil { 77060- return nil, nil 77061- } 77062- result := make([]diff.Edit, len(edits)) 77063- for i, edit := range edits { 77064- start, end, err := m.RangeOffsets(edit.Range) 77065- if err != nil { 77066- return nil, err 77067- } 77068- result[i] = diff.Edit{ 77069- Start: start, 77070- End: end, 77071- New: edit.NewText, 77072- } 77073- } 77074- return result, nil 77075-} 77076- 77077-// ApplyProtocolEdits applies the patch (edits) to m.Content and returns the result. 77078-// It also returns the edits converted to diff-package form. 77079-func ApplyProtocolEdits(m *protocol.Mapper, edits []protocol.TextEdit) ([]byte, []diff.Edit, error) { 77080- diffEdits, err := FromProtocolEdits(m, edits) 77081- if err != nil { 77082- return nil, nil, err 77083- } 77084- out, err := diff.ApplyBytes(m.Content, diffEdits) 77085- return out, diffEdits, err 77086-} 77087diff -urN a/gopls/internal/lsp/source/format_test.go b/gopls/internal/lsp/source/format_test.go 77088--- a/gopls/internal/lsp/source/format_test.go 2000-01-01 00:00:00.000000000 -0000 77089+++ b/gopls/internal/lsp/source/format_test.go 1970-01-01 00:00:00.000000000 +0000 77090@@ -1,75 +0,0 @@ 77091-// Copyright 2020 The Go Authors. All rights reserved. 77092-// Use of this source code is governed by a BSD-style 77093-// license that can be found in the LICENSE file. 77094- 77095-package source 77096- 77097-import ( 77098- "strings" 77099- "testing" 77100- 77101- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 77102-) 77103- 77104-func TestImportPrefix(t *testing.T) { 77105- for i, tt := range []struct { 77106- input, want string 77107- }{ 77108- {"package foo", "package foo"}, 77109- {"package foo\n", "package foo\n"}, 77110- {"package foo\n\nfunc f(){}\n", "package foo\n"}, 77111- {"package foo\n\nimport \"fmt\"\n", "package foo\n\nimport \"fmt\""}, 77112- {"package foo\nimport (\n\"fmt\"\n)\n", "package foo\nimport (\n\"fmt\"\n)"}, 77113- {"\n\n\npackage foo\n", "\n\n\npackage foo\n"}, 77114- {"// hi \n\npackage foo //xx\nfunc _(){}\n", "// hi \n\npackage foo //xx\n"}, 77115- {"package foo //hi\n", "package foo //hi\n"}, 77116- {"//hi\npackage foo\n//a\n\n//b\n", "//hi\npackage foo\n//a\n\n//b\n"}, 77117- { 77118- "package a\n\nimport (\n \"fmt\"\n)\n//hi\n", 77119- "package a\n\nimport (\n \"fmt\"\n)\n//hi\n", 77120- }, 77121- {`package a /*hi*/`, `package a /*hi*/`}, 77122- {"package main\r\n\r\nimport \"go/types\"\r\n\r\n/*\r\n\r\n */\r\n", "package main\r\n\r\nimport \"go/types\"\r\n\r\n/*\r\n\r\n */\r\n"}, 77123- {"package x; import \"os\"; func f() {}\n\n", "package x; import \"os\""}, 77124- {"package x; func f() {fmt.Println()}\n\n", "package x"}, 77125- } { 77126- got, err := importPrefix([]byte(tt.input)) 77127- if err != nil { 77128- t.Fatal(err) 77129- } 77130- if d := compare.Text(tt.want, got); d != "" { 77131- t.Errorf("%d: failed for %q:\n%s", i, tt.input, d) 77132- } 77133- } 77134-} 77135- 77136-func TestCRLFFile(t *testing.T) { 77137- for i, tt := range []struct { 77138- input, want string 77139- }{ 77140- { 77141- input: `package main 77142- 77143-/* 77144-Hi description 77145-*/ 77146-func Hi() { 77147-} 77148-`, 77149- want: `package main 77150- 77151-/* 77152-Hi description 77153-*/`, 77154- }, 77155- } { 77156- got, err := importPrefix([]byte(strings.ReplaceAll(tt.input, "\n", "\r\n"))) 77157- if err != nil { 77158- t.Fatal(err) 77159- } 77160- want := strings.ReplaceAll(tt.want, "\n", "\r\n") 77161- if d := compare.Text(want, got); d != "" { 77162- t.Errorf("%d: failed for %q:\n%s", i, tt.input, d) 77163- } 77164- } 77165-} 77166diff -urN a/gopls/internal/lsp/source/gc_annotations.go b/gopls/internal/lsp/source/gc_annotations.go 77167--- a/gopls/internal/lsp/source/gc_annotations.go 2000-01-01 00:00:00.000000000 -0000 77168+++ b/gopls/internal/lsp/source/gc_annotations.go 1970-01-01 00:00:00.000000000 +0000 77169@@ -1,221 +0,0 @@ 77170-// Copyright 2020 The Go Authors. All rights reserved. 77171-// Use of this source code is governed by a BSD-style 77172-// license that can be found in the LICENSE file. 77173- 77174-package source 77175- 77176-import ( 77177- "bytes" 77178- "context" 77179- "encoding/json" 77180- "fmt" 77181- "io/ioutil" 77182- "os" 77183- "path/filepath" 77184- "strings" 77185- 77186- "golang.org/x/tools/gopls/internal/lsp/protocol" 77187- "golang.org/x/tools/gopls/internal/span" 77188- "golang.org/x/tools/internal/gocommand" 77189-) 77190- 77191-type Annotation string 77192- 77193-const ( 77194- // Nil controls nil checks. 77195- Nil Annotation = "nil" 77196- 77197- // Escape controls diagnostics about escape choices. 77198- Escape Annotation = "escape" 77199- 77200- // Inline controls diagnostics about inlining choices. 77201- Inline Annotation = "inline" 77202- 77203- // Bounds controls bounds checking diagnostics. 77204- Bounds Annotation = "bounds" 77205-) 77206- 77207-func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, m *Metadata) (map[span.URI][]*Diagnostic, error) { 77208- if len(m.CompiledGoFiles) == 0 { 77209- return nil, nil 77210- } 77211- pkgDir := filepath.Dir(m.CompiledGoFiles[0].Filename()) 77212- outDir := filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.details", os.Getpid())) 77213- 77214- if err := os.MkdirAll(outDir, 0700); err != nil { 77215- return nil, err 77216- } 77217- tmpFile, err := ioutil.TempFile(os.TempDir(), "gopls-x") 77218- if err != nil { 77219- return nil, err 77220- } 77221- defer os.Remove(tmpFile.Name()) 77222- 77223- outDirURI := span.URIFromPath(outDir) 77224- // GC details doesn't handle Windows URIs in the form of "file:///C:/...", 77225- // so rewrite them to "file://C:/...". See golang/go#41614. 77226- if !strings.HasPrefix(outDir, "/") { 77227- outDirURI = span.URI(strings.Replace(string(outDirURI), "file:///", "file://", 1)) 77228- } 77229- inv := &gocommand.Invocation{ 77230- Verb: "build", 77231- Args: []string{ 77232- fmt.Sprintf("-gcflags=-json=0,%s", outDirURI), 77233- fmt.Sprintf("-o=%s", tmpFile.Name()), 77234- ".", 77235- }, 77236- WorkingDir: pkgDir, 77237- } 77238- _, err = snapshot.RunGoCommandDirect(ctx, Normal, inv) 77239- if err != nil { 77240- return nil, err 77241- } 77242- files, err := findJSONFiles(outDir) 77243- if err != nil { 77244- return nil, err 77245- } 77246- reports := make(map[span.URI][]*Diagnostic) 77247- opts := snapshot.View().Options() 77248- var parseError error 77249- for _, fn := range files { 77250- uri, diagnostics, err := parseDetailsFile(fn, opts) 77251- if err != nil { 77252- // expect errors for all the files, save 1 77253- parseError = err 77254- } 77255- fh := snapshot.FindFile(uri) 77256- if fh == nil { 77257- continue 77258- } 77259- if pkgDir != filepath.Dir(fh.URI().Filename()) { 77260- // https://github.com/golang/go/issues/42198 77261- // sometimes the detail diagnostics generated for files 77262- // outside the package can never be taken back. 77263- continue 77264- } 77265- reports[fh.URI()] = diagnostics 77266- } 77267- return reports, parseError 77268-} 77269- 77270-func parseDetailsFile(filename string, options *Options) (span.URI, []*Diagnostic, error) { 77271- buf, err := ioutil.ReadFile(filename) 77272- if err != nil { 77273- return "", nil, err 77274- } 77275- var ( 77276- uri span.URI 77277- i int 77278- diagnostics []*Diagnostic 77279- ) 77280- type metadata struct { 77281- File string `json:"file,omitempty"` 77282- } 77283- for dec := json.NewDecoder(bytes.NewReader(buf)); dec.More(); { 77284- // The first element always contains metadata. 77285- if i == 0 { 77286- i++ 77287- m := new(metadata) 77288- if err := dec.Decode(m); err != nil { 77289- return "", nil, err 77290- } 77291- if !strings.HasSuffix(m.File, ".go") { 77292- continue // <autogenerated> 77293- } 77294- uri = span.URIFromPath(m.File) 77295- continue 77296- } 77297- d := new(protocol.Diagnostic) 77298- if err := dec.Decode(d); err != nil { 77299- return "", nil, err 77300- } 77301- msg := d.Code.(string) 77302- if msg != "" { 77303- msg = fmt.Sprintf("%s(%s)", msg, d.Message) 77304- } 77305- if !showDiagnostic(msg, d.Source, options) { 77306- continue 77307- } 77308- var related []protocol.DiagnosticRelatedInformation 77309- for _, ri := range d.RelatedInformation { 77310- // TODO(rfindley): The compiler uses LSP-like JSON to encode gc details, 77311- // however the positions it uses are 1-based UTF-8: 77312- // https://github.com/golang/go/blob/master/src/cmd/compile/internal/logopt/log_opts.go 77313- // 77314- // Here, we adjust for 0-based positions, but do not translate UTF-8 to UTF-16. 77315- related = append(related, protocol.DiagnosticRelatedInformation{ 77316- Location: protocol.Location{ 77317- URI: ri.Location.URI, 77318- Range: zeroIndexedRange(ri.Location.Range), 77319- }, 77320- Message: ri.Message, 77321- }) 77322- } 77323- diagnostic := &Diagnostic{ 77324- URI: uri, 77325- Range: zeroIndexedRange(d.Range), 77326- Message: msg, 77327- Severity: d.Severity, 77328- Source: OptimizationDetailsError, // d.Source is always "go compiler" as of 1.16, use our own 77329- Tags: d.Tags, 77330- Related: related, 77331- } 77332- diagnostics = append(diagnostics, diagnostic) 77333- i++ 77334- } 77335- return uri, diagnostics, nil 77336-} 77337- 77338-// showDiagnostic reports whether a given diagnostic should be shown to the end 77339-// user, given the current options. 77340-func showDiagnostic(msg, source string, o *Options) bool { 77341- if source != "go compiler" { 77342- return false 77343- } 77344- if o.Annotations == nil { 77345- return true 77346- } 77347- switch { 77348- case strings.HasPrefix(msg, "canInline") || 77349- strings.HasPrefix(msg, "cannotInline") || 77350- strings.HasPrefix(msg, "inlineCall"): 77351- return o.Annotations[Inline] 77352- case strings.HasPrefix(msg, "escape") || msg == "leak": 77353- return o.Annotations[Escape] 77354- case strings.HasPrefix(msg, "nilcheck"): 77355- return o.Annotations[Nil] 77356- case strings.HasPrefix(msg, "isInBounds") || 77357- strings.HasPrefix(msg, "isSliceInBounds"): 77358- return o.Annotations[Bounds] 77359- } 77360- return false 77361-} 77362- 77363-// The range produced by the compiler is 1-indexed, so subtract range by 1. 77364-func zeroIndexedRange(rng protocol.Range) protocol.Range { 77365- return protocol.Range{ 77366- Start: protocol.Position{ 77367- Line: rng.Start.Line - 1, 77368- Character: rng.Start.Character - 1, 77369- }, 77370- End: protocol.Position{ 77371- Line: rng.End.Line - 1, 77372- Character: rng.End.Character - 1, 77373- }, 77374- } 77375-} 77376- 77377-func findJSONFiles(dir string) ([]string, error) { 77378- ans := []string{} 77379- f := func(path string, fi os.FileInfo, _ error) error { 77380- if fi.IsDir() { 77381- return nil 77382- } 77383- if strings.HasSuffix(path, ".json") { 77384- ans = append(ans, path) 77385- } 77386- return nil 77387- } 77388- err := filepath.Walk(dir, f) 77389- return ans, err 77390-} 77391diff -urN a/gopls/internal/lsp/source/highlight.go b/gopls/internal/lsp/source/highlight.go 77392--- a/gopls/internal/lsp/source/highlight.go 2000-01-01 00:00:00.000000000 -0000 77393+++ b/gopls/internal/lsp/source/highlight.go 1970-01-01 00:00:00.000000000 +0000 77394@@ -1,484 +0,0 @@ 77395-// Copyright 2019 The Go Authors. All rights reserved. 77396-// Use of this source code is governed by a BSD-style 77397-// license that can be found in the LICENSE file. 77398- 77399-package source 77400- 77401-import ( 77402- "context" 77403- "fmt" 77404- "go/ast" 77405- "go/token" 77406- "go/types" 77407- "strings" 77408- 77409- "golang.org/x/tools/go/ast/astutil" 77410- "golang.org/x/tools/gopls/internal/lsp/protocol" 77411- "golang.org/x/tools/internal/event" 77412-) 77413- 77414-func Highlight(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) ([]protocol.Range, error) { 77415- ctx, done := event.Start(ctx, "source.Highlight") 77416- defer done() 77417- 77418- // We always want fully parsed files for highlight, regardless 77419- // of whether the file belongs to a workspace package. 77420- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 77421- if err != nil { 77422- return nil, fmt.Errorf("getting package for Highlight: %w", err) 77423- } 77424- 77425- pos, err := pgf.PositionPos(position) 77426- if err != nil { 77427- return nil, err 77428- } 77429- path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos) 77430- if len(path) == 0 { 77431- return nil, fmt.Errorf("no enclosing position found for %v:%v", position.Line, position.Character) 77432- } 77433- // If start == end for astutil.PathEnclosingInterval, the 1-char interval 77434- // following start is used instead. As a result, we might not get an exact 77435- // match so we should check the 1-char interval to the left of the passed 77436- // in position to see if that is an exact match. 77437- if _, ok := path[0].(*ast.Ident); !ok { 77438- if p, _ := astutil.PathEnclosingInterval(pgf.File, pos-1, pos-1); p != nil { 77439- switch p[0].(type) { 77440- case *ast.Ident, *ast.SelectorExpr: 77441- path = p // use preceding ident/selector 77442- } 77443- } 77444- } 77445- result, err := highlightPath(path, pgf.File, pkg.GetTypesInfo()) 77446- if err != nil { 77447- return nil, err 77448- } 77449- var ranges []protocol.Range 77450- for rng := range result { 77451- rng, err := pgf.PosRange(rng.start, rng.end) 77452- if err != nil { 77453- return nil, err 77454- } 77455- ranges = append(ranges, rng) 77456- } 77457- return ranges, nil 77458-} 77459- 77460-func highlightPath(path []ast.Node, file *ast.File, info *types.Info) (map[posRange]struct{}, error) { 77461- result := make(map[posRange]struct{}) 77462- switch node := path[0].(type) { 77463- case *ast.BasicLit: 77464- if len(path) > 1 { 77465- if _, ok := path[1].(*ast.ImportSpec); ok { 77466- err := highlightImportUses(path, info, result) 77467- return result, err 77468- } 77469- } 77470- highlightFuncControlFlow(path, result) 77471- case *ast.ReturnStmt, *ast.FuncDecl, *ast.FuncType: 77472- highlightFuncControlFlow(path, result) 77473- case *ast.Ident: 77474- // Check if ident is inside return or func decl. 77475- highlightFuncControlFlow(path, result) 77476- highlightIdentifier(node, file, info, result) 77477- case *ast.ForStmt, *ast.RangeStmt: 77478- highlightLoopControlFlow(path, info, result) 77479- case *ast.SwitchStmt: 77480- highlightSwitchFlow(path, info, result) 77481- case *ast.BranchStmt: 77482- // BREAK can exit a loop, switch or select, while CONTINUE exit a loop so 77483- // these need to be handled separately. They can also be embedded in any 77484- // other loop/switch/select if they have a label. TODO: add support for 77485- // GOTO and FALLTHROUGH as well. 77486- switch node.Tok { 77487- case token.BREAK: 77488- if node.Label != nil { 77489- highlightLabeledFlow(path, info, node, result) 77490- } else { 77491- highlightUnlabeledBreakFlow(path, info, result) 77492- } 77493- case token.CONTINUE: 77494- if node.Label != nil { 77495- highlightLabeledFlow(path, info, node, result) 77496- } else { 77497- highlightLoopControlFlow(path, info, result) 77498- } 77499- } 77500- default: 77501- // If the cursor is in an unidentified area, return empty results. 77502- return nil, nil 77503- } 77504- return result, nil 77505-} 77506- 77507-type posRange struct { 77508- start, end token.Pos 77509-} 77510- 77511-func highlightFuncControlFlow(path []ast.Node, result map[posRange]struct{}) { 77512- var enclosingFunc ast.Node 77513- var returnStmt *ast.ReturnStmt 77514- var resultsList *ast.FieldList 77515- inReturnList := false 77516- 77517-Outer: 77518- // Reverse walk the path till we get to the func block. 77519- for i, n := range path { 77520- switch node := n.(type) { 77521- case *ast.KeyValueExpr: 77522- // If cursor is in a key: value expr, we don't want control flow highlighting 77523- return 77524- case *ast.CallExpr: 77525- // If cursor is an arg in a callExpr, we don't want control flow highlighting. 77526- if i > 0 { 77527- for _, arg := range node.Args { 77528- if arg == path[i-1] { 77529- return 77530- } 77531- } 77532- } 77533- case *ast.Field: 77534- inReturnList = true 77535- case *ast.FuncLit: 77536- enclosingFunc = n 77537- resultsList = node.Type.Results 77538- break Outer 77539- case *ast.FuncDecl: 77540- enclosingFunc = n 77541- resultsList = node.Type.Results 77542- break Outer 77543- case *ast.ReturnStmt: 77544- returnStmt = node 77545- // If the cursor is not directly in a *ast.ReturnStmt, then 77546- // we need to know if it is within one of the values that is being returned. 77547- inReturnList = inReturnList || path[0] != returnStmt 77548- } 77549- } 77550- // Cursor is not in a function. 77551- if enclosingFunc == nil { 77552- return 77553- } 77554- // If the cursor is on a "return" or "func" keyword, we should highlight all of the exit 77555- // points of the function, including the "return" and "func" keywords. 77556- highlightAllReturnsAndFunc := path[0] == returnStmt || path[0] == enclosingFunc 77557- switch path[0].(type) { 77558- case *ast.Ident, *ast.BasicLit: 77559- // Cursor is in an identifier and not in a return statement or in the results list. 77560- if returnStmt == nil && !inReturnList { 77561- return 77562- } 77563- case *ast.FuncType: 77564- highlightAllReturnsAndFunc = true 77565- } 77566- // The user's cursor may be within the return statement of a function, 77567- // or within the result section of a function's signature. 77568- // index := -1 77569- var nodes []ast.Node 77570- if returnStmt != nil { 77571- for _, n := range returnStmt.Results { 77572- nodes = append(nodes, n) 77573- } 77574- } else if resultsList != nil { 77575- for _, n := range resultsList.List { 77576- nodes = append(nodes, n) 77577- } 77578- } 77579- _, index := nodeAtPos(nodes, path[0].Pos()) 77580- 77581- // Highlight the correct argument in the function declaration return types. 77582- if resultsList != nil && -1 < index && index < len(resultsList.List) { 77583- rng := posRange{ 77584- start: resultsList.List[index].Pos(), 77585- end: resultsList.List[index].End(), 77586- } 77587- result[rng] = struct{}{} 77588- } 77589- // Add the "func" part of the func declaration. 77590- if highlightAllReturnsAndFunc { 77591- r := posRange{ 77592- start: enclosingFunc.Pos(), 77593- end: enclosingFunc.Pos() + token.Pos(len("func")), 77594- } 77595- result[r] = struct{}{} 77596- } 77597- ast.Inspect(enclosingFunc, func(n ast.Node) bool { 77598- // Don't traverse any other functions. 77599- switch n.(type) { 77600- case *ast.FuncDecl, *ast.FuncLit: 77601- return enclosingFunc == n 77602- } 77603- ret, ok := n.(*ast.ReturnStmt) 77604- if !ok { 77605- return true 77606- } 77607- var toAdd ast.Node 77608- // Add the entire return statement, applies when highlight the word "return" or "func". 77609- if highlightAllReturnsAndFunc { 77610- toAdd = n 77611- } 77612- // Add the relevant field within the entire return statement. 77613- if -1 < index && index < len(ret.Results) { 77614- toAdd = ret.Results[index] 77615- } 77616- if toAdd != nil { 77617- result[posRange{start: toAdd.Pos(), end: toAdd.End()}] = struct{}{} 77618- } 77619- return false 77620- }) 77621-} 77622- 77623-// highlightUnlabeledBreakFlow highlights the innermost enclosing for/range/switch or swlect 77624-func highlightUnlabeledBreakFlow(path []ast.Node, info *types.Info, result map[posRange]struct{}) { 77625- // Reverse walk the path until we find closest loop, select, or switch. 77626- for _, n := range path { 77627- switch n.(type) { 77628- case *ast.ForStmt, *ast.RangeStmt: 77629- highlightLoopControlFlow(path, info, result) 77630- return // only highlight the innermost statement 77631- case *ast.SwitchStmt: 77632- highlightSwitchFlow(path, info, result) 77633- return 77634- case *ast.SelectStmt: 77635- // TODO: add highlight when breaking a select. 77636- return 77637- } 77638- } 77639-} 77640- 77641-// highlightLabeledFlow highlights the enclosing labeled for, range, 77642-// or switch statement denoted by a labeled break or continue stmt. 77643-func highlightLabeledFlow(path []ast.Node, info *types.Info, stmt *ast.BranchStmt, result map[posRange]struct{}) { 77644- use := info.Uses[stmt.Label] 77645- if use == nil { 77646- return 77647- } 77648- for _, n := range path { 77649- if label, ok := n.(*ast.LabeledStmt); ok && info.Defs[label.Label] == use { 77650- switch label.Stmt.(type) { 77651- case *ast.ForStmt, *ast.RangeStmt: 77652- highlightLoopControlFlow([]ast.Node{label.Stmt, label}, info, result) 77653- case *ast.SwitchStmt: 77654- highlightSwitchFlow([]ast.Node{label.Stmt, label}, info, result) 77655- } 77656- return 77657- } 77658- } 77659-} 77660- 77661-func labelFor(path []ast.Node) *ast.Ident { 77662- if len(path) > 1 { 77663- if n, ok := path[1].(*ast.LabeledStmt); ok { 77664- return n.Label 77665- } 77666- } 77667- return nil 77668-} 77669- 77670-func highlightLoopControlFlow(path []ast.Node, info *types.Info, result map[posRange]struct{}) { 77671- var loop ast.Node 77672- var loopLabel *ast.Ident 77673- stmtLabel := labelFor(path) 77674-Outer: 77675- // Reverse walk the path till we get to the for loop. 77676- for i := range path { 77677- switch n := path[i].(type) { 77678- case *ast.ForStmt, *ast.RangeStmt: 77679- loopLabel = labelFor(path[i:]) 77680- 77681- if stmtLabel == nil || loopLabel == stmtLabel { 77682- loop = n 77683- break Outer 77684- } 77685- } 77686- } 77687- if loop == nil { 77688- return 77689- } 77690- 77691- // Add the for statement. 77692- rng := posRange{ 77693- start: loop.Pos(), 77694- end: loop.Pos() + token.Pos(len("for")), 77695- } 77696- result[rng] = struct{}{} 77697- 77698- // Traverse AST to find branch statements within the same for-loop. 77699- ast.Inspect(loop, func(n ast.Node) bool { 77700- switch n.(type) { 77701- case *ast.ForStmt, *ast.RangeStmt: 77702- return loop == n 77703- case *ast.SwitchStmt, *ast.SelectStmt: 77704- return false 77705- } 77706- b, ok := n.(*ast.BranchStmt) 77707- if !ok { 77708- return true 77709- } 77710- if b.Label == nil || info.Uses[b.Label] == info.Defs[loopLabel] { 77711- result[posRange{start: b.Pos(), end: b.End()}] = struct{}{} 77712- } 77713- return true 77714- }) 77715- 77716- // Find continue statements in the same loop or switches/selects. 77717- ast.Inspect(loop, func(n ast.Node) bool { 77718- switch n.(type) { 77719- case *ast.ForStmt, *ast.RangeStmt: 77720- return loop == n 77721- } 77722- 77723- if n, ok := n.(*ast.BranchStmt); ok && n.Tok == token.CONTINUE { 77724- result[posRange{start: n.Pos(), end: n.End()}] = struct{}{} 77725- } 77726- return true 77727- }) 77728- 77729- // We don't need to check other for loops if we aren't looking for labeled statements. 77730- if loopLabel == nil { 77731- return 77732- } 77733- 77734- // Find labeled branch statements in any loop. 77735- ast.Inspect(loop, func(n ast.Node) bool { 77736- b, ok := n.(*ast.BranchStmt) 77737- if !ok { 77738- return true 77739- } 77740- // statement with labels that matches the loop 77741- if b.Label != nil && info.Uses[b.Label] == info.Defs[loopLabel] { 77742- result[posRange{start: b.Pos(), end: b.End()}] = struct{}{} 77743- } 77744- return true 77745- }) 77746-} 77747- 77748-func highlightSwitchFlow(path []ast.Node, info *types.Info, result map[posRange]struct{}) { 77749- var switchNode ast.Node 77750- var switchNodeLabel *ast.Ident 77751- stmtLabel := labelFor(path) 77752-Outer: 77753- // Reverse walk the path till we get to the switch statement. 77754- for i := range path { 77755- switch n := path[i].(type) { 77756- case *ast.SwitchStmt: 77757- switchNodeLabel = labelFor(path[i:]) 77758- if stmtLabel == nil || switchNodeLabel == stmtLabel { 77759- switchNode = n 77760- break Outer 77761- } 77762- } 77763- } 77764- // Cursor is not in a switch statement 77765- if switchNode == nil { 77766- return 77767- } 77768- 77769- // Add the switch statement. 77770- rng := posRange{ 77771- start: switchNode.Pos(), 77772- end: switchNode.Pos() + token.Pos(len("switch")), 77773- } 77774- result[rng] = struct{}{} 77775- 77776- // Traverse AST to find break statements within the same switch. 77777- ast.Inspect(switchNode, func(n ast.Node) bool { 77778- switch n.(type) { 77779- case *ast.SwitchStmt: 77780- return switchNode == n 77781- case *ast.ForStmt, *ast.RangeStmt, *ast.SelectStmt: 77782- return false 77783- } 77784- 77785- b, ok := n.(*ast.BranchStmt) 77786- if !ok || b.Tok != token.BREAK { 77787- return true 77788- } 77789- 77790- if b.Label == nil || info.Uses[b.Label] == info.Defs[switchNodeLabel] { 77791- result[posRange{start: b.Pos(), end: b.End()}] = struct{}{} 77792- } 77793- return true 77794- }) 77795- 77796- // We don't need to check other switches if we aren't looking for labeled statements. 77797- if switchNodeLabel == nil { 77798- return 77799- } 77800- 77801- // Find labeled break statements in any switch 77802- ast.Inspect(switchNode, func(n ast.Node) bool { 77803- b, ok := n.(*ast.BranchStmt) 77804- if !ok || b.Tok != token.BREAK { 77805- return true 77806- } 77807- 77808- if b.Label != nil && info.Uses[b.Label] == info.Defs[switchNodeLabel] { 77809- result[posRange{start: b.Pos(), end: b.End()}] = struct{}{} 77810- } 77811- 77812- return true 77813- }) 77814-} 77815- 77816-func highlightImportUses(path []ast.Node, info *types.Info, result map[posRange]struct{}) error { 77817- basicLit, ok := path[0].(*ast.BasicLit) 77818- if !ok { 77819- return fmt.Errorf("highlightImportUses called with an ast.Node of type %T", basicLit) 77820- } 77821- ast.Inspect(path[len(path)-1], func(node ast.Node) bool { 77822- if imp, ok := node.(*ast.ImportSpec); ok && imp.Path == basicLit { 77823- result[posRange{start: node.Pos(), end: node.End()}] = struct{}{} 77824- return false 77825- } 77826- n, ok := node.(*ast.Ident) 77827- if !ok { 77828- return true 77829- } 77830- obj, ok := info.ObjectOf(n).(*types.PkgName) 77831- if !ok { 77832- return true 77833- } 77834- if !strings.Contains(basicLit.Value, obj.Name()) { 77835- return true 77836- } 77837- result[posRange{start: n.Pos(), end: n.End()}] = struct{}{} 77838- return false 77839- }) 77840- return nil 77841-} 77842- 77843-func highlightIdentifier(id *ast.Ident, file *ast.File, info *types.Info, result map[posRange]struct{}) { 77844- // TODO(rfindley): idObj may be nil. Note that returning early in this case 77845- // causes tests to fail (because the nObj == idObj check below was succeeded 77846- // for nil == nil!) 77847- // 77848- // Revisit this. If ObjectOf is nil, there are type errors, and it seems 77849- // reasonable for identifier highlighting not to work. 77850- idObj := info.ObjectOf(id) 77851- pkgObj, isImported := idObj.(*types.PkgName) 77852- ast.Inspect(file, func(node ast.Node) bool { 77853- if imp, ok := node.(*ast.ImportSpec); ok && isImported { 77854- highlightImport(pkgObj, imp, result) 77855- } 77856- n, ok := node.(*ast.Ident) 77857- if !ok { 77858- return true 77859- } 77860- if n.Name != id.Name { 77861- return false 77862- } 77863- if nObj := info.ObjectOf(n); nObj == idObj { 77864- result[posRange{start: n.Pos(), end: n.End()}] = struct{}{} 77865- } 77866- return false 77867- }) 77868-} 77869- 77870-func highlightImport(obj *types.PkgName, imp *ast.ImportSpec, result map[posRange]struct{}) { 77871- if imp.Name != nil || imp.Path == nil { 77872- return 77873- } 77874- if !strings.Contains(imp.Path.Value, obj.Name()) { 77875- return 77876- } 77877- result[posRange{start: imp.Path.Pos(), end: imp.Path.End()}] = struct{}{} 77878-} 77879diff -urN a/gopls/internal/lsp/source/hover.go b/gopls/internal/lsp/source/hover.go 77880--- a/gopls/internal/lsp/source/hover.go 2000-01-01 00:00:00.000000000 -0000 77881+++ b/gopls/internal/lsp/source/hover.go 1970-01-01 00:00:00.000000000 +0000 77882@@ -1,951 +0,0 @@ 77883-// Copyright 2019 The Go Authors. All rights reserved. 77884-// Use of this source code is governed by a BSD-style 77885-// license that can be found in the LICENSE file. 77886- 77887-package source 77888- 77889-import ( 77890- "context" 77891- "encoding/json" 77892- "fmt" 77893- "go/ast" 77894- "go/constant" 77895- "go/doc" 77896- "go/format" 77897- "go/token" 77898- "go/types" 77899- "strconv" 77900- "strings" 77901- "time" 77902- "unicode/utf8" 77903- 77904- "golang.org/x/text/unicode/runenames" 77905- "golang.org/x/tools/go/ast/astutil" 77906- "golang.org/x/tools/go/types/typeutil" 77907- "golang.org/x/tools/gopls/internal/lsp/protocol" 77908- "golang.org/x/tools/gopls/internal/lsp/safetoken" 77909- "golang.org/x/tools/gopls/internal/span" 77910- "golang.org/x/tools/internal/bug" 77911- "golang.org/x/tools/internal/event" 77912- "golang.org/x/tools/internal/typeparams" 77913-) 77914- 77915-// HoverJSON contains information used by hover. It is also the JSON returned 77916-// for the "structured" hover format 77917-type HoverJSON struct { 77918- // Synopsis is a single sentence synopsis of the symbol's documentation. 77919- Synopsis string `json:"synopsis"` 77920- 77921- // FullDocumentation is the symbol's full documentation. 77922- FullDocumentation string `json:"fullDocumentation"` 77923- 77924- // Signature is the symbol's signature. 77925- Signature string `json:"signature"` 77926- 77927- // SingleLine is a single line describing the symbol. 77928- // This is recommended only for use in clients that show a single line for hover. 77929- SingleLine string `json:"singleLine"` 77930- 77931- // SymbolName is the human-readable name to use for the symbol in links. 77932- SymbolName string `json:"symbolName"` 77933- 77934- // LinkPath is the pkg.go.dev link for the given symbol. 77935- // For example, the "go/ast" part of "pkg.go.dev/go/ast#Node". 77936- LinkPath string `json:"linkPath"` 77937- 77938- // LinkAnchor is the pkg.go.dev link anchor for the given symbol. 77939- // For example, the "Node" part of "pkg.go.dev/go/ast#Node". 77940- LinkAnchor string `json:"linkAnchor"` 77941-} 77942- 77943-// Hover implements the "textDocument/hover" RPC for Go files. 77944-func Hover(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.Hover, error) { 77945- ctx, done := event.Start(ctx, "source.Hover") 77946- defer done() 77947- 77948- rng, h, err := hover(ctx, snapshot, fh, position) 77949- if err != nil { 77950- return nil, err 77951- } 77952- if h == nil { 77953- return nil, nil 77954- } 77955- hover, err := formatHover(h, snapshot.View().Options()) 77956- if err != nil { 77957- return nil, err 77958- } 77959- return &protocol.Hover{ 77960- Contents: protocol.MarkupContent{ 77961- Kind: snapshot.View().Options().PreferredContentFormat, 77962- Value: hover, 77963- }, 77964- Range: rng, 77965- }, nil 77966-} 77967- 77968-// hover computes hover information at the given position. If we do not support 77969-// hovering at the position, it returns _, nil, nil: an error is only returned 77970-// if the position is valid but we fail to compute hover information. 77971-func hover(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) (protocol.Range, *HoverJSON, error) { 77972- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 77973- if err != nil { 77974- return protocol.Range{}, nil, err 77975- } 77976- pos, err := pgf.PositionPos(pp) 77977- if err != nil { 77978- return protocol.Range{}, nil, err 77979- } 77980- 77981- // Handle hovering over import paths, which do not have an associated 77982- // identifier. 77983- for _, spec := range pgf.File.Imports { 77984- // We are inclusive of the end point here to allow hovering when the cursor 77985- // is just after the import path. 77986- if spec.Path.Pos() <= pos && pos <= spec.Path.End() { 77987- return hoverImport(ctx, snapshot, pkg, pgf, spec) 77988- } 77989- } 77990- 77991- // Handle hovering over the package name, which does not have an associated 77992- // object. 77993- // As with import paths, we allow hovering just after the package name. 77994- if pgf.File.Name != nil && pgf.File.Name.Pos() <= pos && pos <= pgf.File.Name.Pos() { 77995- return hoverPackageName(pkg, pgf) 77996- } 77997- 77998- // Handle hovering over (non-import-path) literals. 77999- if path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos); len(path) > 0 { 78000- if lit, _ := path[0].(*ast.BasicLit); lit != nil { 78001- return hoverLit(pgf, lit, pos) 78002- } 78003- } 78004- 78005- // The general case: compute hover information for the object referenced by 78006- // the identifier at pos. 78007- ident, obj, selectedType := referencedObject(pkg, pgf, pos) 78008- if obj == nil || ident == nil { 78009- return protocol.Range{}, nil, nil // no object to hover 78010- } 78011- 78012- rng, err := pgf.NodeRange(ident) 78013- if err != nil { 78014- return protocol.Range{}, nil, err 78015- } 78016- 78017- // By convention, we qualify hover information relative to the package 78018- // from which the request originated. 78019- qf := Qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo()) 78020- 78021- // Handle type switch identifiers as a special case, since they don't have an 78022- // object. 78023- // 78024- // There's not much useful information to provide. 78025- if selectedType != nil { 78026- fakeObj := types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), selectedType) 78027- signature := objectString(fakeObj, qf, nil) 78028- return rng, &HoverJSON{ 78029- Signature: signature, 78030- SingleLine: signature, 78031- SymbolName: fakeObj.Name(), 78032- }, nil 78033- } 78034- 78035- // Handle builtins, which don't have a package or position. 78036- if obj.Pkg() == nil { 78037- h, err := hoverBuiltin(ctx, snapshot, obj) 78038- return rng, h, err 78039- } 78040- 78041- // For all other objects, consider the full syntax of their declaration in 78042- // order to correctly compute their documentation, signature, and link. 78043- declPGF, declPos, err := parseFull(ctx, snapshot, pkg.FileSet(), obj.Pos()) 78044- if err != nil { 78045- return protocol.Range{}, nil, fmt.Errorf("re-parsing declaration of %s: %v", obj.Name(), err) 78046- } 78047- decl, spec, field := findDeclInfo([]*ast.File{declPGF.File}, declPos) 78048- comment := chooseDocComment(decl, spec, field) 78049- docText := comment.Text() 78050- 78051- // By default, types.ObjectString provides a reasonable signature. 78052- signature := objectString(obj, qf, nil) 78053- // TODO(rfindley): we could do much better for inferred signatures. 78054- if inferred := inferredSignature(pkg.GetTypesInfo(), ident); inferred != nil { 78055- signature = objectString(obj, qf, inferred) 78056- } 78057- 78058- // For "objects defined by a type spec", the signature produced by 78059- // objectString is insufficient: 78060- // (1) large structs are formatted poorly, with no newlines 78061- // (2) we lose inline comments 78062- // 78063- // Furthermore, we include a summary of their method set. 78064- // 78065- // TODO(rfindley): this should use FormatVarType to get proper qualification 78066- // of identifiers, and we should revisit the formatting of method set. 78067- _, isTypeName := obj.(*types.TypeName) 78068- _, isTypeParam := obj.Type().(*typeparams.TypeParam) 78069- if isTypeName && !isTypeParam { 78070- spec, ok := spec.(*ast.TypeSpec) 78071- if !ok { 78072- return protocol.Range{}, nil, bug.Errorf("type name %q without type spec", obj.Name()) 78073- } 78074- spec2 := *spec 78075- // Don't duplicate comments when formatting type specs. 78076- spec2.Doc = nil 78077- spec2.Comment = nil 78078- var b strings.Builder 78079- b.WriteString("type ") 78080- fset := FileSetFor(declPGF.Tok) 78081- if err := format.Node(&b, fset, &spec2); err != nil { 78082- return protocol.Range{}, nil, err 78083- } 78084- 78085- // Display the declared methods accessible from the identifier. 78086- // 78087- // (The format.Node call above displays any struct fields, public 78088- // or private, in syntactic form. We choose not to recursively 78089- // enumerate any fields and methods promoted from them.) 78090- if !types.IsInterface(obj.Type()) { 78091- sep := "\n\n" 78092- for _, m := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { 78093- // Show direct methods that are either exported, or defined in the 78094- // current package. 78095- if (m.Obj().Exported() || m.Obj().Pkg() == pkg.GetTypes()) && len(m.Index()) == 1 { 78096- b.WriteString(sep) 78097- sep = "\n" 78098- b.WriteString(objectString(m.Obj(), qf, nil)) 78099- } 78100- } 78101- } 78102- signature = b.String() 78103- } 78104- 78105- // Compute link data (on pkg.go.dev or other documentation host). 78106- // 78107- // If linkPath is empty, the symbol is not linkable. 78108- var ( 78109- linkName string // => link title, always non-empty 78110- linkPath string // => link path 78111- anchor string // link anchor 78112- linkMeta *Metadata // metadata for the linked package 78113- ) 78114- { 78115- linkMeta = findFileInDeps(snapshot, pkg.Metadata(), declPGF.URI) 78116- if linkMeta == nil { 78117- return protocol.Range{}, nil, bug.Errorf("no metadata for %s", declPGF.URI) 78118- } 78119- 78120- // For package names, we simply link to their imported package. 78121- if pkgName, ok := obj.(*types.PkgName); ok { 78122- linkName = pkgName.Name() 78123- linkPath = pkgName.Imported().Path() 78124- impID := linkMeta.DepsByPkgPath[PackagePath(pkgName.Imported().Path())] 78125- linkMeta = snapshot.Metadata(impID) 78126- if linkMeta == nil { 78127- return protocol.Range{}, nil, bug.Errorf("no metadata for %s", declPGF.URI) 78128- } 78129- } else { 78130- // For all others, check whether the object is in the package scope, or 78131- // an exported field or method of an object in the package scope. 78132- // 78133- // We try to match pkgsite's heuristics for what is linkable, and what is 78134- // not. 78135- var recv types.Object 78136- switch obj := obj.(type) { 78137- case *types.Func: 78138- sig := obj.Type().(*types.Signature) 78139- if sig.Recv() != nil { 78140- tname := typeToObject(sig.Recv().Type()) 78141- if tname != nil { // beware typed nil 78142- recv = tname 78143- } 78144- } 78145- case *types.Var: 78146- if obj.IsField() { 78147- if spec, ok := spec.(*ast.TypeSpec); ok { 78148- typeName := spec.Name 78149- scopeObj, _ := obj.Pkg().Scope().Lookup(typeName.Name).(*types.TypeName) 78150- if scopeObj != nil { 78151- if st, _ := scopeObj.Type().Underlying().(*types.Struct); st != nil { 78152- for i := 0; i < st.NumFields(); i++ { 78153- if obj == st.Field(i) { 78154- recv = scopeObj 78155- } 78156- } 78157- } 78158- } 78159- } 78160- } 78161- } 78162- 78163- // Even if the object is not available in package documentation, it may 78164- // be embedded in a documented receiver. Detect this by searching 78165- // enclosing selector expressions. 78166- // 78167- // TODO(rfindley): pkgsite doesn't document fields from embedding, just 78168- // methods. 78169- if recv == nil || !recv.Exported() { 78170- path := pathEnclosingObjNode(pgf.File, pos) 78171- if enclosing := searchForEnclosing(pkg.GetTypesInfo(), path); enclosing != nil { 78172- recv = enclosing 78173- } else { 78174- recv = nil // note: just recv = ... could result in a typed nil. 78175- } 78176- } 78177- 78178- pkg := obj.Pkg() 78179- if recv != nil { 78180- linkName = fmt.Sprintf("(%s.%s).%s", pkg.Name(), recv.Name(), obj.Name()) 78181- if obj.Exported() && recv.Exported() && pkg.Scope().Lookup(recv.Name()) == recv { 78182- linkPath = pkg.Path() 78183- anchor = fmt.Sprintf("%s.%s", recv.Name(), obj.Name()) 78184- } 78185- } else { 78186- linkName = fmt.Sprintf("%s.%s", pkg.Name(), obj.Name()) 78187- if obj.Exported() && pkg.Scope().Lookup(obj.Name()) == obj { 78188- linkPath = pkg.Path() 78189- anchor = obj.Name() 78190- } 78191- } 78192- } 78193- } 78194- 78195- if snapshot.View().IsGoPrivatePath(linkPath) || linkMeta.ForTest != "" { 78196- linkPath = "" 78197- } else if linkMeta.Module != nil && linkMeta.Module.Version != "" { 78198- mod := linkMeta.Module 78199- linkPath = strings.Replace(linkPath, mod.Path, mod.Path+"@"+mod.Version, 1) 78200- } 78201- 78202- return rng, &HoverJSON{ 78203- Synopsis: doc.Synopsis(docText), 78204- FullDocumentation: docText, 78205- SingleLine: objectString(obj, qf, nil), 78206- SymbolName: linkName, 78207- Signature: signature, 78208- LinkPath: linkPath, 78209- LinkAnchor: anchor, 78210- }, nil 78211-} 78212- 78213-// hoverBuiltin computes hover information when hovering over a builtin 78214-// identifier. 78215-func hoverBuiltin(ctx context.Context, snapshot Snapshot, obj types.Object) (*HoverJSON, error) { 78216- // TODO(rfindley): link to the correct version of Go documentation. 78217- builtin, err := snapshot.BuiltinFile(ctx) 78218- if err != nil { 78219- return nil, err 78220- } 78221- 78222- // TODO(rfindley): add a test for jump to definition of error.Error (which is 78223- // probably failing, considering it lacks special handling). 78224- if obj.Name() == "Error" { 78225- signature := obj.String() 78226- return &HoverJSON{ 78227- Signature: signature, 78228- SingleLine: signature, 78229- // TODO(rfindley): these are better than the current behavior. 78230- // SymbolName: "(error).Error", 78231- // LinkPath: "builtin", 78232- // LinkAnchor: "error.Error", 78233- }, nil 78234- } 78235- 78236- builtinObj := builtin.File.Scope.Lookup(obj.Name()) 78237- if builtinObj == nil { 78238- // All builtins should have a declaration in the builtin file. 78239- return nil, bug.Errorf("no builtin object for %s", obj.Name()) 78240- } 78241- node, _ := builtinObj.Decl.(ast.Node) 78242- if node == nil { 78243- return nil, bug.Errorf("no declaration for %s", obj.Name()) 78244- } 78245- 78246- var comment *ast.CommentGroup 78247- path, _ := astutil.PathEnclosingInterval(builtin.File, node.Pos(), node.End()) 78248- for _, n := range path { 78249- switch n := n.(type) { 78250- case *ast.GenDecl: 78251- // Separate documentation and signature. 78252- comment = n.Doc 78253- node2 := *n 78254- node2.Doc = nil 78255- node = &node2 78256- case *ast.FuncDecl: 78257- // Ditto. 78258- comment = n.Doc 78259- node2 := *n 78260- node2.Doc = nil 78261- node = &node2 78262- } 78263- } 78264- 78265- signature := FormatNodeFile(builtin.Tok, node) 78266- // Replace fake types with their common equivalent. 78267- // TODO(rfindley): we should instead use obj.Type(), which would have the 78268- // *actual* types of the builtin call. 78269- signature = replacer.Replace(signature) 78270- 78271- docText := comment.Text() 78272- return &HoverJSON{ 78273- Synopsis: doc.Synopsis(docText), 78274- FullDocumentation: docText, 78275- Signature: signature, 78276- SingleLine: obj.String(), 78277- SymbolName: obj.Name(), 78278- LinkPath: "builtin", 78279- LinkAnchor: obj.Name(), 78280- }, nil 78281-} 78282- 78283-// hoverImport computes hover information when hovering over the import path of 78284-// imp in the file pgf of pkg. 78285-// 78286-// If we do not have metadata for the hovered import, it returns _ 78287-func hoverImport(ctx context.Context, snapshot Snapshot, pkg Package, pgf *ParsedGoFile, imp *ast.ImportSpec) (protocol.Range, *HoverJSON, error) { 78288- rng, err := pgf.NodeRange(imp.Path) 78289- if err != nil { 78290- return protocol.Range{}, nil, err 78291- } 78292- 78293- importPath := UnquoteImportPath(imp) 78294- if importPath == "" { 78295- return protocol.Range{}, nil, fmt.Errorf("invalid import path") 78296- } 78297- impID := pkg.Metadata().DepsByImpPath[importPath] 78298- if impID == "" { 78299- return protocol.Range{}, nil, fmt.Errorf("no package data for import %q", importPath) 78300- } 78301- impMetadata := snapshot.Metadata(impID) 78302- if impMetadata == nil { 78303- return protocol.Range{}, nil, bug.Errorf("failed to resolve import ID %q", impID) 78304- } 78305- 78306- // Find the first file with a package doc comment. 78307- var comment *ast.CommentGroup 78308- for _, f := range impMetadata.CompiledGoFiles { 78309- fh, err := snapshot.GetFile(ctx, f) 78310- if err != nil { 78311- if ctx.Err() != nil { 78312- return protocol.Range{}, nil, ctx.Err() 78313- } 78314- continue 78315- } 78316- pgf, err := snapshot.ParseGo(ctx, fh, ParseHeader) 78317- if err != nil { 78318- if ctx.Err() != nil { 78319- return protocol.Range{}, nil, ctx.Err() 78320- } 78321- continue 78322- } 78323- if pgf.File.Doc != nil { 78324- comment = pgf.File.Doc 78325- break 78326- } 78327- } 78328- 78329- docText := comment.Text() 78330- return rng, &HoverJSON{ 78331- Synopsis: doc.Synopsis(docText), 78332- FullDocumentation: docText, 78333- }, nil 78334-} 78335- 78336-// hoverPackageName computes hover information for the package name of the file 78337-// pgf in pkg. 78338-func hoverPackageName(pkg Package, pgf *ParsedGoFile) (protocol.Range, *HoverJSON, error) { 78339- var comment *ast.CommentGroup 78340- for _, pgf := range pkg.CompiledGoFiles() { 78341- if pgf.File.Doc != nil { 78342- comment = pgf.File.Doc 78343- break 78344- } 78345- } 78346- rng, err := pgf.NodeRange(pgf.File.Name) 78347- if err != nil { 78348- return protocol.Range{}, nil, err 78349- } 78350- docText := comment.Text() 78351- return rng, &HoverJSON{ 78352- Synopsis: doc.Synopsis(docText), 78353- FullDocumentation: docText, 78354- // Note: including a signature is redundant, since the cursor is already on the 78355- // package name. 78356- }, nil 78357-} 78358- 78359-// hoverLit computes hover information when hovering over the basic literal lit 78360-// in the file pgf. The provided pos must be the exact position of the cursor, 78361-// as it is used to extract the hovered rune in strings. 78362-// 78363-// For example, hovering over "\u2211" in "foo \u2211 bar" yields: 78364-// 78365-// '∑', U+2211, N-ARY SUMMATION 78366-func hoverLit(pgf *ParsedGoFile, lit *ast.BasicLit, pos token.Pos) (protocol.Range, *HoverJSON, error) { 78367- var r rune 78368- var start, end token.Pos 78369- // Extract a rune from the current position. 78370- // 'Ω', "...Ω...", or 0x03A9 => 'Ω', U+03A9, GREEK CAPITAL LETTER OMEGA 78371- switch lit.Kind { 78372- case token.CHAR: 78373- s, err := strconv.Unquote(lit.Value) 78374- if err != nil { 78375- // If the conversion fails, it's because of an invalid syntax, therefore 78376- // there is no rune to be found. 78377- return protocol.Range{}, nil, nil 78378- } 78379- r, _ = utf8.DecodeRuneInString(s) 78380- if r == utf8.RuneError { 78381- return protocol.Range{}, nil, fmt.Errorf("rune error") 78382- } 78383- start, end = lit.Pos(), lit.End() 78384- case token.INT: 78385- // TODO(rfindley): add support for hex/octal/binary->int conversion here. 78386- 78387- // It's an integer, scan only if it is a hex literal whose bitsize in 78388- // ranging from 8 to 32. 78389- if !(strings.HasPrefix(lit.Value, "0x") && len(lit.Value[2:]) >= 2 && len(lit.Value[2:]) <= 8) { 78390- return protocol.Range{}, nil, nil 78391- } 78392- v, err := strconv.ParseUint(lit.Value[2:], 16, 32) 78393- if err != nil { 78394- return protocol.Range{}, nil, fmt.Errorf("parsing int: %v", err) 78395- } 78396- r = rune(v) 78397- if r == utf8.RuneError { 78398- return protocol.Range{}, nil, fmt.Errorf("rune error") 78399- } 78400- start, end = lit.Pos(), lit.End() 78401- case token.STRING: 78402- // It's a string, scan only if it contains a unicode escape sequence under or before the 78403- // current cursor position. 78404- litOffset, err := safetoken.Offset(pgf.Tok, lit.Pos()) 78405- if err != nil { 78406- return protocol.Range{}, nil, err 78407- } 78408- offset, err := safetoken.Offset(pgf.Tok, pos) 78409- if err != nil { 78410- return protocol.Range{}, nil, err 78411- } 78412- for i := offset - litOffset; i > 0; i-- { 78413- // Start at the cursor position and search backward for the beginning of a rune escape sequence. 78414- rr, _ := utf8.DecodeRuneInString(lit.Value[i:]) 78415- if rr == utf8.RuneError { 78416- return protocol.Range{}, nil, fmt.Errorf("rune error") 78417- } 78418- if rr == '\\' { 78419- // Got the beginning, decode it. 78420- var tail string 78421- r, _, tail, err = strconv.UnquoteChar(lit.Value[i:], '"') 78422- if err != nil { 78423- // If the conversion fails, it's because of an invalid syntax, 78424- // therefore is no rune to be found. 78425- return protocol.Range{}, nil, nil 78426- } 78427- // Only the rune escape sequence part of the string has to be highlighted, recompute the range. 78428- runeLen := len(lit.Value) - (int(i) + len(tail)) 78429- start = token.Pos(int(lit.Pos()) + int(i)) 78430- end = token.Pos(int(start) + runeLen) 78431- break 78432- } 78433- } 78434- } 78435- if r == 0 { 78436- return protocol.Range{}, nil, nil 78437- } 78438- rng, err := pgf.PosRange(start, end) 78439- if err != nil { 78440- return protocol.Range{}, nil, err 78441- } 78442- 78443- var desc string 78444- runeName := runenames.Name(r) 78445- if len(runeName) > 0 && runeName[0] == '<' { 78446- // Check if the rune looks like an HTML tag. If so, trim the surrounding <> 78447- // characters to work around https://github.com/microsoft/vscode/issues/124042. 78448- runeName = strings.TrimRight(runeName[1:], ">") 78449- } 78450- if strconv.IsPrint(r) { 78451- desc = fmt.Sprintf("'%s', U+%04X, %s", string(r), uint32(r), runeName) 78452- } else { 78453- desc = fmt.Sprintf("U+%04X, %s", uint32(r), runeName) 78454- } 78455- return rng, &HoverJSON{ 78456- Synopsis: desc, 78457- FullDocumentation: desc, 78458- }, nil 78459-} 78460- 78461-// objectString is a wrapper around the types.ObjectString function. 78462-// It handles adding more information to the object string. 78463-// 78464-// TODO(rfindley): this function does too much. We should lift the special 78465-// handling to callsites. 78466-func objectString(obj types.Object, qf types.Qualifier, inferred *types.Signature) string { 78467- // If the signature type was inferred, prefer the inferred signature with a 78468- // comment showing the generic signature. 78469- if sig, _ := obj.Type().(*types.Signature); sig != nil && typeparams.ForSignature(sig).Len() > 0 && inferred != nil { 78470- obj2 := types.NewFunc(obj.Pos(), obj.Pkg(), obj.Name(), inferred) 78471- str := types.ObjectString(obj2, qf) 78472- // Try to avoid overly long lines. 78473- if len(str) > 60 { 78474- str += "\n" 78475- } else { 78476- str += " " 78477- } 78478- str += "// " + types.TypeString(sig, qf) 78479- return str 78480- } 78481- str := types.ObjectString(obj, qf) 78482- switch obj := obj.(type) { 78483- case *types.Const: 78484- str = fmt.Sprintf("%s = %s", str, obj.Val()) 78485- 78486- // Try to add a formatted duration as an inline comment 78487- typ, ok := obj.Type().(*types.Named) 78488- if !ok { 78489- break 78490- } 78491- pkg := typ.Obj().Pkg() 78492- if pkg.Path() == "time" && typ.Obj().Name() == "Duration" { 78493- if d, ok := constant.Int64Val(obj.Val()); ok { 78494- str += " // " + time.Duration(d).String() 78495- } 78496- } 78497- } 78498- return str 78499-} 78500- 78501-// HoverDocForObject returns the best doc comment for obj (for which 78502-// fset provides file/line information). 78503-// 78504-// TODO(rfindley): there appears to be zero(!) tests for this functionality. 78505-func HoverDocForObject(ctx context.Context, snapshot Snapshot, fset *token.FileSet, obj types.Object) (*ast.CommentGroup, error) { 78506- if _, isTypeName := obj.(*types.TypeName); isTypeName { 78507- if _, isTypeParam := obj.Type().(*typeparams.TypeParam); isTypeParam { 78508- return nil, nil 78509- } 78510- } 78511- 78512- pgf, pos, err := parseFull(ctx, snapshot, fset, obj.Pos()) 78513- if err != nil { 78514- return nil, fmt.Errorf("re-parsing: %v", err) 78515- } 78516- 78517- decl, spec, field := findDeclInfo([]*ast.File{pgf.File}, pos) 78518- return chooseDocComment(decl, spec, field), nil 78519-} 78520- 78521-func chooseDocComment(decl ast.Decl, spec ast.Spec, field *ast.Field) *ast.CommentGroup { 78522- if field != nil { 78523- if field.Doc != nil { 78524- return field.Doc 78525- } 78526- if field.Comment != nil { 78527- return field.Comment 78528- } 78529- return nil 78530- } 78531- switch decl := decl.(type) { 78532- case *ast.FuncDecl: 78533- return decl.Doc 78534- case *ast.GenDecl: 78535- switch spec := spec.(type) { 78536- case *ast.ValueSpec: 78537- if spec.Doc != nil { 78538- return spec.Doc 78539- } 78540- if decl.Doc != nil { 78541- return decl.Doc 78542- } 78543- return spec.Comment 78544- case *ast.TypeSpec: 78545- if spec.Doc != nil { 78546- return spec.Doc 78547- } 78548- if decl.Doc != nil { 78549- return decl.Doc 78550- } 78551- return spec.Comment 78552- } 78553- } 78554- return nil 78555-} 78556- 78557-// parseFull fully parses the file corresponding to position pos (for 78558-// which fset provides file/line information). 78559-// 78560-// It returns the resulting ParsedGoFile as well as new pos contained in the 78561-// parsed file. 78562-func parseFull(ctx context.Context, snapshot Snapshot, fset *token.FileSet, pos token.Pos) (*ParsedGoFile, token.Pos, error) { 78563- f := fset.File(pos) 78564- if f == nil { 78565- return nil, 0, bug.Errorf("internal error: no file for position %d", pos) 78566- } 78567- 78568- uri := span.URIFromPath(f.Name()) 78569- fh, err := snapshot.GetFile(ctx, uri) 78570- if err != nil { 78571- return nil, 0, err 78572- } 78573- 78574- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 78575- if err != nil { 78576- return nil, 0, err 78577- } 78578- 78579- offset, err := safetoken.Offset(f, pos) 78580- if err != nil { 78581- return nil, 0, bug.Errorf("offset out of bounds in %q", uri) 78582- } 78583- 78584- fullPos, err := safetoken.Pos(pgf.Tok, offset) 78585- if err != nil { 78586- return nil, 0, err 78587- } 78588- 78589- return pgf, fullPos, nil 78590-} 78591- 78592-// extractFieldList recursively tries to extract a field list. 78593-// If it is not found, nil is returned. 78594-func extractFieldList(specType ast.Expr) *ast.FieldList { 78595- switch t := specType.(type) { 78596- case *ast.StructType: 78597- return t.Fields 78598- case *ast.InterfaceType: 78599- return t.Methods 78600- case *ast.ArrayType: 78601- return extractFieldList(t.Elt) 78602- case *ast.MapType: 78603- // Map value has a greater chance to be a struct 78604- if fields := extractFieldList(t.Value); fields != nil { 78605- return fields 78606- } 78607- return extractFieldList(t.Key) 78608- case *ast.ChanType: 78609- return extractFieldList(t.Value) 78610- } 78611- return nil 78612-} 78613- 78614-func formatHover(h *HoverJSON, options *Options) (string, error) { 78615- signature := formatSignature(h, options) 78616- 78617- switch options.HoverKind { 78618- case SingleLine: 78619- return h.SingleLine, nil 78620- case NoDocumentation: 78621- return signature, nil 78622- case Structured: 78623- b, err := json.Marshal(h) 78624- if err != nil { 78625- return "", err 78626- } 78627- return string(b), nil 78628- } 78629- 78630- link := formatLink(h, options) 78631- doc := formatDoc(h, options) 78632- 78633- var b strings.Builder 78634- parts := []string{signature, doc, link} 78635- for i, el := range parts { 78636- if el != "" { 78637- b.WriteString(el) 78638- 78639- // If any elements of the remainder of the list are non-empty, 78640- // write an extra newline. 78641- if anyNonEmpty(parts[i+1:]) { 78642- if options.PreferredContentFormat == protocol.Markdown { 78643- b.WriteString("\n\n") 78644- } else { 78645- b.WriteRune('\n') 78646- } 78647- } 78648- } 78649- } 78650- return b.String(), nil 78651-} 78652- 78653-func formatSignature(h *HoverJSON, options *Options) string { 78654- signature := h.Signature 78655- if signature != "" && options.PreferredContentFormat == protocol.Markdown { 78656- signature = fmt.Sprintf("```go\n%s\n```", signature) 78657- } 78658- return signature 78659-} 78660- 78661-func formatLink(h *HoverJSON, options *Options) string { 78662- if !options.LinksInHover || options.LinkTarget == "" || h.LinkPath == "" { 78663- return "" 78664- } 78665- plainLink := BuildLink(options.LinkTarget, h.LinkPath, h.LinkAnchor) 78666- switch options.PreferredContentFormat { 78667- case protocol.Markdown: 78668- return fmt.Sprintf("[`%s` on %s](%s)", h.SymbolName, options.LinkTarget, plainLink) 78669- case protocol.PlainText: 78670- return "" 78671- default: 78672- return plainLink 78673- } 78674-} 78675- 78676-// BuildLink constructs a URL with the given target, path, and anchor. 78677-func BuildLink(target, path, anchor string) string { 78678- link := fmt.Sprintf("https://%s/%s", target, path) 78679- if anchor == "" { 78680- return link 78681- } 78682- return link + "#" + anchor 78683-} 78684- 78685-func formatDoc(h *HoverJSON, options *Options) string { 78686- var doc string 78687- switch options.HoverKind { 78688- case SynopsisDocumentation: 78689- doc = h.Synopsis 78690- case FullDocumentation: 78691- doc = h.FullDocumentation 78692- } 78693- if options.PreferredContentFormat == protocol.Markdown { 78694- return CommentToMarkdown(doc, options) 78695- } 78696- return doc 78697-} 78698- 78699-func anyNonEmpty(x []string) bool { 78700- for _, el := range x { 78701- if el != "" { 78702- return true 78703- } 78704- } 78705- return false 78706-} 78707- 78708-// findDeclInfo returns the syntax nodes involved in the declaration of the 78709-// types.Object with position pos, searching the given list of file syntax 78710-// trees. 78711-// 78712-// Pos may be the position of the name-defining identifier in a FuncDecl, 78713-// ValueSpec, TypeSpec, Field, or as a special case the position of 78714-// Ellipsis.Elt in an ellipsis field. 78715-// 78716-// If found, the resulting decl, spec, and field will be the inner-most 78717-// instance of each node type surrounding pos. 78718-// 78719-// If field is non-nil, pos is the position of a field Var. If field is nil and 78720-// spec is non-nil, pos is the position of a Var, Const, or TypeName object. If 78721-// both field and spec are nil and decl is non-nil, pos is the position of a 78722-// Func object. 78723-// 78724-// It returns a nil decl if no object-defining node is found at pos. 78725-// 78726-// TODO(rfindley): this function has tricky semantics, and may be worth unit 78727-// testing and/or refactoring. 78728-func findDeclInfo(files []*ast.File, pos token.Pos) (decl ast.Decl, spec ast.Spec, field *ast.Field) { 78729- // panic(found{}) breaks off the traversal and 78730- // causes the function to return normally. 78731- type found struct{} 78732- defer func() { 78733- switch x := recover().(type) { 78734- case nil: 78735- case found: 78736- default: 78737- panic(x) 78738- } 78739- }() 78740- 78741- // Visit the files in search of the node at pos. 78742- stack := make([]ast.Node, 0, 20) 78743- // Allocate the closure once, outside the loop. 78744- f := func(n ast.Node) bool { 78745- if n != nil { 78746- stack = append(stack, n) // push 78747- } else { 78748- stack = stack[:len(stack)-1] // pop 78749- return false 78750- } 78751- 78752- // Skip subtrees (incl. files) that don't contain the search point. 78753- if !(n.Pos() <= pos && pos < n.End()) { 78754- return false 78755- } 78756- 78757- switch n := n.(type) { 78758- case *ast.Field: 78759- findEnclosingDeclAndSpec := func() { 78760- for i := len(stack) - 1; i >= 0; i-- { 78761- switch n := stack[i].(type) { 78762- case ast.Spec: 78763- spec = n 78764- case ast.Decl: 78765- decl = n 78766- return 78767- } 78768- } 78769- } 78770- 78771- // Check each field name since you can have 78772- // multiple names for the same type expression. 78773- for _, id := range n.Names { 78774- if id.Pos() == pos { 78775- field = n 78776- findEnclosingDeclAndSpec() 78777- panic(found{}) 78778- } 78779- } 78780- 78781- // Check *ast.Field itself. This handles embedded 78782- // fields which have no associated *ast.Ident name. 78783- if n.Pos() == pos { 78784- field = n 78785- findEnclosingDeclAndSpec() 78786- panic(found{}) 78787- } 78788- 78789- // Also check "X" in "...X". This makes it easy to format variadic 78790- // signature params properly. 78791- // 78792- // TODO(rfindley): I don't understand this comment. How does finding the 78793- // field in this case make it easier to format variadic signature params? 78794- if ell, ok := n.Type.(*ast.Ellipsis); ok && ell.Elt != nil && ell.Elt.Pos() == pos { 78795- field = n 78796- findEnclosingDeclAndSpec() 78797- panic(found{}) 78798- } 78799- 78800- case *ast.FuncDecl: 78801- if n.Name.Pos() == pos { 78802- decl = n 78803- panic(found{}) 78804- } 78805- 78806- case *ast.GenDecl: 78807- for _, s := range n.Specs { 78808- switch s := s.(type) { 78809- case *ast.TypeSpec: 78810- if s.Name.Pos() == pos { 78811- decl = n 78812- spec = s 78813- panic(found{}) 78814- } 78815- case *ast.ValueSpec: 78816- for _, id := range s.Names { 78817- if id.Pos() == pos { 78818- decl = n 78819- spec = s 78820- panic(found{}) 78821- } 78822- } 78823- } 78824- } 78825- } 78826- return true 78827- } 78828- for _, file := range files { 78829- ast.Inspect(file, f) 78830- } 78831- 78832- return nil, nil, nil 78833-} 78834diff -urN a/gopls/internal/lsp/source/identifier.go b/gopls/internal/lsp/source/identifier.go 78835--- a/gopls/internal/lsp/source/identifier.go 2000-01-01 00:00:00.000000000 -0000 78836+++ b/gopls/internal/lsp/source/identifier.go 1970-01-01 00:00:00.000000000 +0000 78837@@ -1,174 +0,0 @@ 78838-// Copyright 2018 The Go Authors. All rights reserved. 78839-// Use of this source code is governed by a BSD-style 78840-// license that can be found in the LICENSE file. 78841- 78842-package source 78843- 78844-import ( 78845- "errors" 78846- "go/ast" 78847- "go/types" 78848- 78849- "golang.org/x/tools/internal/typeparams" 78850-) 78851- 78852-// ErrNoIdentFound is error returned when no identifier is found at a particular position 78853-var ErrNoIdentFound = errors.New("no identifier found") 78854- 78855-// inferredSignature determines the resolved non-generic signature for an 78856-// identifier in an instantiation expression. 78857-// 78858-// If no such signature exists, it returns nil. 78859-func inferredSignature(info *types.Info, id *ast.Ident) *types.Signature { 78860- inst := typeparams.GetInstances(info)[id] 78861- sig, _ := inst.Type.(*types.Signature) 78862- return sig 78863-} 78864- 78865-func searchForEnclosing(info *types.Info, path []ast.Node) *types.TypeName { 78866- for _, n := range path { 78867- switch n := n.(type) { 78868- case *ast.SelectorExpr: 78869- if sel, ok := info.Selections[n]; ok { 78870- recv := Deref(sel.Recv()) 78871- 78872- // Keep track of the last exported type seen. 78873- var exported *types.TypeName 78874- if named, ok := recv.(*types.Named); ok && named.Obj().Exported() { 78875- exported = named.Obj() 78876- } 78877- // We don't want the last element, as that's the field or 78878- // method itself. 78879- for _, index := range sel.Index()[:len(sel.Index())-1] { 78880- if r, ok := recv.Underlying().(*types.Struct); ok { 78881- recv = Deref(r.Field(index).Type()) 78882- if named, ok := recv.(*types.Named); ok && named.Obj().Exported() { 78883- exported = named.Obj() 78884- } 78885- } 78886- } 78887- return exported 78888- } 78889- } 78890- } 78891- return nil 78892-} 78893- 78894-// typeToObject returns the relevant type name for the given type, after 78895-// unwrapping pointers, arrays, slices, channels, and function signatures with 78896-// a single non-error result. 78897-func typeToObject(typ types.Type) *types.TypeName { 78898- switch typ := typ.(type) { 78899- case *types.Named: 78900- // TODO(rfindley): this should use typeparams.NamedTypeOrigin. 78901- return typ.Obj() 78902- case *types.Pointer: 78903- return typeToObject(typ.Elem()) 78904- case *types.Array: 78905- return typeToObject(typ.Elem()) 78906- case *types.Slice: 78907- return typeToObject(typ.Elem()) 78908- case *types.Chan: 78909- return typeToObject(typ.Elem()) 78910- case *types.Signature: 78911- // Try to find a return value of a named type. If there's only one 78912- // such value, jump to its type definition. 78913- var res *types.TypeName 78914- 78915- results := typ.Results() 78916- for i := 0; i < results.Len(); i++ { 78917- obj := typeToObject(results.At(i).Type()) 78918- if obj == nil || hasErrorType(obj) { 78919- // Skip builtins. 78920- continue 78921- } 78922- if res != nil { 78923- // The function/method must have only one return value of a named type. 78924- return nil 78925- } 78926- 78927- res = obj 78928- } 78929- return res 78930- default: 78931- return nil 78932- } 78933-} 78934- 78935-func hasErrorType(obj types.Object) bool { 78936- return types.IsInterface(obj.Type()) && obj.Pkg() == nil && obj.Name() == "error" 78937-} 78938- 78939-// typeSwitchImplicits returns all the implicit type switch objects that 78940-// correspond to the leaf *ast.Ident. It also returns the original type 78941-// associated with the identifier (outside of a case clause). 78942-func typeSwitchImplicits(info *types.Info, path []ast.Node) ([]types.Object, types.Type) { 78943- ident, _ := path[0].(*ast.Ident) 78944- if ident == nil { 78945- return nil, nil 78946- } 78947- 78948- var ( 78949- ts *ast.TypeSwitchStmt 78950- assign *ast.AssignStmt 78951- cc *ast.CaseClause 78952- obj = info.ObjectOf(ident) 78953- ) 78954- 78955- // Walk our ancestors to determine if our leaf ident refers to a 78956- // type switch variable, e.g. the "a" from "switch a := b.(type)". 78957-Outer: 78958- for i := 1; i < len(path); i++ { 78959- switch n := path[i].(type) { 78960- case *ast.AssignStmt: 78961- // Check if ident is the "a" in "a := foo.(type)". The "a" in 78962- // this case has no types.Object, so check for ident equality. 78963- if len(n.Lhs) == 1 && n.Lhs[0] == ident { 78964- assign = n 78965- } 78966- case *ast.CaseClause: 78967- // Check if ident is a use of "a" within a case clause. Each 78968- // case clause implicitly maps "a" to a different types.Object, 78969- // so check if ident's object is the case clause's implicit 78970- // object. 78971- if obj != nil && info.Implicits[n] == obj { 78972- cc = n 78973- } 78974- case *ast.TypeSwitchStmt: 78975- // Look for the type switch that owns our previously found 78976- // *ast.AssignStmt or *ast.CaseClause. 78977- if n.Assign == assign { 78978- ts = n 78979- break Outer 78980- } 78981- 78982- for _, stmt := range n.Body.List { 78983- if stmt == cc { 78984- ts = n 78985- break Outer 78986- } 78987- } 78988- } 78989- } 78990- if ts == nil { 78991- return nil, nil 78992- } 78993- // Our leaf ident refers to a type switch variable. Fan out to the 78994- // type switch's implicit case clause objects. 78995- var objs []types.Object 78996- for _, cc := range ts.Body.List { 78997- if ccObj := info.Implicits[cc]; ccObj != nil { 78998- objs = append(objs, ccObj) 78999- } 79000- } 79001- // The right-hand side of a type switch should only have one 79002- // element, and we need to track its type in order to generate 79003- // hover information for implicit type switch variables. 79004- var typ types.Type 79005- if assign, ok := ts.Assign.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 { 79006- if rhs := assign.Rhs[0].(*ast.TypeAssertExpr); ok { 79007- typ = info.TypeOf(rhs.X) 79008- } 79009- } 79010- return objs, typ 79011-} 79012diff -urN a/gopls/internal/lsp/source/identifier_test.go b/gopls/internal/lsp/source/identifier_test.go 79013--- a/gopls/internal/lsp/source/identifier_test.go 2000-01-01 00:00:00.000000000 -0000 79014+++ b/gopls/internal/lsp/source/identifier_test.go 1970-01-01 00:00:00.000000000 +0000 79015@@ -1,103 +0,0 @@ 79016-// Copyright 2020 The Go Authors. All rights reserved. 79017-// Use of this source code is governed by a BSD-style 79018-// license that can be found in the LICENSE file. 79019- 79020-package source 79021- 79022-import ( 79023- "bytes" 79024- "go/ast" 79025- "go/parser" 79026- "go/token" 79027- "go/types" 79028- "testing" 79029-) 79030- 79031-func TestSearchForEnclosing(t *testing.T) { 79032- tests := []struct { 79033- desc string 79034- // For convenience, consider the first occurrence of the identifier "X" in 79035- // src. 79036- src string 79037- // By convention, "" means no type found. 79038- wantTypeName string 79039- }{ 79040- { 79041- // TODO(rFindley): is this correct, or do we want to resolve I2 here? 79042- desc: "embedded interface in interface", 79043- src: `package a; var y = i1.X; type i1 interface {I2}; type I2 interface{X()}`, 79044- wantTypeName: "", 79045- }, 79046- { 79047- desc: "embedded interface in struct", 79048- src: `package a; var y = t.X; type t struct {I}; type I interface{X()}`, 79049- wantTypeName: "I", 79050- }, 79051- { 79052- desc: "double embedding", 79053- src: `package a; var y = t1.X; type t1 struct {t2}; type t2 struct {I}; type I interface{X()}`, 79054- wantTypeName: "I", 79055- }, 79056- } 79057- 79058- for _, test := range tests { 79059- test := test 79060- t.Run(test.desc, func(t *testing.T) { 79061- fset := token.NewFileSet() 79062- file, err := parser.ParseFile(fset, "a.go", test.src, parser.AllErrors) 79063- if err != nil { 79064- t.Fatal(err) 79065- } 79066- column := 1 + bytes.IndexRune([]byte(test.src), 'X') 79067- pos := posAt(1, column, fset, "a.go") 79068- path := pathEnclosingObjNode(file, pos) 79069- if path == nil { 79070- t.Fatalf("no ident found at (1, %d)", column) 79071- } 79072- info := newInfo() 79073- if _, err = (*types.Config)(nil).Check("p", fset, []*ast.File{file}, info); err != nil { 79074- t.Fatal(err) 79075- } 79076- obj := searchForEnclosing(info, path) 79077- if obj == nil { 79078- if test.wantTypeName != "" { 79079- t.Errorf("searchForEnclosing(...) = <nil>, want %q", test.wantTypeName) 79080- } 79081- return 79082- } 79083- if got := obj.Name(); got != test.wantTypeName { 79084- t.Errorf("searchForEnclosing(...) = %q, want %q", got, test.wantTypeName) 79085- } 79086- }) 79087- } 79088-} 79089- 79090-// posAt returns the token.Pos corresponding to the 1-based (line, column) 79091-// coordinates in the file fname of fset. 79092-func posAt(line, column int, fset *token.FileSet, fname string) token.Pos { 79093- var tok *token.File 79094- fset.Iterate(func(tf *token.File) bool { 79095- if tf.Name() == fname { 79096- tok = tf 79097- return false 79098- } 79099- return true 79100- }) 79101- if tok == nil { 79102- return token.NoPos 79103- } 79104- start := tok.LineStart(line) 79105- return start + token.Pos(column-1) 79106-} 79107- 79108-// newInfo returns a types.Info with all maps populated. 79109-func newInfo() *types.Info { 79110- return &types.Info{ 79111- Types: make(map[ast.Expr]types.TypeAndValue), 79112- Defs: make(map[*ast.Ident]types.Object), 79113- Uses: make(map[*ast.Ident]types.Object), 79114- Implicits: make(map[ast.Node]types.Object), 79115- Selections: make(map[*ast.SelectorExpr]*types.Selection), 79116- Scopes: make(map[ast.Node]*types.Scope), 79117- } 79118-} 79119diff -urN a/gopls/internal/lsp/source/implementation.go b/gopls/internal/lsp/source/implementation.go 79120--- a/gopls/internal/lsp/source/implementation.go 2000-01-01 00:00:00.000000000 -0000 79121+++ b/gopls/internal/lsp/source/implementation.go 1970-01-01 00:00:00.000000000 +0000 79122@@ -1,482 +0,0 @@ 79123-// Copyright 2019 The Go Authors. All rights reserved. 79124-// Use of this source code is governed by a BSD-style 79125-// license that can be found in the LICENSE file. 79126- 79127-package source 79128- 79129-import ( 79130- "context" 79131- "errors" 79132- "fmt" 79133- "go/ast" 79134- "go/token" 79135- "go/types" 79136- "reflect" 79137- "sort" 79138- "strings" 79139- "sync" 79140- 79141- "golang.org/x/sync/errgroup" 79142- "golang.org/x/tools/gopls/internal/lsp/protocol" 79143- "golang.org/x/tools/gopls/internal/lsp/safetoken" 79144- "golang.org/x/tools/gopls/internal/lsp/source/methodsets" 79145- "golang.org/x/tools/gopls/internal/span" 79146- "golang.org/x/tools/internal/event" 79147-) 79148- 79149-// This file defines the new implementation of the 'implementation' 79150-// operator that does not require type-checker data structures for an 79151-// unbounded number of packages. 79152-// 79153-// TODO(adonovan): 79154-// - Audit to ensure robustness in face of type errors. 79155-// - Support 'error' and 'error.Error', which were also lacking from the old implementation. 79156-// - Eliminate false positives due to 'tricky' cases of the global algorithm. 79157-// - Ensure we have test coverage of: 79158-// type aliases 79159-// nil, PkgName, Builtin (all errors) 79160-// any (empty result) 79161-// method of unnamed interface type (e.g. var x interface { f() }) 79162-// (the global algorithm may find implementations of this type 79163-// but will not include it in the index.) 79164- 79165-// Implementation returns a new sorted array of locations of 79166-// declarations of types that implement (or are implemented by) the 79167-// type referred to at the given position. 79168-// 79169-// If the position denotes a method, the computation is applied to its 79170-// receiver type and then its corresponding methods are returned. 79171-func Implementation(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position) ([]protocol.Location, error) { 79172- ctx, done := event.Start(ctx, "source.Implementation") 79173- defer done() 79174- 79175- locs, err := implementations2(ctx, snapshot, f, pp) 79176- if err != nil { 79177- return nil, err 79178- } 79179- 79180- // Sort and de-duplicate locations. 79181- sort.Slice(locs, func(i, j int) bool { 79182- return protocol.CompareLocation(locs[i], locs[j]) < 0 79183- }) 79184- out := locs[:0] 79185- for _, loc := range locs { 79186- if len(out) == 0 || out[len(out)-1] != loc { 79187- out = append(out, loc) 79188- } 79189- } 79190- locs = out 79191- 79192- return locs, nil 79193-} 79194- 79195-func implementations2(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) ([]protocol.Location, error) { 79196- 79197- // Type-check the query package, find the query identifier, 79198- // and locate the type or method declaration it refers to. 79199- declPosn, err := typeDeclPosition(ctx, snapshot, fh.URI(), pp) 79200- if err != nil { 79201- return nil, err 79202- } 79203- 79204- // Type-check the declaring package (incl. variants) for use 79205- // by the "local" search, which uses type information to 79206- // enumerate all types within the package that satisfy the 79207- // query type, even those defined local to a function. 79208- declURI := span.URIFromPath(declPosn.Filename) 79209- declMetas, err := snapshot.MetadataForFile(ctx, declURI) 79210- if err != nil { 79211- return nil, err 79212- } 79213- if len(declMetas) == 0 { 79214- return nil, fmt.Errorf("no packages for file %s", declURI) 79215- } 79216- ids := make([]PackageID, len(declMetas)) 79217- for i, m := range declMetas { 79218- ids[i] = m.ID 79219- } 79220- localPkgs, err := snapshot.TypeCheck(ctx, ids...) 79221- if err != nil { 79222- return nil, err 79223- } 79224- // The narrowest package will do, since the local search is based 79225- // on position and the global search is based on fingerprint. 79226- // (Neither is based on object identity.) 79227- declPkg := localPkgs[0] 79228- declFile, err := declPkg.File(declURI) 79229- if err != nil { 79230- return nil, err // "can't happen" 79231- } 79232- 79233- // Find declaration of corresponding object 79234- // in this package based on (URI, offset). 79235- pos, err := safetoken.Pos(declFile.Tok, declPosn.Offset) 79236- if err != nil { 79237- return nil, err 79238- } 79239- // TODO(adonovan): simplify: use objectsAt? 79240- path := pathEnclosingObjNode(declFile.File, pos) 79241- if path == nil { 79242- return nil, ErrNoIdentFound // checked earlier 79243- } 79244- id, ok := path[0].(*ast.Ident) 79245- if !ok { 79246- return nil, ErrNoIdentFound // checked earlier 79247- } 79248- obj := declPkg.GetTypesInfo().ObjectOf(id) // may be nil 79249- 79250- // Is the selected identifier a type name or method? 79251- // (For methods, report the corresponding method names.) 79252- var queryType types.Type 79253- var queryMethodID string 79254- switch obj := obj.(type) { 79255- case *types.TypeName: 79256- queryType = obj.Type() 79257- case *types.Func: 79258- // For methods, use the receiver type, which may be anonymous. 79259- if recv := obj.Type().(*types.Signature).Recv(); recv != nil { 79260- queryType = recv.Type() 79261- queryMethodID = obj.Id() 79262- } 79263- } 79264- if queryType == nil { 79265- return nil, fmt.Errorf("%s is not a type or method", id.Name) 79266- } 79267- 79268- // Compute the method-set fingerprint used as a key to the global search. 79269- key, hasMethods := methodsets.KeyOf(queryType) 79270- if !hasMethods { 79271- // A type with no methods yields an empty result. 79272- // (No point reporting that every type satisfies 'any'.) 79273- return nil, nil 79274- } 79275- 79276- // The global search needs to look at every package in the workspace; 79277- // see package ./methodsets. 79278- // 79279- // For now we do all the type checking before beginning the search. 79280- // TODO(adonovan): opt: search in parallel topological order 79281- // so that we can overlap index lookup with typechecking. 79282- // I suspect a number of algorithms on the result of TypeCheck could 79283- // be optimized by being applied as soon as each package is available. 79284- globalMetas, err := snapshot.AllMetadata(ctx) 79285- if err != nil { 79286- return nil, err 79287- } 79288- globalIDs := make([]PackageID, 0, len(globalMetas)) 79289- for _, m := range globalMetas { 79290- if m.PkgPath == declPkg.Metadata().PkgPath { 79291- continue // declaring package is handled by local implementation 79292- } 79293- globalIDs = append(globalIDs, m.ID) 79294- } 79295- indexes, err := snapshot.MethodSets(ctx, globalIDs...) 79296- if err != nil { 79297- return nil, err 79298- } 79299- 79300- // Search local and global packages in parallel. 79301- var ( 79302- group errgroup.Group 79303- locsMu sync.Mutex 79304- locs []protocol.Location 79305- ) 79306- // local search 79307- for _, localPkg := range localPkgs { 79308- localPkg := localPkg 79309- group.Go(func() error { 79310- localLocs, err := localImplementations(ctx, snapshot, localPkg, queryType, queryMethodID) 79311- if err != nil { 79312- return err 79313- } 79314- locsMu.Lock() 79315- locs = append(locs, localLocs...) 79316- locsMu.Unlock() 79317- return nil 79318- }) 79319- } 79320- // global search 79321- for _, index := range indexes { 79322- index := index 79323- group.Go(func() error { 79324- for _, res := range index.Search(key, queryMethodID) { 79325- loc := res.Location 79326- // Map offsets to protocol.Locations in parallel (may involve I/O). 79327- group.Go(func() error { 79328- ploc, err := offsetToLocation(ctx, snapshot, loc.Filename, loc.Start, loc.End) 79329- if err != nil { 79330- return err 79331- } 79332- locsMu.Lock() 79333- locs = append(locs, ploc) 79334- locsMu.Unlock() 79335- return nil 79336- }) 79337- } 79338- return nil 79339- }) 79340- } 79341- if err := group.Wait(); err != nil { 79342- return nil, err 79343- } 79344- 79345- return locs, nil 79346-} 79347- 79348-// offsetToLocation converts an offset-based position to a protocol.Location, 79349-// which requires reading the file. 79350-func offsetToLocation(ctx context.Context, snapshot Snapshot, filename string, start, end int) (protocol.Location, error) { 79351- uri := span.URIFromPath(filename) 79352- fh, err := snapshot.GetFile(ctx, uri) 79353- if err != nil { 79354- return protocol.Location{}, err // cancelled, perhaps 79355- } 79356- content, err := fh.Read() 79357- if err != nil { 79358- return protocol.Location{}, err // nonexistent or deleted ("can't happen") 79359- } 79360- m := protocol.NewMapper(uri, content) 79361- return m.OffsetLocation(start, end) 79362-} 79363- 79364-// typeDeclPosition returns the position of the declaration of the 79365-// type (or one of its methods) referred to at (uri, ppos). 79366-func typeDeclPosition(ctx context.Context, snapshot Snapshot, uri span.URI, ppos protocol.Position) (token.Position, error) { 79367- var noPosn token.Position 79368- 79369- pkg, pgf, err := PackageForFile(ctx, snapshot, uri, WidestPackage) 79370- if err != nil { 79371- return noPosn, err 79372- } 79373- pos, err := pgf.PositionPos(ppos) 79374- if err != nil { 79375- return noPosn, err 79376- } 79377- 79378- // This function inherits the limitation of its predecessor in 79379- // requiring the selection to be an identifier (of a type or 79380- // method). But there's no fundamental reason why one could 79381- // not pose this query about any selected piece of syntax that 79382- // has a type and thus a method set. 79383- // (If LSP was more thorough about passing text selections as 79384- // intervals to queries, you could ask about the method set of a 79385- // subexpression such as x.f().) 79386- 79387- // TODO(adonovan): simplify: use objectsAt? 79388- path := pathEnclosingObjNode(pgf.File, pos) 79389- if path == nil { 79390- return noPosn, ErrNoIdentFound 79391- } 79392- id, ok := path[0].(*ast.Ident) 79393- if !ok { 79394- return noPosn, ErrNoIdentFound 79395- } 79396- 79397- // Is the object a type or method? Reject other kinds. 79398- obj := pkg.GetTypesInfo().Uses[id] 79399- if obj == nil { 79400- // Check uses first (unlike ObjectOf) so that T in 79401- // struct{T} is treated as a reference to a type, 79402- // not a declaration of a field. 79403- obj = pkg.GetTypesInfo().Defs[id] 79404- } 79405- switch obj := obj.(type) { 79406- case *types.TypeName: 79407- // ok 79408- case *types.Func: 79409- if obj.Type().(*types.Signature).Recv() == nil { 79410- return noPosn, fmt.Errorf("%s is a function, not a method", id.Name) 79411- } 79412- case nil: 79413- return noPosn, fmt.Errorf("%s denotes unknown object", id.Name) 79414- default: 79415- // e.g. *types.Var -> "var". 79416- kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types.")) 79417- return noPosn, fmt.Errorf("%s is a %s, not a type", id.Name, kind) 79418- } 79419- 79420- declPosn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()) 79421- return declPosn, nil 79422-} 79423- 79424-// localImplementations searches within pkg for declarations of all 79425-// types that are assignable to/from the query type, and returns a new 79426-// unordered array of their locations. 79427-// 79428-// If methodID is non-empty, the function instead returns the location 79429-// of each type's method (if any) of that ID. 79430-// 79431-// ("Local" refers to the search within the same package, but this 79432-// function's results may include type declarations that are local to 79433-// a function body. The global search index excludes such types 79434-// because reliably naming such types is hard.) 79435-func localImplementations(ctx context.Context, snapshot Snapshot, pkg Package, queryType types.Type, methodID string) ([]protocol.Location, error) { 79436- queryType = methodsets.EnsurePointer(queryType) 79437- 79438- // Scan through all type declarations in the syntax. 79439- var locs []protocol.Location 79440- var methodLocs []methodsets.Location 79441- for _, pgf := range pkg.CompiledGoFiles() { 79442- ast.Inspect(pgf.File, func(n ast.Node) bool { 79443- spec, ok := n.(*ast.TypeSpec) 79444- if !ok { 79445- return true // not a type declaration 79446- } 79447- def := pkg.GetTypesInfo().Defs[spec.Name] 79448- if def == nil { 79449- return true // "can't happen" for types 79450- } 79451- if def.(*types.TypeName).IsAlias() { 79452- return true // skip type aliases to avoid duplicate reporting 79453- } 79454- candidateType := methodsets.EnsurePointer(def.Type()) 79455- 79456- // The historical behavior enshrined by this 79457- // function rejects cases where both are 79458- // (nontrivial) interface types? 79459- // That seems like useful information. 79460- // TODO(adonovan): UX: report I/I pairs too? 79461- // The same question appears in the global algorithm (methodsets). 79462- if !concreteImplementsIntf(candidateType, queryType) { 79463- return true // not assignable 79464- } 79465- 79466- // Ignore types with empty method sets. 79467- // (No point reporting that every type satisfies 'any'.) 79468- mset := types.NewMethodSet(candidateType) 79469- if mset.Len() == 0 { 79470- return true 79471- } 79472- 79473- if methodID == "" { 79474- // Found matching type. 79475- locs = append(locs, mustLocation(pgf, spec.Name)) 79476- return true 79477- } 79478- 79479- // Find corresponding method. 79480- // 79481- // We can't use LookupFieldOrMethod because it requires 79482- // the methodID's types.Package, which we don't know. 79483- // We could recursively search pkg.Imports for it, 79484- // but it's easier to walk the method set. 79485- for i := 0; i < mset.Len(); i++ { 79486- method := mset.At(i).Obj() 79487- if method.Id() == methodID { 79488- posn := safetoken.StartPosition(pkg.FileSet(), method.Pos()) 79489- methodLocs = append(methodLocs, methodsets.Location{ 79490- Filename: posn.Filename, 79491- Start: posn.Offset, 79492- End: posn.Offset + len(method.Name()), 79493- }) 79494- break 79495- } 79496- } 79497- return true 79498- }) 79499- } 79500- 79501- // Finally convert method positions to protocol form by reading the files. 79502- for _, mloc := range methodLocs { 79503- loc, err := offsetToLocation(ctx, snapshot, mloc.Filename, mloc.Start, mloc.End) 79504- if err != nil { 79505- return nil, err 79506- } 79507- locs = append(locs, loc) 79508- } 79509- 79510- return locs, nil 79511-} 79512- 79513-// concreteImplementsIntf returns true if a is an interface type implemented by 79514-// concrete type b, or vice versa. 79515-func concreteImplementsIntf(a, b types.Type) bool { 79516- aIsIntf, bIsIntf := types.IsInterface(a), types.IsInterface(b) 79517- 79518- // Make sure exactly one is an interface type. 79519- if aIsIntf == bIsIntf { 79520- return false 79521- } 79522- 79523- // Rearrange if needed so "a" is the concrete type. 79524- if aIsIntf { 79525- a, b = b, a 79526- } 79527- 79528- // TODO(adonovan): this should really use GenericAssignableTo 79529- // to report (e.g.) "ArrayList[T] implements List[T]", but 79530- // GenericAssignableTo doesn't work correctly on pointers to 79531- // generic named types. Thus the legacy implementation and the 79532- // "local" part of implementation2 fail to report generics. 79533- // The global algorithm based on subsets does the right thing. 79534- return types.AssignableTo(a, b) 79535-} 79536- 79537-var ( 79538- // TODO(adonovan): why do various RPC handlers related to 79539- // IncomingCalls return (nil, nil) on the protocol in response 79540- // to this error? That seems like a violation of the protocol. 79541- // Is it perhaps a workaround for VSCode behavior? 79542- errNoObjectFound = errors.New("no object found") 79543-) 79544- 79545-// pathEnclosingObjNode returns the AST path to the object-defining 79546-// node associated with pos. "Object-defining" means either an 79547-// *ast.Ident mapped directly to a types.Object or an ast.Node mapped 79548-// implicitly to a types.Object. 79549-func pathEnclosingObjNode(f *ast.File, pos token.Pos) []ast.Node { 79550- var ( 79551- path []ast.Node 79552- found bool 79553- ) 79554- 79555- ast.Inspect(f, func(n ast.Node) bool { 79556- if found { 79557- return false 79558- } 79559- 79560- if n == nil { 79561- path = path[:len(path)-1] 79562- return false 79563- } 79564- 79565- path = append(path, n) 79566- 79567- switch n := n.(type) { 79568- case *ast.Ident: 79569- // Include the position directly after identifier. This handles 79570- // the common case where the cursor is right after the 79571- // identifier the user is currently typing. Previously we 79572- // handled this by calling astutil.PathEnclosingInterval twice, 79573- // once for "pos" and once for "pos-1". 79574- found = n.Pos() <= pos && pos <= n.End() 79575- case *ast.ImportSpec: 79576- if n.Path.Pos() <= pos && pos < n.Path.End() { 79577- found = true 79578- // If import spec has a name, add name to path even though 79579- // position isn't in the name. 79580- if n.Name != nil { 79581- path = append(path, n.Name) 79582- } 79583- } 79584- case *ast.StarExpr: 79585- // Follow star expressions to the inner identifier. 79586- if pos == n.Star { 79587- pos = n.X.Pos() 79588- } 79589- } 79590- 79591- return !found 79592- }) 79593- 79594- if len(path) == 0 { 79595- return nil 79596- } 79597- 79598- // Reverse path so leaf is first element. 79599- for i := 0; i < len(path)/2; i++ { 79600- path[i], path[len(path)-1-i] = path[len(path)-1-i], path[i] 79601- } 79602- 79603- return path 79604-} 79605diff -urN a/gopls/internal/lsp/source/inlay_hint.go b/gopls/internal/lsp/source/inlay_hint.go 79606--- a/gopls/internal/lsp/source/inlay_hint.go 2000-01-01 00:00:00.000000000 -0000 79607+++ b/gopls/internal/lsp/source/inlay_hint.go 1970-01-01 00:00:00.000000000 +0000 79608@@ -1,394 +0,0 @@ 79609-// Copyright 2022 The Go Authors. All rights reserved. 79610-// Use of this source code is governed by a BSD-style 79611-// license that can be found in the LICENSE file. 79612- 79613-package source 79614- 79615-import ( 79616- "context" 79617- "fmt" 79618- "go/ast" 79619- "go/constant" 79620- "go/token" 79621- "go/types" 79622- "strings" 79623- 79624- "golang.org/x/tools/gopls/internal/lsp/protocol" 79625- "golang.org/x/tools/internal/event" 79626- "golang.org/x/tools/internal/typeparams" 79627-) 79628- 79629-const ( 79630- maxLabelLength = 28 79631-) 79632- 79633-type InlayHintFunc func(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, q *types.Qualifier) []protocol.InlayHint 79634- 79635-type Hint struct { 79636- Name string 79637- Doc string 79638- Run InlayHintFunc 79639-} 79640- 79641-const ( 79642- ParameterNames = "parameterNames" 79643- AssignVariableTypes = "assignVariableTypes" 79644- ConstantValues = "constantValues" 79645- RangeVariableTypes = "rangeVariableTypes" 79646- CompositeLiteralTypes = "compositeLiteralTypes" 79647- CompositeLiteralFieldNames = "compositeLiteralFields" 79648- FunctionTypeParameters = "functionTypeParameters" 79649-) 79650- 79651-var AllInlayHints = map[string]*Hint{ 79652- AssignVariableTypes: { 79653- Name: AssignVariableTypes, 79654- Doc: "Enable/disable inlay hints for variable types in assign statements:\n```go\n\ti/* int*/, j/* int*/ := 0, len(r)-1\n```", 79655- Run: assignVariableTypes, 79656- }, 79657- ParameterNames: { 79658- Name: ParameterNames, 79659- Doc: "Enable/disable inlay hints for parameter names:\n```go\n\tparseInt(/* str: */ \"123\", /* radix: */ 8)\n```", 79660- Run: parameterNames, 79661- }, 79662- ConstantValues: { 79663- Name: ConstantValues, 79664- Doc: "Enable/disable inlay hints for constant values:\n```go\n\tconst (\n\t\tKindNone Kind = iota/* = 0*/\n\t\tKindPrint/* = 1*/\n\t\tKindPrintf/* = 2*/\n\t\tKindErrorf/* = 3*/\n\t)\n```", 79665- Run: constantValues, 79666- }, 79667- RangeVariableTypes: { 79668- Name: RangeVariableTypes, 79669- Doc: "Enable/disable inlay hints for variable types in range statements:\n```go\n\tfor k/* int*/, v/* string*/ := range []string{} {\n\t\tfmt.Println(k, v)\n\t}\n```", 79670- Run: rangeVariableTypes, 79671- }, 79672- CompositeLiteralTypes: { 79673- Name: CompositeLiteralTypes, 79674- Doc: "Enable/disable inlay hints for composite literal types:\n```go\n\tfor _, c := range []struct {\n\t\tin, want string\n\t}{\n\t\t/*struct{ in string; want string }*/{\"Hello, world\", \"dlrow ,olleH\"},\n\t}\n```", 79675- Run: compositeLiteralTypes, 79676- }, 79677- CompositeLiteralFieldNames: { 79678- Name: CompositeLiteralFieldNames, 79679- Doc: "Enable/disable inlay hints for composite literal field names:\n```go\n\t{/*in: */\"Hello, world\", /*want: */\"dlrow ,olleH\"}\n```", 79680- Run: compositeLiteralFields, 79681- }, 79682- FunctionTypeParameters: { 79683- Name: FunctionTypeParameters, 79684- Doc: "Enable/disable inlay hints for implicit type parameters on generic functions:\n```go\n\tmyFoo/*[int, string]*/(1, \"hello\")\n```", 79685- Run: funcTypeParams, 79686- }, 79687-} 79688- 79689-func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) ([]protocol.InlayHint, error) { 79690- ctx, done := event.Start(ctx, "source.InlayHint") 79691- defer done() 79692- 79693- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 79694- if err != nil { 79695- return nil, fmt.Errorf("getting file for InlayHint: %w", err) 79696- } 79697- 79698- // Collect a list of the inlay hints that are enabled. 79699- inlayHintOptions := snapshot.View().Options().InlayHintOptions 79700- var enabledHints []InlayHintFunc 79701- for hint, enabled := range inlayHintOptions.Hints { 79702- if !enabled { 79703- continue 79704- } 79705- if h, ok := AllInlayHints[hint]; ok { 79706- enabledHints = append(enabledHints, h.Run) 79707- } 79708- } 79709- if len(enabledHints) == 0 { 79710- return nil, nil 79711- } 79712- 79713- info := pkg.GetTypesInfo() 79714- q := Qualifier(pgf.File, pkg.GetTypes(), info) 79715- 79716- // Set the range to the full file if the range is not valid. 79717- start, end := pgf.File.Pos(), pgf.File.End() 79718- if pRng.Start.Line < pRng.End.Line || pRng.Start.Character < pRng.End.Character { 79719- // Adjust start and end for the specified range. 79720- var err error 79721- start, end, err = pgf.RangePos(pRng) 79722- if err != nil { 79723- return nil, err 79724- } 79725- } 79726- 79727- var hints []protocol.InlayHint 79728- ast.Inspect(pgf.File, func(node ast.Node) bool { 79729- // If not in range, we can stop looking. 79730- if node == nil || node.End() < start || node.Pos() > end { 79731- return false 79732- } 79733- for _, fn := range enabledHints { 79734- hints = append(hints, fn(node, pgf.Mapper, pgf.Tok, info, &q)...) 79735- } 79736- return true 79737- }) 79738- return hints, nil 79739-} 79740- 79741-func parameterNames(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, _ *types.Qualifier) []protocol.InlayHint { 79742- callExpr, ok := node.(*ast.CallExpr) 79743- if !ok { 79744- return nil 79745- } 79746- signature, ok := info.TypeOf(callExpr.Fun).(*types.Signature) 79747- if !ok { 79748- return nil 79749- } 79750- 79751- var hints []protocol.InlayHint 79752- for i, v := range callExpr.Args { 79753- start, err := m.PosPosition(tf, v.Pos()) 79754- if err != nil { 79755- continue 79756- } 79757- params := signature.Params() 79758- // When a function has variadic params, we skip args after 79759- // params.Len(). 79760- if i > params.Len()-1 { 79761- break 79762- } 79763- param := params.At(i) 79764- // param.Name is empty for built-ins like append 79765- if param.Name() == "" { 79766- continue 79767- } 79768- // Skip the parameter name hint if the arg matches the 79769- // the parameter name. 79770- if i, ok := v.(*ast.Ident); ok && i.Name == param.Name() { 79771- continue 79772- } 79773- 79774- label := param.Name() 79775- if signature.Variadic() && i == params.Len()-1 { 79776- label = label + "..." 79777- } 79778- hints = append(hints, protocol.InlayHint{ 79779- Position: start, 79780- Label: buildLabel(label + ":"), 79781- Kind: protocol.Parameter, 79782- PaddingRight: true, 79783- }) 79784- } 79785- return hints 79786-} 79787- 79788-func funcTypeParams(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, _ *types.Qualifier) []protocol.InlayHint { 79789- ce, ok := node.(*ast.CallExpr) 79790- if !ok { 79791- return nil 79792- } 79793- id, ok := ce.Fun.(*ast.Ident) 79794- if !ok { 79795- return nil 79796- } 79797- inst := typeparams.GetInstances(info)[id] 79798- if inst.TypeArgs == nil { 79799- return nil 79800- } 79801- start, err := m.PosPosition(tf, id.End()) 79802- if err != nil { 79803- return nil 79804- } 79805- var args []string 79806- for i := 0; i < inst.TypeArgs.Len(); i++ { 79807- args = append(args, inst.TypeArgs.At(i).String()) 79808- } 79809- if len(args) == 0 { 79810- return nil 79811- } 79812- return []protocol.InlayHint{{ 79813- Position: start, 79814- Label: buildLabel("[" + strings.Join(args, ", ") + "]"), 79815- Kind: protocol.Type, 79816- }} 79817-} 79818- 79819-func assignVariableTypes(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, q *types.Qualifier) []protocol.InlayHint { 79820- stmt, ok := node.(*ast.AssignStmt) 79821- if !ok || stmt.Tok != token.DEFINE { 79822- return nil 79823- } 79824- 79825- var hints []protocol.InlayHint 79826- for _, v := range stmt.Lhs { 79827- if h := variableType(v, m, tf, info, q); h != nil { 79828- hints = append(hints, *h) 79829- } 79830- } 79831- return hints 79832-} 79833- 79834-func rangeVariableTypes(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, q *types.Qualifier) []protocol.InlayHint { 79835- rStmt, ok := node.(*ast.RangeStmt) 79836- if !ok { 79837- return nil 79838- } 79839- var hints []protocol.InlayHint 79840- if h := variableType(rStmt.Key, m, tf, info, q); h != nil { 79841- hints = append(hints, *h) 79842- } 79843- if h := variableType(rStmt.Value, m, tf, info, q); h != nil { 79844- hints = append(hints, *h) 79845- } 79846- return hints 79847-} 79848- 79849-func variableType(e ast.Expr, m *protocol.Mapper, tf *token.File, info *types.Info, q *types.Qualifier) *protocol.InlayHint { 79850- typ := info.TypeOf(e) 79851- if typ == nil { 79852- return nil 79853- } 79854- end, err := m.PosPosition(tf, e.End()) 79855- if err != nil { 79856- return nil 79857- } 79858- return &protocol.InlayHint{ 79859- Position: end, 79860- Label: buildLabel(types.TypeString(typ, *q)), 79861- Kind: protocol.Type, 79862- PaddingLeft: true, 79863- } 79864-} 79865- 79866-func constantValues(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, _ *types.Qualifier) []protocol.InlayHint { 79867- genDecl, ok := node.(*ast.GenDecl) 79868- if !ok || genDecl.Tok != token.CONST { 79869- return nil 79870- } 79871- 79872- var hints []protocol.InlayHint 79873- for _, v := range genDecl.Specs { 79874- spec, ok := v.(*ast.ValueSpec) 79875- if !ok { 79876- continue 79877- } 79878- end, err := m.PosPosition(tf, v.End()) 79879- if err != nil { 79880- continue 79881- } 79882- // Show hints when values are missing or at least one value is not 79883- // a basic literal. 79884- showHints := len(spec.Values) == 0 79885- checkValues := len(spec.Names) == len(spec.Values) 79886- var values []string 79887- for i, w := range spec.Names { 79888- obj, ok := info.ObjectOf(w).(*types.Const) 79889- if !ok || obj.Val().Kind() == constant.Unknown { 79890- return nil 79891- } 79892- if checkValues { 79893- switch spec.Values[i].(type) { 79894- case *ast.BadExpr: 79895- return nil 79896- case *ast.BasicLit: 79897- default: 79898- if obj.Val().Kind() != constant.Bool { 79899- showHints = true 79900- } 79901- } 79902- } 79903- values = append(values, fmt.Sprintf("%v", obj.Val())) 79904- } 79905- if !showHints || len(values) == 0 { 79906- continue 79907- } 79908- hints = append(hints, protocol.InlayHint{ 79909- Position: end, 79910- Label: buildLabel("= " + strings.Join(values, ", ")), 79911- PaddingLeft: true, 79912- }) 79913- } 79914- return hints 79915-} 79916- 79917-func compositeLiteralFields(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, q *types.Qualifier) []protocol.InlayHint { 79918- compLit, ok := node.(*ast.CompositeLit) 79919- if !ok { 79920- return nil 79921- } 79922- typ := info.TypeOf(compLit) 79923- if typ == nil { 79924- return nil 79925- } 79926- if t, ok := typ.(*types.Pointer); ok { 79927- typ = t.Elem() 79928- } 79929- strct, ok := typ.Underlying().(*types.Struct) 79930- if !ok { 79931- return nil 79932- } 79933- 79934- var hints []protocol.InlayHint 79935- var allEdits []protocol.TextEdit 79936- for i, v := range compLit.Elts { 79937- if _, ok := v.(*ast.KeyValueExpr); !ok { 79938- start, err := m.PosPosition(tf, v.Pos()) 79939- if err != nil { 79940- continue 79941- } 79942- if i > strct.NumFields()-1 { 79943- break 79944- } 79945- hints = append(hints, protocol.InlayHint{ 79946- Position: start, 79947- Label: buildLabel(strct.Field(i).Name() + ":"), 79948- Kind: protocol.Parameter, 79949- PaddingRight: true, 79950- }) 79951- allEdits = append(allEdits, protocol.TextEdit{ 79952- Range: protocol.Range{Start: start, End: start}, 79953- NewText: strct.Field(i).Name() + ": ", 79954- }) 79955- } 79956- } 79957- // It is not allowed to have a mix of keyed and unkeyed fields, so 79958- // have the text edits add keys to all fields. 79959- for i := range hints { 79960- hints[i].TextEdits = allEdits 79961- } 79962- return hints 79963-} 79964- 79965-func compositeLiteralTypes(node ast.Node, m *protocol.Mapper, tf *token.File, info *types.Info, q *types.Qualifier) []protocol.InlayHint { 79966- compLit, ok := node.(*ast.CompositeLit) 79967- if !ok { 79968- return nil 79969- } 79970- typ := info.TypeOf(compLit) 79971- if typ == nil { 79972- return nil 79973- } 79974- if compLit.Type != nil { 79975- return nil 79976- } 79977- prefix := "" 79978- if t, ok := typ.(*types.Pointer); ok { 79979- typ = t.Elem() 79980- prefix = "&" 79981- } 79982- // The type for this composite literal is implicit, add an inlay hint. 79983- start, err := m.PosPosition(tf, compLit.Lbrace) 79984- if err != nil { 79985- return nil 79986- } 79987- return []protocol.InlayHint{{ 79988- Position: start, 79989- Label: buildLabel(fmt.Sprintf("%s%s", prefix, types.TypeString(typ, *q))), 79990- Kind: protocol.Type, 79991- }} 79992-} 79993- 79994-func buildLabel(s string) []protocol.InlayHintLabelPart { 79995- label := protocol.InlayHintLabelPart{ 79996- Value: s, 79997- } 79998- if len(s) > maxLabelLength+len("...") { 79999- label.Value = s[:maxLabelLength] + "..." 80000- } 80001- return []protocol.InlayHintLabelPart{label} 80002-} 80003diff -urN a/gopls/internal/lsp/source/known_packages.go b/gopls/internal/lsp/source/known_packages.go 80004--- a/gopls/internal/lsp/source/known_packages.go 2000-01-01 00:00:00.000000000 -0000 80005+++ b/gopls/internal/lsp/source/known_packages.go 1970-01-01 00:00:00.000000000 +0000 80006@@ -1,140 +0,0 @@ 80007-// Copyright 2020 The Go Authors. All rights reserved. 80008-// Use of this source code is governed by a BSD-style 80009-// license that can be found in the LICENSE file. 80010- 80011-package source 80012- 80013-import ( 80014- "context" 80015- "fmt" 80016- "go/parser" 80017- "go/token" 80018- "sort" 80019- "strings" 80020- "sync" 80021- "time" 80022- 80023- "golang.org/x/tools/internal/event" 80024- "golang.org/x/tools/internal/imports" 80025-) 80026- 80027-// KnownPackagePaths returns a new list of package paths of all known 80028-// packages in the package graph that could potentially be imported by 80029-// the given file. The list is ordered lexicographically, except that 80030-// all dot-free paths (standard packages) appear before dotful ones. 80031-// 80032-// It is part of the gopls.list_known_packages command. 80033-func KnownPackagePaths(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]PackagePath, error) { 80034- // This algorithm is expressed in terms of Metadata, not Packages, 80035- // so it doesn't cause or wait for type checking. 80036- 80037- // Find a Metadata containing the file. 80038- metas, err := snapshot.MetadataForFile(ctx, fh.URI()) 80039- if err != nil { 80040- return nil, err // e.g. context cancelled 80041- } 80042- if len(metas) == 0 { 80043- return nil, fmt.Errorf("no loaded package contain file %s", fh.URI()) 80044- } 80045- current := metas[0] // pick one arbitrarily (they should all have the same package path) 80046- 80047- // Parse the file's imports so we can compute which 80048- // PackagePaths are imported by this specific file. 80049- src, err := fh.Read() 80050- if err != nil { 80051- return nil, err 80052- } 80053- file, err := parser.ParseFile(token.NewFileSet(), fh.URI().Filename(), src, parser.ImportsOnly) 80054- if err != nil { 80055- return nil, err 80056- } 80057- imported := make(map[PackagePath]bool) 80058- for _, imp := range file.Imports { 80059- if id := current.DepsByImpPath[UnquoteImportPath(imp)]; id != "" { 80060- if m := snapshot.Metadata(id); m != nil { 80061- imported[m.PkgPath] = true 80062- } 80063- } 80064- } 80065- 80066- // Now find candidates among known packages. 80067- knownPkgs, err := snapshot.AllMetadata(ctx) 80068- if err != nil { 80069- return nil, err 80070- } 80071- seen := make(map[PackagePath]bool) 80072- for _, knownPkg := range knownPkgs { 80073- // package main cannot be imported 80074- if knownPkg.Name == "main" { 80075- continue 80076- } 80077- // test packages cannot be imported 80078- if knownPkg.ForTest != "" { 80079- continue 80080- } 80081- // No need to import what the file already imports. 80082- // This check is based on PackagePath, not PackageID, 80083- // so that all test variants are filtered out too. 80084- if imported[knownPkg.PkgPath] { 80085- continue 80086- } 80087- // make sure internal packages are importable by the file 80088- if !IsValidImport(current.PkgPath, knownPkg.PkgPath) { 80089- continue 80090- } 80091- // naive check on cyclical imports 80092- if isDirectlyCyclical(current, knownPkg) { 80093- continue 80094- } 80095- // AllMetadata may have multiple variants of a pkg. 80096- seen[knownPkg.PkgPath] = true 80097- } 80098- 80099- // Augment the set by invoking the goimports algorithm. 80100- if err := snapshot.RunProcessEnvFunc(ctx, func(o *imports.Options) error { 80101- ctx, cancel := context.WithTimeout(ctx, time.Millisecond*80) 80102- defer cancel() 80103- var seenMu sync.Mutex 80104- wrapped := func(ifix imports.ImportFix) { 80105- seenMu.Lock() 80106- defer seenMu.Unlock() 80107- // TODO(adonovan): what if the actual package path has a vendor/ prefix? 80108- seen[PackagePath(ifix.StmtInfo.ImportPath)] = true 80109- } 80110- return imports.GetAllCandidates(ctx, wrapped, "", fh.URI().Filename(), string(current.Name), o.Env) 80111- }); err != nil { 80112- // If goimports failed, proceed with just the candidates from the metadata. 80113- event.Error(ctx, "imports.GetAllCandidates", err) 80114- } 80115- 80116- // Sort lexicographically, but with std before non-std packages. 80117- paths := make([]PackagePath, 0, len(seen)) 80118- for path := range seen { 80119- paths = append(paths, path) 80120- } 80121- sort.Slice(paths, func(i, j int) bool { 80122- importI, importJ := paths[i], paths[j] 80123- iHasDot := strings.Contains(string(importI), ".") 80124- jHasDot := strings.Contains(string(importJ), ".") 80125- if iHasDot != jHasDot { 80126- return jHasDot // dot-free paths (standard packages) compare less 80127- } 80128- return importI < importJ 80129- }) 80130- 80131- return paths, nil 80132-} 80133- 80134-// isDirectlyCyclical checks if imported directly imports pkg. 80135-// It does not (yet) offer a full cyclical check because showing a user 80136-// a list of importable packages already generates a very large list 80137-// and having a few false positives in there could be worth the 80138-// performance snappiness. 80139-// 80140-// TODO(adonovan): ensure that metadata graph is always cyclic! 80141-// Many algorithms will get confused or even stuck in the 80142-// presence of cycles. Then replace this function by 'false'. 80143-func isDirectlyCyclical(pkg, imported *Metadata) bool { 80144- _, ok := imported.DepsByPkgPath[pkg.PkgPath] 80145- return ok 80146-} 80147diff -urN a/gopls/internal/lsp/source/linkname.go b/gopls/internal/lsp/source/linkname.go 80148--- a/gopls/internal/lsp/source/linkname.go 2000-01-01 00:00:00.000000000 -0000 80149+++ b/gopls/internal/lsp/source/linkname.go 1970-01-01 00:00:00.000000000 +0000 80150@@ -1,136 +0,0 @@ 80151-// Copyright 2023 The Go Authors. All rights reserved. 80152-// Use of this source code is governed by a BSD-style 80153-// license that can be found in the LICENSE file. 80154- 80155-package source 80156- 80157-import ( 80158- "context" 80159- "errors" 80160- "fmt" 80161- "go/token" 80162- "strings" 80163- 80164- "golang.org/x/tools/gopls/internal/lsp/protocol" 80165- "golang.org/x/tools/gopls/internal/lsp/safetoken" 80166- "golang.org/x/tools/gopls/internal/span" 80167-) 80168- 80169-// ErrNoLinkname is returned by LinknameDefinition when no linkname 80170-// directive is found at a particular position. 80171-// As such it indicates that other definitions could be worth checking. 80172-var ErrNoLinkname = errors.New("no linkname directive found") 80173- 80174-// LinknameDefinition finds the definition of the linkname directive in fh at pos. 80175-// If there is no linkname directive at pos, returns ErrNoLinkname. 80176-func LinknameDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]protocol.Location, error) { 80177- pkgPath, name := parseLinkname(ctx, snapshot, fh, pos) 80178- if pkgPath == "" { 80179- return nil, ErrNoLinkname 80180- } 80181- return findLinkname(ctx, snapshot, fh, pos, PackagePath(pkgPath), name) 80182-} 80183- 80184-// parseLinkname attempts to parse a go:linkname declaration at the given pos. 80185-// If successful, it returns the package path and object name referenced by the second 80186-// argument of the linkname directive. 80187-// 80188-// If the position is not in the second argument of a go:linkname directive, or parsing fails, it returns "", "". 80189-func parseLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (pkgPath, name string) { 80190- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 80191- if err != nil { 80192- return "", "" 80193- } 80194- 80195- span, err := pgf.Mapper.PositionPoint(pos) 80196- if err != nil { 80197- return "", "" 80198- } 80199- atLine := span.Line() 80200- atColumn := span.Column() 80201- 80202- // Looking for pkgpath in '//go:linkname f pkgpath.g'. 80203- // (We ignore 1-arg linkname directives.) 80204- directive, column := findLinknameOnLine(pgf, atLine) 80205- parts := strings.Fields(directive) 80206- if len(parts) != 3 { 80207- return "", "" 80208- } 80209- 80210- // Inside 2nd arg [start, end]? 80211- end := column + len(directive) 80212- start := end - len(parts[2]) 80213- if !(start <= atColumn && atColumn <= end) { 80214- return "", "" 80215- } 80216- linkname := parts[2] 80217- 80218- // Split the pkg path from the name. 80219- dot := strings.LastIndexByte(linkname, '.') 80220- if dot < 0 { 80221- return "", "" 80222- } 80223- return linkname[:dot], linkname[dot+1:] 80224-} 80225- 80226-// findLinknameOnLine returns the first linkname directive on line and the column it starts at. 80227-// Returns "", 0 if no linkname directive is found on the line. 80228-func findLinknameOnLine(pgf *ParsedGoFile, line int) (string, int) { 80229- for _, grp := range pgf.File.Comments { 80230- for _, com := range grp.List { 80231- if strings.HasPrefix(com.Text, "//go:linkname") { 80232- p := safetoken.Position(pgf.Tok, com.Pos()) 80233- if p.Line == line { 80234- return com.Text, p.Column 80235- } 80236- } 80237- } 80238- } 80239- return "", 0 80240-} 80241- 80242-// findLinkname searches dependencies of packages containing fh for an object 80243-// with linker name matching the given package path and name. 80244-func findLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position, pkgPath PackagePath, name string) ([]protocol.Location, error) { 80245- // Typically the linkname refers to a forward dependency 80246- // or a reverse dependency, but in general it may refer 80247- // to any package in the workspace. 80248- var pkgMeta *Metadata 80249- metas, err := snapshot.AllMetadata(ctx) 80250- if err != nil { 80251- return nil, err 80252- } 80253- metas = RemoveIntermediateTestVariants(metas) 80254- for _, meta := range metas { 80255- if meta.PkgPath == pkgPath { 80256- pkgMeta = meta 80257- break 80258- } 80259- } 80260- if pkgMeta == nil { 80261- return nil, fmt.Errorf("cannot find package %q", pkgPath) 80262- } 80263- 80264- // When found, type check the desired package (snapshot.TypeCheck in TypecheckFull mode), 80265- pkgs, err := snapshot.TypeCheck(ctx, pkgMeta.ID) 80266- if err != nil { 80267- return nil, err 80268- } 80269- pkg := pkgs[0] 80270- 80271- obj := pkg.GetTypes().Scope().Lookup(name) 80272- if obj == nil { 80273- return nil, fmt.Errorf("package %q does not define %s", pkgPath, name) 80274- } 80275- 80276- objURI := safetoken.StartPosition(pkg.FileSet(), obj.Pos()) 80277- pgf, err := pkg.File(span.URIFromPath(objURI.Filename)) 80278- if err != nil { 80279- return nil, err 80280- } 80281- loc, err := pgf.PosLocation(obj.Pos(), obj.Pos()+token.Pos(len(name))) 80282- if err != nil { 80283- return nil, err 80284- } 80285- return []protocol.Location{loc}, nil 80286-} 80287diff -urN a/gopls/internal/lsp/source/methodsets/methodsets.go b/gopls/internal/lsp/source/methodsets/methodsets.go 80288--- a/gopls/internal/lsp/source/methodsets/methodsets.go 2000-01-01 00:00:00.000000000 -0000 80289+++ b/gopls/internal/lsp/source/methodsets/methodsets.go 1970-01-01 00:00:00.000000000 +0000 80290@@ -1,508 +0,0 @@ 80291-// Copyright 2023 The Go Authors. All rights reserved. 80292-// Use of this source code is governed by a BSD-style 80293-// license that can be found in the LICENSE file. 80294- 80295-// Package methodsets defines an incremental, serializable index of 80296-// method-set information that allows efficient 'implements' queries 80297-// across packages of the workspace without using the type checker. 80298-// 80299-// This package provides only the "global" (all workspace) search; the 80300-// "local" search within a given package uses a different 80301-// implementation based on type-checker data structures for a single 80302-// package plus variants; see ../implementation2.go. 80303-// The local algorithm is more precise as it tests function-local types too. 80304-// 80305-// A global index of function-local types is challenging since they 80306-// may reference other local types, for which we would need to invent 80307-// stable names, an unsolved problem described in passing in Go issue 80308-// 57497. The global algorithm also does not index anonymous interface 80309-// types, even outside function bodies. 80310-// 80311-// Consequently, global results are not symmetric: applying the 80312-// operation twice may not get you back where you started. 80313-package methodsets 80314- 80315-// DESIGN 80316-// 80317-// See https://go.dev/cl/452060 for a minimal exposition of the algorithm. 80318-// 80319-// For each method, we compute a fingerprint: a string representing 80320-// the method name and type such that equal fingerprint strings mean 80321-// identical method types. 80322-// 80323-// For efficiency, the fingerprint is reduced to a single bit 80324-// of a uint64, so that the method set can be represented as 80325-// the union of those method bits (a uint64 bitmask). 80326-// Assignability thus reduces to a subset check on bitmasks 80327-// followed by equality checks on fingerprints. 80328-// 80329-// In earlier experiments, using 128-bit masks instead of 64 reduced 80330-// the number of candidates by about 2x. Using (like a Bloom filter) a 80331-// different hash function to compute a second 64-bit mask and 80332-// performing a second mask test reduced it by about 4x. 80333-// Neither had much effect on the running time, presumably because a 80334-// single 64-bit mask is quite effective. See CL 452060 for details. 80335- 80336-import ( 80337- "bytes" 80338- "encoding/gob" 80339- "fmt" 80340- "go/token" 80341- "go/types" 80342- "hash/crc32" 80343- "log" 80344- "strconv" 80345- "strings" 80346- 80347- "golang.org/x/tools/go/types/objectpath" 80348- "golang.org/x/tools/gopls/internal/lsp/safetoken" 80349- "golang.org/x/tools/internal/typeparams" 80350- "golang.org/x/tools/internal/typesinternal" 80351-) 80352- 80353-// An Index records the non-empty method sets of all package-level 80354-// types in a package in a form that permits assignability queries 80355-// without the type checker. 80356-type Index struct { 80357- pkg gobPackage 80358-} 80359- 80360-// Decode decodes the given gob-encoded data as an Index. 80361-func Decode(data []byte) *Index { 80362- var pkg gobPackage 80363- mustDecode(data, &pkg) 80364- return &Index{pkg} 80365-} 80366- 80367-// Encode encodes the receiver as gob-encoded data. 80368-func (index *Index) Encode() []byte { 80369- return mustEncode(index.pkg) 80370-} 80371- 80372-func mustEncode(x interface{}) []byte { 80373- var buf bytes.Buffer 80374- if err := gob.NewEncoder(&buf).Encode(x); err != nil { 80375- log.Fatalf("internal error encoding %T: %v", x, err) 80376- } 80377- return buf.Bytes() 80378-} 80379- 80380-func mustDecode(data []byte, ptr interface{}) { 80381- if err := gob.NewDecoder(bytes.NewReader(data)).Decode(ptr); err != nil { 80382- log.Fatalf("internal error decoding %T: %v", ptr, err) 80383- } 80384-} 80385- 80386-// NewIndex returns a new index of method-set information for all 80387-// package-level types in the specified package. 80388-func NewIndex(fset *token.FileSet, pkg *types.Package) *Index { 80389- return new(indexBuilder).build(fset, pkg) 80390-} 80391- 80392-// A Location records the extent of an identifier in byte-offset form. 80393-// 80394-// Conversion to protocol (UTF-16) form is done by the caller after a 80395-// search, not during index construction. 80396-type Location struct { 80397- Filename string 80398- Start, End int // byte offsets 80399-} 80400- 80401-// A Key represents the method set of a given type in a form suitable 80402-// to pass to the (*Index).Search method of many different Indexes. 80403-type Key struct { 80404- mset gobMethodSet // note: lacks position information 80405-} 80406- 80407-// KeyOf returns the search key for the method sets of a given type. 80408-// It returns false if the type has no methods. 80409-func KeyOf(t types.Type) (Key, bool) { 80410- mset := methodSetInfo(t, nil) 80411- if mset.Mask == 0 { 80412- return Key{}, false // no methods 80413- } 80414- return Key{mset}, true 80415-} 80416- 80417-// A Result reports a matching type or method in a method-set search. 80418-type Result struct { 80419- Location Location // location of the type or method 80420- 80421- // methods only: 80422- PkgPath string // path of declaring package (may differ due to embedding) 80423- ObjectPath objectpath.Path // path of method within declaring package 80424-} 80425- 80426-// Search reports each type that implements (or is implemented by) the 80427-// type that produced the search key. If methodID is nonempty, only 80428-// that method of each type is reported. 80429-// 80430-// The result does not include the error.Error method. 80431-// TODO(adonovan): give this special case a more systematic treatment. 80432-func (index *Index) Search(key Key, methodID string) []Result { 80433- var results []Result 80434- for _, candidate := range index.pkg.MethodSets { 80435- // Traditionally this feature doesn't report 80436- // interface/interface elements of the relation. 80437- // I think that's a mistake. 80438- // TODO(adonovan): UX: change it, here and in the local implementation. 80439- if candidate.IsInterface && key.mset.IsInterface { 80440- continue 80441- } 80442- if !satisfies(candidate, key.mset) && !satisfies(key.mset, candidate) { 80443- continue 80444- } 80445- 80446- if candidate.Tricky { 80447- // If any interface method is tricky then extra 80448- // checking may be needed to eliminate a false positive. 80449- // TODO(adonovan): implement it. 80450- } 80451- 80452- if methodID == "" { 80453- results = append(results, Result{Location: index.location(candidate.Posn)}) 80454- } else { 80455- for _, m := range candidate.Methods { 80456- // Here we exploit knowledge of the shape of the fingerprint string. 80457- if strings.HasPrefix(m.Fingerprint, methodID) && 80458- m.Fingerprint[len(methodID)] == '(' { 80459- 80460- // Don't report error.Error among the results: 80461- // it has no true source location, no package, 80462- // and is excluded from the xrefs index. 80463- if m.PkgPath == 0 || m.ObjectPath == 0 { 80464- if methodID != "Error" { 80465- panic("missing info for" + methodID) 80466- } 80467- continue 80468- } 80469- 80470- results = append(results, Result{ 80471- Location: index.location(m.Posn), 80472- PkgPath: index.pkg.Strings[m.PkgPath], 80473- ObjectPath: objectpath.Path(index.pkg.Strings[m.ObjectPath]), 80474- }) 80475- break 80476- } 80477- } 80478- } 80479- } 80480- return results 80481-} 80482- 80483-// satisfies does a fast check for whether x satisfies y. 80484-func satisfies(x, y gobMethodSet) bool { 80485- return y.IsInterface && x.Mask&y.Mask == y.Mask && subset(y, x) 80486-} 80487- 80488-// subset reports whether method set x is a subset of y. 80489-func subset(x, y gobMethodSet) bool { 80490-outer: 80491- for _, mx := range x.Methods { 80492- for _, my := range y.Methods { 80493- if mx.Sum == my.Sum && mx.Fingerprint == my.Fingerprint { 80494- continue outer // found; try next x method 80495- } 80496- } 80497- return false // method of x not found in y 80498- } 80499- return true // all methods of x found in y 80500-} 80501- 80502-func (index *Index) location(posn gobPosition) Location { 80503- return Location{ 80504- Filename: index.pkg.Strings[posn.File], 80505- Start: posn.Offset, 80506- End: posn.Offset + posn.Len, 80507- } 80508-} 80509- 80510-// An indexBuilder builds an index for a single package. 80511-type indexBuilder struct { 80512- gobPackage 80513- stringIndex map[string]int 80514-} 80515- 80516-// build adds to the index all package-level named types of the specified package. 80517-func (b *indexBuilder) build(fset *token.FileSet, pkg *types.Package) *Index { 80518- _ = b.string("") // 0 => "" 80519- 80520- objectPos := func(obj types.Object) gobPosition { 80521- posn := safetoken.StartPosition(fset, obj.Pos()) 80522- return gobPosition{b.string(posn.Filename), posn.Offset, len(obj.Name())} 80523- } 80524- 80525- objectpathFor := typesinternal.NewObjectpathFunc() 80526- 80527- // setindexInfo sets the (Posn, PkgPath, ObjectPath) fields for each method declaration. 80528- setIndexInfo := func(m *gobMethod, method *types.Func) { 80529- // error.Error has empty Position, PkgPath, and ObjectPath. 80530- if method.Pkg() == nil { 80531- return 80532- } 80533- 80534- m.Posn = objectPos(method) 80535- m.PkgPath = b.string(method.Pkg().Path()) 80536- 80537- // Instantiations of generic methods don't have an 80538- // object path, so we use the generic. 80539- if p, err := objectpathFor(typeparams.OriginMethod(method)); err != nil { 80540- panic(err) // can't happen for a method of a package-level type 80541- } else { 80542- m.ObjectPath = b.string(string(p)) 80543- } 80544- } 80545- 80546- // We ignore aliases, though in principle they could define a 80547- // struct{...} or interface{...} type, or an instantiation of 80548- // a generic, that has a novel method set. 80549- scope := pkg.Scope() 80550- for _, name := range scope.Names() { 80551- if tname, ok := scope.Lookup(name).(*types.TypeName); ok && !tname.IsAlias() { 80552- if mset := methodSetInfo(tname.Type(), setIndexInfo); mset.Mask != 0 { 80553- mset.Posn = objectPos(tname) 80554- // Only record types with non-trivial method sets. 80555- b.MethodSets = append(b.MethodSets, mset) 80556- } 80557- } 80558- } 80559- 80560- return &Index{pkg: b.gobPackage} 80561-} 80562- 80563-// string returns a small integer that encodes the string. 80564-func (b *indexBuilder) string(s string) int { 80565- i, ok := b.stringIndex[s] 80566- if !ok { 80567- i = len(b.Strings) 80568- if b.stringIndex == nil { 80569- b.stringIndex = make(map[string]int) 80570- } 80571- b.stringIndex[s] = i 80572- b.Strings = append(b.Strings, s) 80573- } 80574- return i 80575-} 80576- 80577-// methodSetInfo returns the method-set fingerprint of a type. 80578-// It calls the optional setIndexInfo function for each gobMethod. 80579-// This is used during index construction, but not search (KeyOf), 80580-// to store extra information. 80581-func methodSetInfo(t types.Type, setIndexInfo func(*gobMethod, *types.Func)) gobMethodSet { 80582- // For non-interface types, use *T 80583- // (if T is not already a pointer) 80584- // since it may have more methods. 80585- mset := types.NewMethodSet(EnsurePointer(t)) 80586- 80587- // Convert the method set into a compact summary. 80588- var mask uint64 80589- tricky := false 80590- methods := make([]gobMethod, mset.Len()) 80591- for i := 0; i < mset.Len(); i++ { 80592- m := mset.At(i).Obj().(*types.Func) 80593- fp, isTricky := fingerprint(m) 80594- if isTricky { 80595- tricky = true 80596- } 80597- sum := crc32.ChecksumIEEE([]byte(fp)) 80598- methods[i] = gobMethod{Fingerprint: fp, Sum: sum} 80599- if setIndexInfo != nil { 80600- setIndexInfo(&methods[i], m) // set Position, PkgPath, ObjectPath 80601- } 80602- mask |= 1 << uint64(((sum>>24)^(sum>>16)^(sum>>8)^sum)&0x3f) 80603- } 80604- return gobMethodSet{ 80605- IsInterface: types.IsInterface(t), 80606- Tricky: tricky, 80607- Mask: mask, 80608- Methods: methods, 80609- } 80610-} 80611- 80612-// EnsurePointer wraps T in a types.Pointer if T is a named, non-interface type. 80613-// This is useful to make sure you consider a named type's full method set. 80614-func EnsurePointer(T types.Type) types.Type { 80615- if _, ok := T.(*types.Named); ok && !types.IsInterface(T) { 80616- return types.NewPointer(T) 80617- } 80618- 80619- return T 80620-} 80621- 80622-// fingerprint returns an encoding of a method signature such that two 80623-// methods with equal encodings have identical types, except for a few 80624-// tricky types whose encodings may spuriously match and whose exact 80625-// identity computation requires the type checker to eliminate false 80626-// positives (which are rare). The boolean result indicates whether 80627-// the result was one of these tricky types. 80628-// 80629-// In the standard library, 99.8% of package-level types have a 80630-// non-tricky method-set. The most common exceptions are due to type 80631-// parameters. 80632-// 80633-// The fingerprint string starts with method.Id() + "(". 80634-func fingerprint(method *types.Func) (string, bool) { 80635- var buf strings.Builder 80636- tricky := false 80637- var fprint func(t types.Type) 80638- fprint = func(t types.Type) { 80639- switch t := t.(type) { 80640- case *types.Named: 80641- tname := t.Obj() 80642- if tname.Pkg() != nil { 80643- buf.WriteString(strconv.Quote(tname.Pkg().Path())) 80644- buf.WriteByte('.') 80645- } else if tname.Name() != "error" { 80646- panic(tname) // error is the only named type with no package 80647- } 80648- buf.WriteString(tname.Name()) 80649- 80650- case *types.Array: 80651- fmt.Fprintf(&buf, "[%d]", t.Len()) 80652- fprint(t.Elem()) 80653- 80654- case *types.Slice: 80655- buf.WriteString("[]") 80656- fprint(t.Elem()) 80657- 80658- case *types.Pointer: 80659- buf.WriteByte('*') 80660- fprint(t.Elem()) 80661- 80662- case *types.Map: 80663- buf.WriteString("map[") 80664- fprint(t.Key()) 80665- buf.WriteByte(']') 80666- fprint(t.Elem()) 80667- 80668- case *types.Chan: 80669- switch t.Dir() { 80670- case types.SendRecv: 80671- buf.WriteString("chan ") 80672- case types.SendOnly: 80673- buf.WriteString("<-chan ") 80674- case types.RecvOnly: 80675- buf.WriteString("chan<- ") 80676- } 80677- fprint(t.Elem()) 80678- 80679- case *types.Tuple: 80680- buf.WriteByte('(') 80681- for i := 0; i < t.Len(); i++ { 80682- if i > 0 { 80683- buf.WriteByte(',') 80684- } 80685- fprint(t.At(i).Type()) 80686- } 80687- buf.WriteByte(')') 80688- 80689- case *types.Basic: 80690- // Use canonical names for uint8 and int32 aliases. 80691- switch t.Kind() { 80692- case types.Byte: 80693- buf.WriteString("byte") 80694- case types.Rune: 80695- buf.WriteString("rune") 80696- default: 80697- buf.WriteString(t.String()) 80698- } 80699- 80700- case *types.Signature: 80701- buf.WriteString("func") 80702- fprint(t.Params()) 80703- if t.Variadic() { 80704- buf.WriteString("...") // not quite Go syntax 80705- } 80706- fprint(t.Results()) 80707- 80708- case *types.Struct: 80709- // Non-empty unnamed struct types in method 80710- // signatures are vanishingly rare. 80711- buf.WriteString("struct{") 80712- for i := 0; i < t.NumFields(); i++ { 80713- if i > 0 { 80714- buf.WriteByte(';') 80715- } 80716- f := t.Field(i) 80717- // This isn't quite right for embedded type aliases. 80718- // (See types.TypeString(StructType) and #44410 for context.) 80719- // But this is vanishingly rare. 80720- if !f.Embedded() { 80721- buf.WriteString(f.Id()) 80722- buf.WriteByte(' ') 80723- } 80724- fprint(f.Type()) 80725- if tag := t.Tag(i); tag != "" { 80726- buf.WriteByte(' ') 80727- buf.WriteString(strconv.Quote(tag)) 80728- } 80729- } 80730- buf.WriteString("}") 80731- 80732- case *types.Interface: 80733- if t.NumMethods() == 0 { 80734- buf.WriteString("any") // common case 80735- } else { 80736- // Interface assignability is particularly 80737- // tricky due to the possibility of recursion. 80738- tricky = true 80739- // We could still give more disambiguating precision 80740- // than "..." if we wanted to. 80741- buf.WriteString("interface{...}") 80742- } 80743- 80744- case *typeparams.TypeParam: 80745- tricky = true 80746- // TODO(adonovan): refine this by adding a numeric suffix 80747- // indicating the index among the receiver type's parameters. 80748- buf.WriteByte('?') 80749- 80750- default: // incl. *types.Union 80751- panic(t) 80752- } 80753- } 80754- 80755- buf.WriteString(method.Id()) // e.g. "pkg.Type" 80756- sig := method.Type().(*types.Signature) 80757- fprint(sig.Params()) 80758- fprint(sig.Results()) 80759- return buf.String(), tricky 80760-} 80761- 80762-// -- serial format of index -- 80763- 80764-// The cost of gob encoding and decoding for most packages in x/tools 80765-// is under 50us, with occasional peaks of around 1-3ms. 80766-// The encoded indexes are around 1KB-50KB. 80767- 80768-// A gobPackage records the method set of each package-level type for a single package. 80769-type gobPackage struct { 80770- Strings []string // index of strings used by gobPosition.File, gobMethod.{Pkg,Object}Path 80771- MethodSets []gobMethodSet 80772-} 80773- 80774-// A gobMethodSet records the method set of a single type. 80775-type gobMethodSet struct { 80776- Posn gobPosition 80777- IsInterface bool 80778- Tricky bool // at least one method is tricky; assignability requires go/types 80779- Mask uint64 // mask with 1 bit from each of methods[*].sum 80780- Methods []gobMethod 80781-} 80782- 80783-// A gobMethod records the name, type, and position of a single method. 80784-type gobMethod struct { 80785- Fingerprint string // string of form "methodID(params...)(results)" 80786- Sum uint32 // checksum of fingerprint 80787- 80788- // index records only (zero in KeyOf; also for index of error.Error). 80789- Posn gobPosition // location of method declaration 80790- PkgPath int // path of package containing method declaration 80791- ObjectPath int // object path of method relative to PkgPath 80792-} 80793- 80794-// A gobPosition records the file, offset, and length of an identifier. 80795-type gobPosition struct { 80796- File int // index into gobPackage.Strings 80797- Offset, Len int // in bytes 80798-} 80799diff -urN a/gopls/internal/lsp/source/options.go b/gopls/internal/lsp/source/options.go 80800--- a/gopls/internal/lsp/source/options.go 2000-01-01 00:00:00.000000000 -0000 80801+++ b/gopls/internal/lsp/source/options.go 1970-01-01 00:00:00.000000000 +0000 80802@@ -1,1631 +0,0 @@ 80803-// Copyright 2019 The Go Authors. All rights reserved. 80804-// Use of this source code is governed by a BSD-style 80805-// license that can be found in the LICENSE file. 80806- 80807-package source 80808- 80809-import ( 80810- "context" 80811- "fmt" 80812- "io" 80813- "path/filepath" 80814- "regexp" 80815- "runtime" 80816- "strings" 80817- "sync" 80818- "time" 80819- 80820- "golang.org/x/tools/go/analysis" 80821- "golang.org/x/tools/go/analysis/passes/asmdecl" 80822- "golang.org/x/tools/go/analysis/passes/assign" 80823- "golang.org/x/tools/go/analysis/passes/atomic" 80824- "golang.org/x/tools/go/analysis/passes/atomicalign" 80825- "golang.org/x/tools/go/analysis/passes/bools" 80826- "golang.org/x/tools/go/analysis/passes/buildtag" 80827- "golang.org/x/tools/go/analysis/passes/cgocall" 80828- "golang.org/x/tools/go/analysis/passes/composite" 80829- "golang.org/x/tools/go/analysis/passes/copylock" 80830- "golang.org/x/tools/go/analysis/passes/deepequalerrors" 80831- "golang.org/x/tools/go/analysis/passes/directive" 80832- "golang.org/x/tools/go/analysis/passes/errorsas" 80833- "golang.org/x/tools/go/analysis/passes/fieldalignment" 80834- "golang.org/x/tools/go/analysis/passes/httpresponse" 80835- "golang.org/x/tools/go/analysis/passes/ifaceassert" 80836- "golang.org/x/tools/go/analysis/passes/loopclosure" 80837- "golang.org/x/tools/go/analysis/passes/lostcancel" 80838- "golang.org/x/tools/go/analysis/passes/nilfunc" 80839- "golang.org/x/tools/go/analysis/passes/nilness" 80840- "golang.org/x/tools/go/analysis/passes/printf" 80841- "golang.org/x/tools/go/analysis/passes/shadow" 80842- "golang.org/x/tools/go/analysis/passes/shift" 80843- "golang.org/x/tools/go/analysis/passes/sortslice" 80844- "golang.org/x/tools/go/analysis/passes/stdmethods" 80845- "golang.org/x/tools/go/analysis/passes/stringintconv" 80846- "golang.org/x/tools/go/analysis/passes/structtag" 80847- "golang.org/x/tools/go/analysis/passes/testinggoroutine" 80848- "golang.org/x/tools/go/analysis/passes/tests" 80849- "golang.org/x/tools/go/analysis/passes/timeformat" 80850- "golang.org/x/tools/go/analysis/passes/unmarshal" 80851- "golang.org/x/tools/go/analysis/passes/unreachable" 80852- "golang.org/x/tools/go/analysis/passes/unsafeptr" 80853- "golang.org/x/tools/go/analysis/passes/unusedresult" 80854- "golang.org/x/tools/go/analysis/passes/unusedwrite" 80855- "golang.org/x/tools/gopls/internal/lsp/analysis/embeddirective" 80856- "golang.org/x/tools/gopls/internal/lsp/analysis/fillreturns" 80857- "golang.org/x/tools/gopls/internal/lsp/analysis/fillstruct" 80858- "golang.org/x/tools/gopls/internal/lsp/analysis/infertypeargs" 80859- "golang.org/x/tools/gopls/internal/lsp/analysis/nonewvars" 80860- "golang.org/x/tools/gopls/internal/lsp/analysis/noresultvalues" 80861- "golang.org/x/tools/gopls/internal/lsp/analysis/simplifycompositelit" 80862- "golang.org/x/tools/gopls/internal/lsp/analysis/simplifyrange" 80863- "golang.org/x/tools/gopls/internal/lsp/analysis/simplifyslice" 80864- "golang.org/x/tools/gopls/internal/lsp/analysis/stubmethods" 80865- "golang.org/x/tools/gopls/internal/lsp/analysis/undeclaredname" 80866- "golang.org/x/tools/gopls/internal/lsp/analysis/unusedparams" 80867- "golang.org/x/tools/gopls/internal/lsp/analysis/unusedvariable" 80868- "golang.org/x/tools/gopls/internal/lsp/analysis/useany" 80869- "golang.org/x/tools/gopls/internal/lsp/command" 80870- "golang.org/x/tools/gopls/internal/lsp/protocol" 80871- "golang.org/x/tools/internal/diff" 80872- "golang.org/x/tools/internal/diff/myers" 80873-) 80874- 80875-var ( 80876- optionsOnce sync.Once 80877- defaultOptions *Options 80878-) 80879- 80880-// DefaultOptions is the options that are used for Gopls execution independent 80881-// of any externally provided configuration (LSP initialization, command 80882-// invocation, etc.). 80883-func DefaultOptions() *Options { 80884- optionsOnce.Do(func() { 80885- var commands []string 80886- for _, c := range command.Commands { 80887- commands = append(commands, c.ID()) 80888- } 80889- defaultOptions = &Options{ 80890- ClientOptions: ClientOptions{ 80891- InsertTextFormat: protocol.PlainTextTextFormat, 80892- PreferredContentFormat: protocol.Markdown, 80893- ConfigurationSupported: true, 80894- DynamicConfigurationSupported: true, 80895- DynamicRegistrationSemanticTokensSupported: true, 80896- DynamicWatchedFilesSupported: true, 80897- LineFoldingOnly: false, 80898- HierarchicalDocumentSymbolSupport: true, 80899- }, 80900- ServerOptions: ServerOptions{ 80901- SupportedCodeActions: map[FileKind]map[protocol.CodeActionKind]bool{ 80902- Go: { 80903- protocol.SourceFixAll: true, 80904- protocol.SourceOrganizeImports: true, 80905- protocol.QuickFix: true, 80906- protocol.RefactorRewrite: true, 80907- protocol.RefactorExtract: true, 80908- }, 80909- Mod: { 80910- protocol.SourceOrganizeImports: true, 80911- protocol.QuickFix: true, 80912- }, 80913- Work: {}, 80914- Sum: {}, 80915- Tmpl: {}, 80916- }, 80917- SupportedCommands: commands, 80918- }, 80919- UserOptions: UserOptions{ 80920- BuildOptions: BuildOptions{ 80921- ExpandWorkspaceToModule: true, 80922- MemoryMode: ModeNormal, 80923- DirectoryFilters: []string{"-**/node_modules"}, 80924- TemplateExtensions: []string{}, 80925- StandaloneTags: []string{"ignore"}, 80926- }, 80927- UIOptions: UIOptions{ 80928- DiagnosticOptions: DiagnosticOptions{ 80929- DiagnosticsDelay: 250 * time.Millisecond, 80930- Annotations: map[Annotation]bool{ 80931- Bounds: true, 80932- Escape: true, 80933- Inline: true, 80934- Nil: true, 80935- }, 80936- Vulncheck: ModeVulncheckOff, 80937- }, 80938- InlayHintOptions: InlayHintOptions{}, 80939- DocumentationOptions: DocumentationOptions{ 80940- HoverKind: FullDocumentation, 80941- LinkTarget: "pkg.go.dev", 80942- LinksInHover: true, 80943- }, 80944- NavigationOptions: NavigationOptions{ 80945- ImportShortcut: BothShortcuts, 80946- SymbolMatcher: SymbolFastFuzzy, 80947- SymbolStyle: DynamicSymbols, 80948- }, 80949- CompletionOptions: CompletionOptions{ 80950- Matcher: Fuzzy, 80951- CompletionBudget: 100 * time.Millisecond, 80952- ExperimentalPostfixCompletions: true, 80953- }, 80954- Codelenses: map[string]bool{ 80955- string(command.Generate): true, 80956- string(command.RegenerateCgo): true, 80957- string(command.Tidy): true, 80958- string(command.GCDetails): false, 80959- string(command.UpgradeDependency): true, 80960- string(command.Vendor): true, 80961- // TODO(hyangah): enable command.RunGovulncheck. 80962- }, 80963- }, 80964- }, 80965- InternalOptions: InternalOptions{ 80966- LiteralCompletions: true, 80967- TempModfile: true, 80968- CompleteUnimported: true, 80969- CompletionDocumentation: true, 80970- DeepCompletion: true, 80971- ChattyDiagnostics: true, 80972- NewDiff: "both", 80973- }, 80974- Hooks: Hooks{ 80975- // TODO(adonovan): switch to new diff.Strings implementation. 80976- ComputeEdits: myers.ComputeEdits, 80977- URLRegexp: urlRegexp(), 80978- DefaultAnalyzers: defaultAnalyzers(), 80979- TypeErrorAnalyzers: typeErrorAnalyzers(), 80980- ConvenienceAnalyzers: convenienceAnalyzers(), 80981- StaticcheckAnalyzers: map[string]*Analyzer{}, 80982- GoDiff: true, 80983- }, 80984- } 80985- }) 80986- return defaultOptions 80987-} 80988- 80989-// Options holds various configuration that affects Gopls execution, organized 80990-// by the nature or origin of the settings. 80991-type Options struct { 80992- ClientOptions 80993- ServerOptions 80994- UserOptions 80995- InternalOptions 80996- Hooks 80997-} 80998- 80999-// ClientOptions holds LSP-specific configuration that is provided by the 81000-// client. 81001-type ClientOptions struct { 81002- InsertTextFormat protocol.InsertTextFormat 81003- ConfigurationSupported bool 81004- DynamicConfigurationSupported bool 81005- DynamicRegistrationSemanticTokensSupported bool 81006- DynamicWatchedFilesSupported bool 81007- PreferredContentFormat protocol.MarkupKind 81008- LineFoldingOnly bool 81009- HierarchicalDocumentSymbolSupport bool 81010- SemanticTypes []string 81011- SemanticMods []string 81012- RelatedInformationSupported bool 81013- CompletionTags bool 81014- CompletionDeprecated bool 81015- SupportedResourceOperations []protocol.ResourceOperationKind 81016-} 81017- 81018-// ServerOptions holds LSP-specific configuration that is provided by the 81019-// server. 81020-type ServerOptions struct { 81021- SupportedCodeActions map[FileKind]map[protocol.CodeActionKind]bool 81022- SupportedCommands []string 81023-} 81024- 81025-type BuildOptions struct { 81026- // BuildFlags is the set of flags passed on to the build system when invoked. 81027- // It is applied to queries like `go list`, which is used when discovering files. 81028- // The most common use is to set `-tags`. 81029- BuildFlags []string 81030- 81031- // Env adds environment variables to external commands run by `gopls`, most notably `go list`. 81032- Env map[string]string 81033- 81034- // DirectoryFilters can be used to exclude unwanted directories from the 81035- // workspace. By default, all directories are included. Filters are an 81036- // operator, `+` to include and `-` to exclude, followed by a path prefix 81037- // relative to the workspace folder. They are evaluated in order, and 81038- // the last filter that applies to a path controls whether it is included. 81039- // The path prefix can be empty, so an initial `-` excludes everything. 81040- // 81041- // DirectoryFilters also supports the `**` operator to match 0 or more directories. 81042- // 81043- // Examples: 81044- // 81045- // Exclude node_modules at current depth: `-node_modules` 81046- // 81047- // Exclude node_modules at any depth: `-**/node_modules` 81048- // 81049- // Include only project_a: `-` (exclude everything), `+project_a` 81050- // 81051- // Include only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules` 81052- DirectoryFilters []string 81053- 81054- // TemplateExtensions gives the extensions of file names that are treateed 81055- // as template files. (The extension 81056- // is the part of the file name after the final dot.) 81057- TemplateExtensions []string 81058- 81059- // MemoryMode controls the tradeoff `gopls` makes between memory usage and 81060- // correctness. 81061- // 81062- // Values other than `Normal` are untested and may break in surprising ways. 81063- MemoryMode MemoryMode `status:"experimental"` 81064- 81065- // ExpandWorkspaceToModule instructs `gopls` to adjust the scope of the 81066- // workspace to find the best available module root. `gopls` first looks for 81067- // a go.mod file in any parent directory of the workspace folder, expanding 81068- // the scope to that directory if it exists. If no viable parent directory is 81069- // found, gopls will check if there is exactly one child directory containing 81070- // a go.mod file, narrowing the scope to that directory if it exists. 81071- ExpandWorkspaceToModule bool `status:"experimental"` 81072- 81073- // AllowModfileModifications disables -mod=readonly, allowing imports from 81074- // out-of-scope modules. This option will eventually be removed. 81075- AllowModfileModifications bool `status:"experimental"` 81076- 81077- // AllowImplicitNetworkAccess disables GOPROXY=off, allowing implicit module 81078- // downloads rather than requiring user action. This option will eventually 81079- // be removed. 81080- AllowImplicitNetworkAccess bool `status:"experimental"` 81081- 81082- // StandaloneTags specifies a set of build constraints that identify 81083- // individual Go source files that make up the entire main package of an 81084- // executable. 81085- // 81086- // A common example of standalone main files is the convention of using the 81087- // directive `//go:build ignore` to denote files that are not intended to be 81088- // included in any package, for example because they are invoked directly by 81089- // the developer using `go run`. 81090- // 81091- // Gopls considers a file to be a standalone main file if and only if it has 81092- // package name "main" and has a build directive of the exact form 81093- // "//go:build tag" or "// +build tag", where tag is among the list of tags 81094- // configured by this setting. Notably, if the build constraint is more 81095- // complicated than a simple tag (such as the composite constraint 81096- // `//go:build tag && go1.18`), the file is not considered to be a standalone 81097- // main file. 81098- // 81099- // This setting is only supported when gopls is built with Go 1.16 or later. 81100- StandaloneTags []string 81101-} 81102- 81103-type UIOptions struct { 81104- DocumentationOptions 81105- CompletionOptions 81106- NavigationOptions 81107- DiagnosticOptions 81108- InlayHintOptions 81109- 81110- // Codelenses overrides the enabled/disabled state of code lenses. See the 81111- // "Code Lenses" section of the 81112- // [Settings page](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#code-lenses) 81113- // for the list of supported lenses. 81114- // 81115- // Example Usage: 81116- // 81117- // ```json5 81118- // "gopls": { 81119- // ... 81120- // "codelenses": { 81121- // "generate": false, // Don't show the `go generate` lens. 81122- // "gc_details": true // Show a code lens toggling the display of gc's choices. 81123- // } 81124- // ... 81125- // } 81126- // ``` 81127- Codelenses map[string]bool 81128- 81129- // SemanticTokens controls whether the LSP server will send 81130- // semantic tokens to the client. 81131- SemanticTokens bool `status:"experimental"` 81132- 81133- // NoSemanticString turns off the sending of the semantic token 'string' 81134- NoSemanticString bool `status:"experimental"` 81135- 81136- // NoSemanticNumber turns off the sending of the semantic token 'number' 81137- NoSemanticNumber bool `status:"experimental"` 81138-} 81139- 81140-type CompletionOptions struct { 81141- // Placeholders enables placeholders for function parameters or struct 81142- // fields in completion responses. 81143- UsePlaceholders bool 81144- 81145- // CompletionBudget is the soft latency goal for completion requests. Most 81146- // requests finish in a couple milliseconds, but in some cases deep 81147- // completions can take much longer. As we use up our budget we 81148- // dynamically reduce the search scope to ensure we return timely 81149- // results. Zero means unlimited. 81150- CompletionBudget time.Duration `status:"debug"` 81151- 81152- // Matcher sets the algorithm that is used when calculating completion 81153- // candidates. 81154- Matcher Matcher `status:"advanced"` 81155- 81156- // ExperimentalPostfixCompletions enables artificial method snippets 81157- // such as "someSlice.sort!". 81158- ExperimentalPostfixCompletions bool `status:"experimental"` 81159-} 81160- 81161-type DocumentationOptions struct { 81162- // HoverKind controls the information that appears in the hover text. 81163- // SingleLine and Structured are intended for use only by authors of editor plugins. 81164- HoverKind HoverKind 81165- 81166- // LinkTarget controls where documentation links go. 81167- // It might be one of: 81168- // 81169- // * `"godoc.org"` 81170- // * `"pkg.go.dev"` 81171- // 81172- // If company chooses to use its own `godoc.org`, its address can be used as well. 81173- // 81174- // Modules matching the GOPRIVATE environment variable will not have 81175- // documentation links in hover. 81176- LinkTarget string 81177- 81178- // LinksInHover toggles the presence of links to documentation in hover. 81179- LinksInHover bool 81180-} 81181- 81182-type FormattingOptions struct { 81183- // Local is the equivalent of the `goimports -local` flag, which puts 81184- // imports beginning with this string after third-party packages. It should 81185- // be the prefix of the import path whose imports should be grouped 81186- // separately. 81187- Local string 81188- 81189- // Gofumpt indicates if we should run gofumpt formatting. 81190- Gofumpt bool 81191-} 81192- 81193-type DiagnosticOptions struct { 81194- // Analyses specify analyses that the user would like to enable or disable. 81195- // A map of the names of analysis passes that should be enabled/disabled. 81196- // A full list of analyzers that gopls uses can be found in 81197- // [analyzers.md](https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md). 81198- // 81199- // Example Usage: 81200- // 81201- // ```json5 81202- // ... 81203- // "analyses": { 81204- // "unreachable": false, // Disable the unreachable analyzer. 81205- // "unusedparams": true // Enable the unusedparams analyzer. 81206- // } 81207- // ... 81208- // ``` 81209- Analyses map[string]bool 81210- 81211- // Staticcheck enables additional analyses from staticcheck.io. 81212- // These analyses are documented on 81213- // [Staticcheck's website](https://staticcheck.io/docs/checks/). 81214- Staticcheck bool `status:"experimental"` 81215- 81216- // Annotations specifies the various kinds of optimization diagnostics 81217- // that should be reported by the gc_details command. 81218- Annotations map[Annotation]bool `status:"experimental"` 81219- 81220- // Vulncheck enables vulnerability scanning. 81221- Vulncheck VulncheckMode `status:"experimental"` 81222- 81223- // DiagnosticsDelay controls the amount of time that gopls waits 81224- // after the most recent file modification before computing deep diagnostics. 81225- // Simple diagnostics (parsing and type-checking) are always run immediately 81226- // on recently modified packages. 81227- // 81228- // This option must be set to a valid duration string, for example `"250ms"`. 81229- DiagnosticsDelay time.Duration `status:"advanced"` 81230-} 81231- 81232-type InlayHintOptions struct { 81233- // Hints specify inlay hints that users want to see. A full list of hints 81234- // that gopls uses can be found in 81235- // [inlayHints.md](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md). 81236- Hints map[string]bool `status:"experimental"` 81237-} 81238- 81239-type NavigationOptions struct { 81240- // ImportShortcut specifies whether import statements should link to 81241- // documentation or go to definitions. 81242- ImportShortcut ImportShortcut 81243- 81244- // SymbolMatcher sets the algorithm that is used when finding workspace symbols. 81245- SymbolMatcher SymbolMatcher `status:"advanced"` 81246- 81247- // SymbolStyle controls how symbols are qualified in symbol responses. 81248- // 81249- // Example Usage: 81250- // 81251- // ```json5 81252- // "gopls": { 81253- // ... 81254- // "symbolStyle": "Dynamic", 81255- // ... 81256- // } 81257- // ``` 81258- SymbolStyle SymbolStyle `status:"advanced"` 81259-} 81260- 81261-// UserOptions holds custom Gopls configuration (not part of the LSP) that is 81262-// modified by the client. 81263-type UserOptions struct { 81264- BuildOptions 81265- UIOptions 81266- FormattingOptions 81267- 81268- // VerboseOutput enables additional debug logging. 81269- VerboseOutput bool `status:"debug"` 81270-} 81271- 81272-// EnvSlice returns Env as a slice of k=v strings. 81273-func (u *UserOptions) EnvSlice() []string { 81274- var result []string 81275- for k, v := range u.Env { 81276- result = append(result, fmt.Sprintf("%v=%v", k, v)) 81277- } 81278- return result 81279-} 81280- 81281-// SetEnvSlice sets Env from a slice of k=v strings. 81282-func (u *UserOptions) SetEnvSlice(env []string) { 81283- u.Env = map[string]string{} 81284- for _, kv := range env { 81285- split := strings.SplitN(kv, "=", 2) 81286- if len(split) != 2 { 81287- continue 81288- } 81289- u.Env[split[0]] = split[1] 81290- } 81291-} 81292- 81293-// DiffFunction is the type for a function that produces a set of edits that 81294-// convert from the before content to the after content. 81295-type DiffFunction func(before, after string) []diff.Edit 81296- 81297-// Hooks contains configuration that is provided to the Gopls command by the 81298-// main package. 81299-type Hooks struct { 81300- // LicensesText holds third party licenses for software used by gopls. 81301- LicensesText string 81302- 81303- // GoDiff is used in gopls/hooks to get Myers' diff 81304- GoDiff bool 81305- 81306- // Whether staticcheck is supported. 81307- StaticcheckSupported bool 81308- 81309- // ComputeEdits is used to compute edits between file versions. 81310- ComputeEdits DiffFunction 81311- 81312- // URLRegexp is used to find potential URLs in comments/strings. 81313- // 81314- // Not all matches are shown to the user: if the matched URL is not detected 81315- // as valid, it will be skipped. 81316- URLRegexp *regexp.Regexp 81317- 81318- // GofumptFormat allows the gopls module to wire-in a call to 81319- // gofumpt/format.Source. langVersion and modulePath are used for some 81320- // Gofumpt formatting rules -- see the Gofumpt documentation for details. 81321- GofumptFormat func(ctx context.Context, langVersion, modulePath string, src []byte) ([]byte, error) 81322- 81323- DefaultAnalyzers map[string]*Analyzer 81324- TypeErrorAnalyzers map[string]*Analyzer 81325- ConvenienceAnalyzers map[string]*Analyzer 81326- StaticcheckAnalyzers map[string]*Analyzer 81327-} 81328- 81329-// InternalOptions contains settings that are not intended for use by the 81330-// average user. These may be settings used by tests or outdated settings that 81331-// will soon be deprecated. Some of these settings may not even be configurable 81332-// by the user. 81333-type InternalOptions struct { 81334- // LiteralCompletions controls whether literal candidates such as 81335- // "&someStruct{}" are offered. Tests disable this flag to simplify 81336- // their expected values. 81337- LiteralCompletions bool 81338- 81339- // VerboseWorkDoneProgress controls whether the LSP server should send 81340- // progress reports for all work done outside the scope of an RPC. 81341- // Used by the regression tests. 81342- VerboseWorkDoneProgress bool 81343- 81344- // The following options were previously available to users, but they 81345- // really shouldn't be configured by anyone other than "power users". 81346- 81347- // CompletionDocumentation enables documentation with completion results. 81348- CompletionDocumentation bool 81349- 81350- // CompleteUnimported enables completion for packages that you do not 81351- // currently import. 81352- CompleteUnimported bool 81353- 81354- // DeepCompletion enables the ability to return completions from deep 81355- // inside relevant entities, rather than just the locally accessible ones. 81356- // 81357- // Consider this example: 81358- // 81359- // ```go 81360- // package main 81361- // 81362- // import "fmt" 81363- // 81364- // type wrapString struct { 81365- // str string 81366- // } 81367- // 81368- // func main() { 81369- // x := wrapString{"hello world"} 81370- // fmt.Printf(<>) 81371- // } 81372- // ``` 81373- // 81374- // At the location of the `<>` in this program, deep completion would suggest 81375- // the result `x.str`. 81376- DeepCompletion bool 81377- 81378- // TempModfile controls the use of the -modfile flag in Go 1.14. 81379- TempModfile bool 81380- 81381- // ShowBugReports causes a message to be shown when the first bug is reported 81382- // on the server. 81383- // This option applies only during initialization. 81384- ShowBugReports bool 81385- 81386- // NewDiff controls the choice of the new diff implementation. It can be 81387- // 'new', 'old', or 'both', which is the default. 'both' computes diffs with 81388- // both algorithms, checks that the new algorithm has worked, and write some 81389- // summary statistics to a file in os.TmpDir(). 81390- NewDiff string 81391- 81392- // ChattyDiagnostics controls whether to report file diagnostics for each 81393- // file change. If unset, gopls only reports diagnostics when they change, or 81394- // when a file is opened or closed. 81395- ChattyDiagnostics bool 81396-} 81397- 81398-type ImportShortcut string 81399- 81400-const ( 81401- BothShortcuts ImportShortcut = "Both" 81402- LinkShortcut ImportShortcut = "Link" 81403- DefinitionShortcut ImportShortcut = "Definition" 81404-) 81405- 81406-func (s ImportShortcut) ShowLinks() bool { 81407- return s == BothShortcuts || s == LinkShortcut 81408-} 81409- 81410-func (s ImportShortcut) ShowDefinition() bool { 81411- return s == BothShortcuts || s == DefinitionShortcut 81412-} 81413- 81414-type Matcher string 81415- 81416-const ( 81417- Fuzzy Matcher = "Fuzzy" 81418- CaseInsensitive Matcher = "CaseInsensitive" 81419- CaseSensitive Matcher = "CaseSensitive" 81420-) 81421- 81422-type SymbolMatcher string 81423- 81424-const ( 81425- SymbolFuzzy SymbolMatcher = "Fuzzy" 81426- SymbolFastFuzzy SymbolMatcher = "FastFuzzy" 81427- SymbolCaseInsensitive SymbolMatcher = "CaseInsensitive" 81428- SymbolCaseSensitive SymbolMatcher = "CaseSensitive" 81429-) 81430- 81431-type SymbolStyle string 81432- 81433-const ( 81434- // PackageQualifiedSymbols is package qualified symbols i.e. 81435- // "pkg.Foo.Field". 81436- PackageQualifiedSymbols SymbolStyle = "Package" 81437- // FullyQualifiedSymbols is fully qualified symbols, i.e. 81438- // "path/to/pkg.Foo.Field". 81439- FullyQualifiedSymbols SymbolStyle = "Full" 81440- // DynamicSymbols uses whichever qualifier results in the highest scoring 81441- // match for the given symbol query. Here a "qualifier" is any "/" or "." 81442- // delimited suffix of the fully qualified symbol. i.e. "to/pkg.Foo.Field" or 81443- // just "Foo.Field". 81444- DynamicSymbols SymbolStyle = "Dynamic" 81445-) 81446- 81447-type HoverKind string 81448- 81449-const ( 81450- SingleLine HoverKind = "SingleLine" 81451- NoDocumentation HoverKind = "NoDocumentation" 81452- SynopsisDocumentation HoverKind = "SynopsisDocumentation" 81453- FullDocumentation HoverKind = "FullDocumentation" 81454- 81455- // Structured is an experimental setting that returns a structured hover format. 81456- // This format separates the signature from the documentation, so that the client 81457- // can do more manipulation of these fields. 81458- // 81459- // This should only be used by clients that support this behavior. 81460- Structured HoverKind = "Structured" 81461-) 81462- 81463-type MemoryMode string 81464- 81465-const ( 81466- ModeNormal MemoryMode = "Normal" 81467- // In DegradeClosed mode, `gopls` will collect less information about 81468- // packages without open files. As a result, features like Find 81469- // References and Rename will miss results in such packages. 81470- ModeDegradeClosed MemoryMode = "DegradeClosed" 81471-) 81472- 81473-type VulncheckMode string 81474- 81475-const ( 81476- // Disable vulnerability analysis. 81477- ModeVulncheckOff VulncheckMode = "Off" 81478- // In Imports mode, `gopls` will report vulnerabilities that affect packages 81479- // directly and indirectly used by the analyzed main module. 81480- ModeVulncheckImports VulncheckMode = "Imports" 81481- 81482- // TODO: VulncheckRequire, VulncheckCallgraph 81483-) 81484- 81485-type OptionResults []OptionResult 81486- 81487-type OptionResult struct { 81488- Name string 81489- Value interface{} 81490- Error error 81491-} 81492- 81493-func SetOptions(options *Options, opts interface{}) OptionResults { 81494- var results OptionResults 81495- switch opts := opts.(type) { 81496- case nil: 81497- case map[string]interface{}: 81498- // If the user's settings contains "allExperiments", set that first, 81499- // and then let them override individual settings independently. 81500- var enableExperiments bool 81501- for name, value := range opts { 81502- if b, ok := value.(bool); name == "allExperiments" && ok && b { 81503- enableExperiments = true 81504- options.EnableAllExperiments() 81505- } 81506- } 81507- seen := map[string]struct{}{} 81508- for name, value := range opts { 81509- results = append(results, options.set(name, value, seen)) 81510- } 81511- // Finally, enable any experimental features that are specified in 81512- // maps, which allows users to individually toggle them on or off. 81513- if enableExperiments { 81514- options.enableAllExperimentMaps() 81515- } 81516- default: 81517- results = append(results, OptionResult{ 81518- Value: opts, 81519- Error: fmt.Errorf("Invalid options type %T", opts), 81520- }) 81521- } 81522- return results 81523-} 81524- 81525-func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) { 81526- // Check if the client supports snippets in completion items. 81527- if caps.Workspace.WorkspaceEdit != nil { 81528- o.SupportedResourceOperations = caps.Workspace.WorkspaceEdit.ResourceOperations 81529- } 81530- if c := caps.TextDocument.Completion; c.CompletionItem.SnippetSupport { 81531- o.InsertTextFormat = protocol.SnippetTextFormat 81532- } 81533- // Check if the client supports configuration messages. 81534- o.ConfigurationSupported = caps.Workspace.Configuration 81535- o.DynamicConfigurationSupported = caps.Workspace.DidChangeConfiguration.DynamicRegistration 81536- o.DynamicRegistrationSemanticTokensSupported = caps.TextDocument.SemanticTokens.DynamicRegistration 81537- o.DynamicWatchedFilesSupported = caps.Workspace.DidChangeWatchedFiles.DynamicRegistration 81538- 81539- // Check which types of content format are supported by this client. 81540- if hover := caps.TextDocument.Hover; hover != nil && len(hover.ContentFormat) > 0 { 81541- o.PreferredContentFormat = hover.ContentFormat[0] 81542- } 81543- // Check if the client supports only line folding. 81544- 81545- if fr := caps.TextDocument.FoldingRange; fr != nil { 81546- o.LineFoldingOnly = fr.LineFoldingOnly 81547- } 81548- // Check if the client supports hierarchical document symbols. 81549- o.HierarchicalDocumentSymbolSupport = caps.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport 81550- 81551- // Client's semantic tokens 81552- o.SemanticTypes = caps.TextDocument.SemanticTokens.TokenTypes 81553- o.SemanticMods = caps.TextDocument.SemanticTokens.TokenModifiers 81554- // we don't need Requests, as we support full functionality 81555- // we don't need Formats, as there is only one, for now 81556- 81557- // Check if the client supports diagnostic related information. 81558- o.RelatedInformationSupported = caps.TextDocument.PublishDiagnostics.RelatedInformation 81559- // Check if the client completion support includes tags (preferred) or deprecation 81560- if caps.TextDocument.Completion.CompletionItem.TagSupport.ValueSet != nil { 81561- o.CompletionTags = true 81562- } else if caps.TextDocument.Completion.CompletionItem.DeprecatedSupport { 81563- o.CompletionDeprecated = true 81564- } 81565-} 81566- 81567-func (o *Options) Clone() *Options { 81568- // TODO(rfindley): has this function gone stale? It appears that there are 81569- // settings that are incorrectly cloned here (such as TemplateExtensions). 81570- result := &Options{ 81571- ClientOptions: o.ClientOptions, 81572- InternalOptions: o.InternalOptions, 81573- Hooks: Hooks{ 81574- GoDiff: o.GoDiff, 81575- StaticcheckSupported: o.StaticcheckSupported, 81576- ComputeEdits: o.ComputeEdits, 81577- GofumptFormat: o.GofumptFormat, 81578- URLRegexp: o.URLRegexp, 81579- }, 81580- ServerOptions: o.ServerOptions, 81581- UserOptions: o.UserOptions, 81582- } 81583- // Fully clone any slice or map fields. Only Hooks, ExperimentalOptions, 81584- // and UserOptions can be modified. 81585- copyStringMap := func(src map[string]bool) map[string]bool { 81586- dst := make(map[string]bool) 81587- for k, v := range src { 81588- dst[k] = v 81589- } 81590- return dst 81591- } 81592- result.Analyses = copyStringMap(o.Analyses) 81593- result.Codelenses = copyStringMap(o.Codelenses) 81594- 81595- copySlice := func(src []string) []string { 81596- dst := make([]string, len(src)) 81597- copy(dst, src) 81598- return dst 81599- } 81600- result.SetEnvSlice(o.EnvSlice()) 81601- result.BuildFlags = copySlice(o.BuildFlags) 81602- result.DirectoryFilters = copySlice(o.DirectoryFilters) 81603- result.StandaloneTags = copySlice(o.StandaloneTags) 81604- 81605- copyAnalyzerMap := func(src map[string]*Analyzer) map[string]*Analyzer { 81606- dst := make(map[string]*Analyzer) 81607- for k, v := range src { 81608- dst[k] = v 81609- } 81610- return dst 81611- } 81612- result.DefaultAnalyzers = copyAnalyzerMap(o.DefaultAnalyzers) 81613- result.TypeErrorAnalyzers = copyAnalyzerMap(o.TypeErrorAnalyzers) 81614- result.ConvenienceAnalyzers = copyAnalyzerMap(o.ConvenienceAnalyzers) 81615- result.StaticcheckAnalyzers = copyAnalyzerMap(o.StaticcheckAnalyzers) 81616- return result 81617-} 81618- 81619-func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer, enabled bool, severity protocol.DiagnosticSeverity) { 81620- o.StaticcheckAnalyzers[a.Name] = &Analyzer{ 81621- Analyzer: a, 81622- Enabled: enabled, 81623- Severity: severity, 81624- } 81625-} 81626- 81627-// EnableAllExperiments turns on all of the experimental "off-by-default" 81628-// features offered by gopls. Any experimental features specified in maps 81629-// should be enabled in enableAllExperimentMaps. 81630-func (o *Options) EnableAllExperiments() { 81631- o.SemanticTokens = true 81632-} 81633- 81634-func (o *Options) enableAllExperimentMaps() { 81635- if _, ok := o.Codelenses[string(command.GCDetails)]; !ok { 81636- o.Codelenses[string(command.GCDetails)] = true 81637- } 81638- if _, ok := o.Codelenses[string(command.RunGovulncheck)]; !ok { 81639- o.Codelenses[string(command.RunGovulncheck)] = true 81640- } 81641- if _, ok := o.Analyses[unusedparams.Analyzer.Name]; !ok { 81642- o.Analyses[unusedparams.Analyzer.Name] = true 81643- } 81644- if _, ok := o.Analyses[unusedvariable.Analyzer.Name]; !ok { 81645- o.Analyses[unusedvariable.Analyzer.Name] = true 81646- } 81647-} 81648- 81649-// validateDirectoryFilter validates if the filter string 81650-// - is not empty 81651-// - start with either + or - 81652-// - doesn't contain currently unsupported glob operators: *, ? 81653-func validateDirectoryFilter(ifilter string) (string, error) { 81654- filter := fmt.Sprint(ifilter) 81655- if filter == "" || (filter[0] != '+' && filter[0] != '-') { 81656- return "", fmt.Errorf("invalid filter %v, must start with + or -", filter) 81657- } 81658- segs := strings.Split(filter[1:], "/") 81659- unsupportedOps := [...]string{"?", "*"} 81660- for _, seg := range segs { 81661- if seg != "**" { 81662- for _, op := range unsupportedOps { 81663- if strings.Contains(seg, op) { 81664- return "", fmt.Errorf("invalid filter %v, operator %v not supported. If you want to have this operator supported, consider filing an issue.", filter, op) 81665- } 81666- } 81667- } 81668- } 81669- 81670- return strings.TrimRight(filepath.FromSlash(filter), "/"), nil 81671-} 81672- 81673-func (o *Options) set(name string, value interface{}, seen map[string]struct{}) OptionResult { 81674- // Flatten the name in case we get options with a hierarchy. 81675- split := strings.Split(name, ".") 81676- name = split[len(split)-1] 81677- 81678- result := OptionResult{Name: name, Value: value} 81679- if _, ok := seen[name]; ok { 81680- result.parseErrorf("duplicate configuration for %s", name) 81681- } 81682- seen[name] = struct{}{} 81683- 81684- switch name { 81685- case "env": 81686- menv, ok := value.(map[string]interface{}) 81687- if !ok { 81688- result.parseErrorf("invalid type %T, expect map", value) 81689- break 81690- } 81691- if o.Env == nil { 81692- o.Env = make(map[string]string) 81693- } 81694- for k, v := range menv { 81695- o.Env[k] = fmt.Sprint(v) 81696- } 81697- 81698- case "buildFlags": 81699- // TODO(rfindley): use asStringSlice. 81700- iflags, ok := value.([]interface{}) 81701- if !ok { 81702- result.parseErrorf("invalid type %T, expect list", value) 81703- break 81704- } 81705- flags := make([]string, 0, len(iflags)) 81706- for _, flag := range iflags { 81707- flags = append(flags, fmt.Sprintf("%s", flag)) 81708- } 81709- o.BuildFlags = flags 81710- 81711- case "directoryFilters": 81712- // TODO(rfindley): use asStringSlice. 81713- ifilters, ok := value.([]interface{}) 81714- if !ok { 81715- result.parseErrorf("invalid type %T, expect list", value) 81716- break 81717- } 81718- var filters []string 81719- for _, ifilter := range ifilters { 81720- filter, err := validateDirectoryFilter(fmt.Sprintf("%v", ifilter)) 81721- if err != nil { 81722- result.parseErrorf("%v", err) 81723- return result 81724- } 81725- filters = append(filters, strings.TrimRight(filepath.FromSlash(filter), "/")) 81726- } 81727- o.DirectoryFilters = filters 81728- 81729- case "memoryMode": 81730- if s, ok := result.asOneOf( 81731- string(ModeNormal), 81732- string(ModeDegradeClosed), 81733- ); ok { 81734- o.MemoryMode = MemoryMode(s) 81735- } 81736- case "completionDocumentation": 81737- result.setBool(&o.CompletionDocumentation) 81738- case "usePlaceholders": 81739- result.setBool(&o.UsePlaceholders) 81740- case "deepCompletion": 81741- result.setBool(&o.DeepCompletion) 81742- case "completeUnimported": 81743- result.setBool(&o.CompleteUnimported) 81744- case "completionBudget": 81745- result.setDuration(&o.CompletionBudget) 81746- case "matcher": 81747- if s, ok := result.asOneOf( 81748- string(Fuzzy), 81749- string(CaseSensitive), 81750- string(CaseInsensitive), 81751- ); ok { 81752- o.Matcher = Matcher(s) 81753- } 81754- 81755- case "symbolMatcher": 81756- if s, ok := result.asOneOf( 81757- string(SymbolFuzzy), 81758- string(SymbolFastFuzzy), 81759- string(SymbolCaseInsensitive), 81760- string(SymbolCaseSensitive), 81761- ); ok { 81762- o.SymbolMatcher = SymbolMatcher(s) 81763- } 81764- 81765- case "symbolStyle": 81766- if s, ok := result.asOneOf( 81767- string(FullyQualifiedSymbols), 81768- string(PackageQualifiedSymbols), 81769- string(DynamicSymbols), 81770- ); ok { 81771- o.SymbolStyle = SymbolStyle(s) 81772- } 81773- 81774- case "hoverKind": 81775- if s, ok := result.asOneOf( 81776- string(NoDocumentation), 81777- string(SingleLine), 81778- string(SynopsisDocumentation), 81779- string(FullDocumentation), 81780- string(Structured), 81781- ); ok { 81782- o.HoverKind = HoverKind(s) 81783- } 81784- 81785- case "linkTarget": 81786- result.setString(&o.LinkTarget) 81787- 81788- case "linksInHover": 81789- result.setBool(&o.LinksInHover) 81790- 81791- case "importShortcut": 81792- if s, ok := result.asOneOf(string(BothShortcuts), string(LinkShortcut), string(DefinitionShortcut)); ok { 81793- o.ImportShortcut = ImportShortcut(s) 81794- } 81795- 81796- case "analyses": 81797- result.setBoolMap(&o.Analyses) 81798- 81799- case "hints": 81800- result.setBoolMap(&o.Hints) 81801- 81802- case "annotations": 81803- result.setAnnotationMap(&o.Annotations) 81804- 81805- case "vulncheck": 81806- if s, ok := result.asOneOf( 81807- string(ModeVulncheckOff), 81808- string(ModeVulncheckImports), 81809- ); ok { 81810- o.Vulncheck = VulncheckMode(s) 81811- } 81812- 81813- case "codelenses", "codelens": 81814- var lensOverrides map[string]bool 81815- result.setBoolMap(&lensOverrides) 81816- if result.Error == nil { 81817- if o.Codelenses == nil { 81818- o.Codelenses = make(map[string]bool) 81819- } 81820- for lens, enabled := range lensOverrides { 81821- o.Codelenses[lens] = enabled 81822- } 81823- } 81824- 81825- // codelens is deprecated, but still works for now. 81826- // TODO(rstambler): Remove this for the gopls/v0.7.0 release. 81827- if name == "codelens" { 81828- result.deprecated("codelenses") 81829- } 81830- 81831- case "staticcheck": 81832- if v, ok := result.asBool(); ok { 81833- o.Staticcheck = v 81834- if v && !o.StaticcheckSupported { 81835- result.Error = fmt.Errorf("applying setting %q: staticcheck is not supported at %s;"+ 81836- " rebuild gopls with a more recent version of Go", result.Name, runtime.Version()) 81837- } 81838- } 81839- 81840- case "local": 81841- result.setString(&o.Local) 81842- 81843- case "verboseOutput": 81844- result.setBool(&o.VerboseOutput) 81845- 81846- case "verboseWorkDoneProgress": 81847- result.setBool(&o.VerboseWorkDoneProgress) 81848- 81849- case "tempModfile": 81850- result.setBool(&o.TempModfile) 81851- 81852- case "showBugReports": 81853- result.setBool(&o.ShowBugReports) 81854- 81855- case "gofumpt": 81856- if v, ok := result.asBool(); ok { 81857- o.Gofumpt = v 81858- if v && o.GofumptFormat == nil { 81859- result.Error = fmt.Errorf("applying setting %q: gofumpt is not supported at %s;"+ 81860- " rebuild gopls with a more recent version of Go", result.Name, runtime.Version()) 81861- } 81862- } 81863- 81864- case "semanticTokens": 81865- result.setBool(&o.SemanticTokens) 81866- 81867- case "noSemanticString": 81868- result.setBool(&o.NoSemanticString) 81869- 81870- case "noSemanticNumber": 81871- result.setBool(&o.NoSemanticNumber) 81872- 81873- case "expandWorkspaceToModule": 81874- result.setBool(&o.ExpandWorkspaceToModule) 81875- 81876- case "experimentalPostfixCompletions": 81877- result.setBool(&o.ExperimentalPostfixCompletions) 81878- 81879- case "experimentalWorkspaceModule": 81880- result.deprecated("") 81881- 81882- case "experimentalTemplateSupport": // TODO(pjw): remove after June 2022 81883- result.deprecated("") 81884- 81885- case "templateExtensions": 81886- if iexts, ok := value.([]interface{}); ok { 81887- ans := []string{} 81888- for _, x := range iexts { 81889- ans = append(ans, fmt.Sprint(x)) 81890- } 81891- o.TemplateExtensions = ans 81892- break 81893- } 81894- if value == nil { 81895- o.TemplateExtensions = nil 81896- break 81897- } 81898- result.parseErrorf("unexpected type %T not []string", value) 81899- 81900- case "experimentalDiagnosticsDelay": 81901- result.deprecated("diagnosticsDelay") 81902- 81903- case "diagnosticsDelay": 81904- result.setDuration(&o.DiagnosticsDelay) 81905- 81906- case "experimentalWatchedFileDelay": 81907- result.deprecated("") 81908- 81909- case "experimentalPackageCacheKey": 81910- result.deprecated("") 81911- 81912- case "allowModfileModifications": 81913- result.setBool(&o.AllowModfileModifications) 81914- 81915- case "allowImplicitNetworkAccess": 81916- result.setBool(&o.AllowImplicitNetworkAccess) 81917- 81918- case "experimentalUseInvalidMetadata": 81919- result.deprecated("") 81920- 81921- case "standaloneTags": 81922- result.setStringSlice(&o.StandaloneTags) 81923- 81924- case "allExperiments": 81925- // This setting should be handled before all of the other options are 81926- // processed, so do nothing here. 81927- 81928- case "newDiff": 81929- result.setString(&o.NewDiff) 81930- 81931- case "chattyDiagnostics": 81932- result.setBool(&o.ChattyDiagnostics) 81933- 81934- // Replaced settings. 81935- case "experimentalDisabledAnalyses": 81936- result.deprecated("analyses") 81937- 81938- case "disableDeepCompletion": 81939- result.deprecated("deepCompletion") 81940- 81941- case "disableFuzzyMatching": 81942- result.deprecated("fuzzyMatching") 81943- 81944- case "wantCompletionDocumentation": 81945- result.deprecated("completionDocumentation") 81946- 81947- case "wantUnimportedCompletions": 81948- result.deprecated("completeUnimported") 81949- 81950- case "fuzzyMatching": 81951- result.deprecated("matcher") 81952- 81953- case "caseSensitiveCompletion": 81954- result.deprecated("matcher") 81955- 81956- // Deprecated settings. 81957- case "wantSuggestedFixes": 81958- result.deprecated("") 81959- 81960- case "noIncrementalSync": 81961- result.deprecated("") 81962- 81963- case "watchFileChanges": 81964- result.deprecated("") 81965- 81966- case "go-diff": 81967- result.deprecated("") 81968- 81969- default: 81970- result.unexpected() 81971- } 81972- return result 81973-} 81974- 81975-// parseErrorf reports an error parsing the current configuration value. 81976-func (r *OptionResult) parseErrorf(msg string, values ...interface{}) { 81977- if false { 81978- _ = fmt.Sprintf(msg, values...) // this causes vet to check this like printf 81979- } 81980- prefix := fmt.Sprintf("parsing setting %q: ", r.Name) 81981- r.Error = fmt.Errorf(prefix+msg, values...) 81982-} 81983- 81984-// A SoftError is an error that does not affect the functionality of gopls. 81985-type SoftError struct { 81986- msg string 81987-} 81988- 81989-func (e *SoftError) Error() string { 81990- return e.msg 81991-} 81992- 81993-// softErrorf reports an error that does not affect the functionality of gopls 81994-// (a warning in the UI). 81995-// The formatted message will be shown to the user unmodified. 81996-func (r *OptionResult) softErrorf(format string, values ...interface{}) { 81997- msg := fmt.Sprintf(format, values...) 81998- r.Error = &SoftError{msg} 81999-} 82000- 82001-// deprecated reports the current setting as deprecated. If 'replacement' is 82002-// non-nil, it is suggested to the user. 82003-func (r *OptionResult) deprecated(replacement string) { 82004- msg := fmt.Sprintf("gopls setting %q is deprecated", r.Name) 82005- if replacement != "" { 82006- msg = fmt.Sprintf("%s, use %q instead", msg, replacement) 82007- } 82008- r.Error = &SoftError{msg} 82009-} 82010- 82011-// unexpected reports that the current setting is not known to gopls. 82012-func (r *OptionResult) unexpected() { 82013- r.Error = fmt.Errorf("unexpected gopls setting %q", r.Name) 82014-} 82015- 82016-func (r *OptionResult) asBool() (bool, bool) { 82017- b, ok := r.Value.(bool) 82018- if !ok { 82019- r.parseErrorf("invalid type %T, expect bool", r.Value) 82020- return false, false 82021- } 82022- return b, true 82023-} 82024- 82025-func (r *OptionResult) setBool(b *bool) { 82026- if v, ok := r.asBool(); ok { 82027- *b = v 82028- } 82029-} 82030- 82031-func (r *OptionResult) setDuration(d *time.Duration) { 82032- if v, ok := r.asString(); ok { 82033- parsed, err := time.ParseDuration(v) 82034- if err != nil { 82035- r.parseErrorf("failed to parse duration %q: %v", v, err) 82036- return 82037- } 82038- *d = parsed 82039- } 82040-} 82041- 82042-func (r *OptionResult) setBoolMap(bm *map[string]bool) { 82043- m := r.asBoolMap() 82044- *bm = m 82045-} 82046- 82047-func (r *OptionResult) setAnnotationMap(bm *map[Annotation]bool) { 82048- all := r.asBoolMap() 82049- if all == nil { 82050- return 82051- } 82052- // Default to everything enabled by default. 82053- m := make(map[Annotation]bool) 82054- for k, enabled := range all { 82055- a, err := asOneOf( 82056- k, 82057- string(Nil), 82058- string(Escape), 82059- string(Inline), 82060- string(Bounds), 82061- ) 82062- if err != nil { 82063- // In case of an error, process any legacy values. 82064- switch k { 82065- case "noEscape": 82066- m[Escape] = false 82067- r.parseErrorf(`"noEscape" is deprecated, set "Escape: false" instead`) 82068- case "noNilcheck": 82069- m[Nil] = false 82070- r.parseErrorf(`"noNilcheck" is deprecated, set "Nil: false" instead`) 82071- case "noInline": 82072- m[Inline] = false 82073- r.parseErrorf(`"noInline" is deprecated, set "Inline: false" instead`) 82074- case "noBounds": 82075- m[Bounds] = false 82076- r.parseErrorf(`"noBounds" is deprecated, set "Bounds: false" instead`) 82077- default: 82078- r.parseErrorf("%v", err) 82079- } 82080- continue 82081- } 82082- m[Annotation(a)] = enabled 82083- } 82084- *bm = m 82085-} 82086- 82087-func (r *OptionResult) asBoolMap() map[string]bool { 82088- all, ok := r.Value.(map[string]interface{}) 82089- if !ok { 82090- r.parseErrorf("invalid type %T for map[string]bool option", r.Value) 82091- return nil 82092- } 82093- m := make(map[string]bool) 82094- for a, enabled := range all { 82095- if e, ok := enabled.(bool); ok { 82096- m[a] = e 82097- } else { 82098- r.parseErrorf("invalid type %T for map key %q", enabled, a) 82099- return m 82100- } 82101- } 82102- return m 82103-} 82104- 82105-func (r *OptionResult) asString() (string, bool) { 82106- b, ok := r.Value.(string) 82107- if !ok { 82108- r.parseErrorf("invalid type %T, expect string", r.Value) 82109- return "", false 82110- } 82111- return b, true 82112-} 82113- 82114-func (r *OptionResult) asStringSlice() ([]string, bool) { 82115- iList, ok := r.Value.([]interface{}) 82116- if !ok { 82117- r.parseErrorf("invalid type %T, expect list", r.Value) 82118- return nil, false 82119- } 82120- var list []string 82121- for _, elem := range iList { 82122- s, ok := elem.(string) 82123- if !ok { 82124- r.parseErrorf("invalid element type %T, expect string", elem) 82125- return nil, false 82126- } 82127- list = append(list, s) 82128- } 82129- return list, true 82130-} 82131- 82132-func (r *OptionResult) asOneOf(options ...string) (string, bool) { 82133- s, ok := r.asString() 82134- if !ok { 82135- return "", false 82136- } 82137- s, err := asOneOf(s, options...) 82138- if err != nil { 82139- r.parseErrorf("%v", err) 82140- } 82141- return s, err == nil 82142-} 82143- 82144-func asOneOf(str string, options ...string) (string, error) { 82145- lower := strings.ToLower(str) 82146- for _, opt := range options { 82147- if strings.ToLower(opt) == lower { 82148- return opt, nil 82149- } 82150- } 82151- return "", fmt.Errorf("invalid option %q for enum", str) 82152-} 82153- 82154-func (r *OptionResult) setString(s *string) { 82155- if v, ok := r.asString(); ok { 82156- *s = v 82157- } 82158-} 82159- 82160-func (r *OptionResult) setStringSlice(s *[]string) { 82161- if v, ok := r.asStringSlice(); ok { 82162- *s = v 82163- } 82164-} 82165- 82166-func typeErrorAnalyzers() map[string]*Analyzer { 82167- return map[string]*Analyzer{ 82168- fillreturns.Analyzer.Name: { 82169- Analyzer: fillreturns.Analyzer, 82170- ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix}, 82171- Enabled: true, 82172- }, 82173- nonewvars.Analyzer.Name: { 82174- Analyzer: nonewvars.Analyzer, 82175- Enabled: true, 82176- }, 82177- noresultvalues.Analyzer.Name: { 82178- Analyzer: noresultvalues.Analyzer, 82179- Enabled: true, 82180- }, 82181- undeclaredname.Analyzer.Name: { 82182- Analyzer: undeclaredname.Analyzer, 82183- Fix: UndeclaredName, 82184- Enabled: true, 82185- }, 82186- unusedvariable.Analyzer.Name: { 82187- Analyzer: unusedvariable.Analyzer, 82188- Enabled: false, 82189- }, 82190- } 82191-} 82192- 82193-func convenienceAnalyzers() map[string]*Analyzer { 82194- return map[string]*Analyzer{ 82195- fillstruct.Analyzer.Name: { 82196- Analyzer: fillstruct.Analyzer, 82197- Fix: FillStruct, 82198- Enabled: true, 82199- ActionKind: []protocol.CodeActionKind{protocol.RefactorRewrite}, 82200- }, 82201- stubmethods.Analyzer.Name: { 82202- Analyzer: stubmethods.Analyzer, 82203- ActionKind: []protocol.CodeActionKind{protocol.RefactorRewrite}, 82204- Fix: StubMethods, 82205- Enabled: true, 82206- }, 82207- } 82208-} 82209- 82210-func defaultAnalyzers() map[string]*Analyzer { 82211- return map[string]*Analyzer{ 82212- // The traditional vet suite: 82213- asmdecl.Analyzer.Name: {Analyzer: asmdecl.Analyzer, Enabled: true}, 82214- assign.Analyzer.Name: {Analyzer: assign.Analyzer, Enabled: true}, 82215- atomic.Analyzer.Name: {Analyzer: atomic.Analyzer, Enabled: true}, 82216- bools.Analyzer.Name: {Analyzer: bools.Analyzer, Enabled: true}, 82217- buildtag.Analyzer.Name: {Analyzer: buildtag.Analyzer, Enabled: true}, 82218- cgocall.Analyzer.Name: {Analyzer: cgocall.Analyzer, Enabled: true}, 82219- composite.Analyzer.Name: {Analyzer: composite.Analyzer, Enabled: true}, 82220- copylock.Analyzer.Name: {Analyzer: copylock.Analyzer, Enabled: true}, 82221- directive.Analyzer.Name: {Analyzer: directive.Analyzer, Enabled: true}, 82222- errorsas.Analyzer.Name: {Analyzer: errorsas.Analyzer, Enabled: true}, 82223- httpresponse.Analyzer.Name: {Analyzer: httpresponse.Analyzer, Enabled: true}, 82224- ifaceassert.Analyzer.Name: {Analyzer: ifaceassert.Analyzer, Enabled: true}, 82225- loopclosure.Analyzer.Name: {Analyzer: loopclosure.Analyzer, Enabled: true}, 82226- lostcancel.Analyzer.Name: {Analyzer: lostcancel.Analyzer, Enabled: true}, 82227- nilfunc.Analyzer.Name: {Analyzer: nilfunc.Analyzer, Enabled: true}, 82228- printf.Analyzer.Name: {Analyzer: printf.Analyzer, Enabled: true}, 82229- shift.Analyzer.Name: {Analyzer: shift.Analyzer, Enabled: true}, 82230- stdmethods.Analyzer.Name: {Analyzer: stdmethods.Analyzer, Enabled: true}, 82231- stringintconv.Analyzer.Name: {Analyzer: stringintconv.Analyzer, Enabled: true}, 82232- structtag.Analyzer.Name: {Analyzer: structtag.Analyzer, Enabled: true}, 82233- tests.Analyzer.Name: {Analyzer: tests.Analyzer, Enabled: true}, 82234- unmarshal.Analyzer.Name: {Analyzer: unmarshal.Analyzer, Enabled: true}, 82235- unreachable.Analyzer.Name: {Analyzer: unreachable.Analyzer, Enabled: true}, 82236- unsafeptr.Analyzer.Name: {Analyzer: unsafeptr.Analyzer, Enabled: true}, 82237- unusedresult.Analyzer.Name: {Analyzer: unusedresult.Analyzer, Enabled: true}, 82238- 82239- // Non-vet analyzers: 82240- atomicalign.Analyzer.Name: {Analyzer: atomicalign.Analyzer, Enabled: true}, 82241- deepequalerrors.Analyzer.Name: {Analyzer: deepequalerrors.Analyzer, Enabled: true}, 82242- fieldalignment.Analyzer.Name: {Analyzer: fieldalignment.Analyzer, Enabled: false}, 82243- nilness.Analyzer.Name: {Analyzer: nilness.Analyzer, Enabled: false}, 82244- shadow.Analyzer.Name: {Analyzer: shadow.Analyzer, Enabled: false}, 82245- sortslice.Analyzer.Name: {Analyzer: sortslice.Analyzer, Enabled: true}, 82246- testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true}, 82247- unusedparams.Analyzer.Name: {Analyzer: unusedparams.Analyzer, Enabled: false}, 82248- unusedwrite.Analyzer.Name: {Analyzer: unusedwrite.Analyzer, Enabled: false}, 82249- useany.Analyzer.Name: {Analyzer: useany.Analyzer, Enabled: false}, 82250- infertypeargs.Analyzer.Name: {Analyzer: infertypeargs.Analyzer, Enabled: true}, 82251- embeddirective.Analyzer.Name: {Analyzer: embeddirective.Analyzer, Enabled: true}, 82252- timeformat.Analyzer.Name: {Analyzer: timeformat.Analyzer, Enabled: true}, 82253- 82254- // gofmt -s suite: 82255- simplifycompositelit.Analyzer.Name: { 82256- Analyzer: simplifycompositelit.Analyzer, 82257- Enabled: true, 82258- ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix}, 82259- }, 82260- simplifyrange.Analyzer.Name: { 82261- Analyzer: simplifyrange.Analyzer, 82262- Enabled: true, 82263- ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix}, 82264- }, 82265- simplifyslice.Analyzer.Name: { 82266- Analyzer: simplifyslice.Analyzer, 82267- Enabled: true, 82268- ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix}, 82269- }, 82270- } 82271-} 82272- 82273-func urlRegexp() *regexp.Regexp { 82274- // Ensure links are matched as full words, not anywhere. 82275- re := regexp.MustCompile(`\b(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?\b`) 82276- re.Longest() 82277- return re 82278-} 82279- 82280-type APIJSON struct { 82281- Options map[string][]*OptionJSON 82282- Commands []*CommandJSON 82283- Lenses []*LensJSON 82284- Analyzers []*AnalyzerJSON 82285- Hints []*HintJSON 82286-} 82287- 82288-type OptionJSON struct { 82289- Name string 82290- Type string 82291- Doc string 82292- EnumKeys EnumKeys 82293- EnumValues []EnumValue 82294- Default string 82295- Status string 82296- Hierarchy string 82297-} 82298- 82299-func (o *OptionJSON) String() string { 82300- return o.Name 82301-} 82302- 82303-func (o *OptionJSON) Write(w io.Writer) { 82304- fmt.Fprintf(w, "**%v** *%v*\n\n", o.Name, o.Type) 82305- writeStatus(w, o.Status) 82306- enumValues := collectEnums(o) 82307- fmt.Fprintf(w, "%v%v\nDefault: `%v`.\n\n", o.Doc, enumValues, o.Default) 82308-} 82309- 82310-func writeStatus(section io.Writer, status string) { 82311- switch status { 82312- case "": 82313- case "advanced": 82314- fmt.Fprint(section, "**This is an advanced setting and should not be configured by most `gopls` users.**\n\n") 82315- case "debug": 82316- fmt.Fprint(section, "**This setting is for debugging purposes only.**\n\n") 82317- case "experimental": 82318- fmt.Fprint(section, "**This setting is experimental and may be deleted.**\n\n") 82319- default: 82320- fmt.Fprintf(section, "**Status: %s.**\n\n", status) 82321- } 82322-} 82323- 82324-var parBreakRE = regexp.MustCompile("\n{2,}") 82325- 82326-func collectEnums(opt *OptionJSON) string { 82327- var b strings.Builder 82328- write := func(name, doc string, index, len int) { 82329- if doc != "" { 82330- unbroken := parBreakRE.ReplaceAllString(doc, "\\\n") 82331- fmt.Fprintf(&b, "* %s\n", strings.TrimSpace(unbroken)) 82332- } else { 82333- fmt.Fprintf(&b, "* `%s`\n", name) 82334- } 82335- } 82336- if len(opt.EnumValues) > 0 && opt.Type == "enum" { 82337- b.WriteString("\nMust be one of:\n\n") 82338- for i, val := range opt.EnumValues { 82339- write(val.Value, val.Doc, i, len(opt.EnumValues)) 82340- } 82341- } else if len(opt.EnumKeys.Keys) > 0 && shouldShowEnumKeysInSettings(opt.Name) { 82342- b.WriteString("\nCan contain any of:\n\n") 82343- for i, val := range opt.EnumKeys.Keys { 82344- write(val.Name, val.Doc, i, len(opt.EnumKeys.Keys)) 82345- } 82346- } 82347- return b.String() 82348-} 82349- 82350-func shouldShowEnumKeysInSettings(name string) bool { 82351- // These fields have too many possible options to print. 82352- return !(name == "analyses" || name == "codelenses" || name == "hints") 82353-} 82354- 82355-type EnumKeys struct { 82356- ValueType string 82357- Keys []EnumKey 82358-} 82359- 82360-type EnumKey struct { 82361- Name string 82362- Doc string 82363- Default string 82364-} 82365- 82366-type EnumValue struct { 82367- Value string 82368- Doc string 82369-} 82370- 82371-type CommandJSON struct { 82372- Command string 82373- Title string 82374- Doc string 82375- ArgDoc string 82376- ResultDoc string 82377-} 82378- 82379-func (c *CommandJSON) String() string { 82380- return c.Command 82381-} 82382- 82383-func (c *CommandJSON) Write(w io.Writer) { 82384- fmt.Fprintf(w, "### **%v**\nIdentifier: `%v`\n\n%v\n\n", c.Title, c.Command, c.Doc) 82385- if c.ArgDoc != "" { 82386- fmt.Fprintf(w, "Args:\n\n```\n%s\n```\n\n", c.ArgDoc) 82387- } 82388- if c.ResultDoc != "" { 82389- fmt.Fprintf(w, "Result:\n\n```\n%s\n```\n\n", c.ResultDoc) 82390- } 82391-} 82392- 82393-type LensJSON struct { 82394- Lens string 82395- Title string 82396- Doc string 82397-} 82398- 82399-func (l *LensJSON) String() string { 82400- return l.Title 82401-} 82402- 82403-func (l *LensJSON) Write(w io.Writer) { 82404- fmt.Fprintf(w, "%s (%s): %s", l.Title, l.Lens, l.Doc) 82405-} 82406- 82407-type AnalyzerJSON struct { 82408- Name string 82409- Doc string 82410- Default bool 82411-} 82412- 82413-func (a *AnalyzerJSON) String() string { 82414- return a.Name 82415-} 82416- 82417-func (a *AnalyzerJSON) Write(w io.Writer) { 82418- fmt.Fprintf(w, "%s (%s): %v", a.Name, a.Doc, a.Default) 82419-} 82420- 82421-type HintJSON struct { 82422- Name string 82423- Doc string 82424- Default bool 82425-} 82426- 82427-func (h *HintJSON) String() string { 82428- return h.Name 82429-} 82430- 82431-func (h *HintJSON) Write(w io.Writer) { 82432- fmt.Fprintf(w, "%s (%s): %v", h.Name, h.Doc, h.Default) 82433-} 82434diff -urN a/gopls/internal/lsp/source/options_test.go b/gopls/internal/lsp/source/options_test.go 82435--- a/gopls/internal/lsp/source/options_test.go 2000-01-01 00:00:00.000000000 -0000 82436+++ b/gopls/internal/lsp/source/options_test.go 1970-01-01 00:00:00.000000000 +0000 82437@@ -1,206 +0,0 @@ 82438-// Copyright 2020 The Go Authors. All rights reserved. 82439-// Use of this source code is governed by a BSD-style 82440-// license that can be found in the LICENSE file. 82441- 82442-package source 82443- 82444-import ( 82445- "testing" 82446- "time" 82447-) 82448- 82449-func TestSetOption(t *testing.T) { 82450- tests := []struct { 82451- name string 82452- value interface{} 82453- wantError bool 82454- check func(Options) bool 82455- }{ 82456- { 82457- name: "symbolStyle", 82458- value: "Dynamic", 82459- check: func(o Options) bool { return o.SymbolStyle == DynamicSymbols }, 82460- }, 82461- { 82462- name: "symbolStyle", 82463- value: "", 82464- wantError: true, 82465- check: func(o Options) bool { return o.SymbolStyle == "" }, 82466- }, 82467- { 82468- name: "symbolStyle", 82469- value: false, 82470- wantError: true, 82471- check: func(o Options) bool { return o.SymbolStyle == "" }, 82472- }, 82473- { 82474- name: "symbolMatcher", 82475- value: "caseInsensitive", 82476- check: func(o Options) bool { return o.SymbolMatcher == SymbolCaseInsensitive }, 82477- }, 82478- { 82479- name: "completionBudget", 82480- value: "2s", 82481- check: func(o Options) bool { return o.CompletionBudget == 2*time.Second }, 82482- }, 82483- { 82484- name: "staticcheck", 82485- value: true, 82486- check: func(o Options) bool { return o.Staticcheck == true }, 82487- wantError: true, // o.StaticcheckSupported is unset 82488- }, 82489- { 82490- name: "codelenses", 82491- value: map[string]interface{}{"generate": true}, 82492- check: func(o Options) bool { return o.Codelenses["generate"] }, 82493- }, 82494- { 82495- name: "allExperiments", 82496- value: true, 82497- check: func(o Options) bool { 82498- return true // just confirm that we handle this setting 82499- }, 82500- }, 82501- { 82502- name: "hoverKind", 82503- value: "FullDocumentation", 82504- check: func(o Options) bool { 82505- return o.HoverKind == FullDocumentation 82506- }, 82507- }, 82508- { 82509- name: "hoverKind", 82510- value: "NoDocumentation", 82511- check: func(o Options) bool { 82512- return o.HoverKind == NoDocumentation 82513- }, 82514- }, 82515- { 82516- name: "hoverKind", 82517- value: "SingleLine", 82518- check: func(o Options) bool { 82519- return o.HoverKind == SingleLine 82520- }, 82521- }, 82522- { 82523- name: "hoverKind", 82524- value: "Structured", 82525- check: func(o Options) bool { 82526- return o.HoverKind == Structured 82527- }, 82528- }, 82529- { 82530- name: "ui.documentation.hoverKind", 82531- value: "Structured", 82532- check: func(o Options) bool { 82533- return o.HoverKind == Structured 82534- }, 82535- }, 82536- { 82537- name: "matcher", 82538- value: "Fuzzy", 82539- check: func(o Options) bool { 82540- return o.Matcher == Fuzzy 82541- }, 82542- }, 82543- { 82544- name: "matcher", 82545- value: "CaseSensitive", 82546- check: func(o Options) bool { 82547- return o.Matcher == CaseSensitive 82548- }, 82549- }, 82550- { 82551- name: "matcher", 82552- value: "CaseInsensitive", 82553- check: func(o Options) bool { 82554- return o.Matcher == CaseInsensitive 82555- }, 82556- }, 82557- { 82558- name: "env", 82559- value: map[string]interface{}{"testing": "true"}, 82560- check: func(o Options) bool { 82561- v, found := o.Env["testing"] 82562- return found && v == "true" 82563- }, 82564- }, 82565- { 82566- name: "env", 82567- value: []string{"invalid", "input"}, 82568- wantError: true, 82569- check: func(o Options) bool { 82570- return o.Env == nil 82571- }, 82572- }, 82573- { 82574- name: "directoryFilters", 82575- value: []interface{}{"-node_modules", "+project_a"}, 82576- check: func(o Options) bool { 82577- return len(o.DirectoryFilters) == 2 82578- }, 82579- }, 82580- { 82581- name: "directoryFilters", 82582- value: []interface{}{"invalid"}, 82583- wantError: true, 82584- check: func(o Options) bool { 82585- return len(o.DirectoryFilters) == 0 82586- }, 82587- }, 82588- { 82589- name: "directoryFilters", 82590- value: []string{"-invalid", "+type"}, 82591- wantError: true, 82592- check: func(o Options) bool { 82593- return len(o.DirectoryFilters) == 0 82594- }, 82595- }, 82596- { 82597- name: "annotations", 82598- value: map[string]interface{}{ 82599- "Nil": false, 82600- "noBounds": true, 82601- }, 82602- wantError: true, 82603- check: func(o Options) bool { 82604- return !o.Annotations[Nil] && !o.Annotations[Bounds] 82605- }, 82606- }, 82607- { 82608- name: "vulncheck", 82609- value: []interface{}{"invalid"}, 82610- wantError: true, 82611- check: func(o Options) bool { 82612- return o.Vulncheck == "" // For invalid value, default to 'off'. 82613- }, 82614- }, 82615- { 82616- name: "vulncheck", 82617- value: "Imports", 82618- check: func(o Options) bool { 82619- return o.Vulncheck == ModeVulncheckImports // For invalid value, default to 'off'. 82620- }, 82621- }, 82622- { 82623- name: "vulncheck", 82624- value: "imports", 82625- check: func(o Options) bool { 82626- return o.Vulncheck == ModeVulncheckImports 82627- }, 82628- }, 82629- } 82630- 82631- for _, test := range tests { 82632- var opts Options 82633- result := opts.set(test.name, test.value, map[string]struct{}{}) 82634- if (result.Error != nil) != test.wantError { 82635- t.Fatalf("Options.set(%q, %v): result.Error = %v, want error: %t", test.name, test.value, result.Error, test.wantError) 82636- } 82637- // TODO: this could be made much better using cmp.Diff, if that becomes 82638- // available in this module. 82639- if !test.check(opts) { 82640- t.Errorf("Options.set(%q, %v): unexpected result %+v", test.name, test.value, opts) 82641- } 82642- } 82643-} 82644diff -urN a/gopls/internal/lsp/source/references.go b/gopls/internal/lsp/source/references.go 82645--- a/gopls/internal/lsp/source/references.go 2000-01-01 00:00:00.000000000 -0000 82646+++ b/gopls/internal/lsp/source/references.go 1970-01-01 00:00:00.000000000 +0000 82647@@ -1,582 +0,0 @@ 82648-// Copyright 2019 The Go Authors. All rights reserved. 82649-// Use of this source code is governed by a BSD-style 82650-// license that can be found in the LICENSE file. 82651- 82652-package source 82653- 82654-// This file defines the 'references' query based on a serializable 82655-// index constructed during type checking, thus avoiding the need to 82656-// type-check packages at search time. 82657-// 82658-// See the ./xrefs/ subpackage for the index construction and lookup. 82659-// 82660-// This implementation does not intermingle objects from distinct 82661-// calls to TypeCheck. 82662- 82663-import ( 82664- "context" 82665- "fmt" 82666- "go/ast" 82667- "go/token" 82668- "go/types" 82669- "sort" 82670- "strings" 82671- "sync" 82672- 82673- "golang.org/x/sync/errgroup" 82674- "golang.org/x/tools/go/types/objectpath" 82675- "golang.org/x/tools/gopls/internal/lsp/protocol" 82676- "golang.org/x/tools/gopls/internal/lsp/safetoken" 82677- "golang.org/x/tools/gopls/internal/lsp/source/methodsets" 82678- "golang.org/x/tools/gopls/internal/span" 82679- "golang.org/x/tools/internal/bug" 82680- "golang.org/x/tools/internal/event" 82681-) 82682- 82683-// References returns a list of all references (sorted with 82684-// definitions before uses) to the object denoted by the identifier at 82685-// the given file/position, searching the entire workspace. 82686-func References(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position, includeDeclaration bool) ([]protocol.Location, error) { 82687- references, err := references(ctx, snapshot, fh, pp, includeDeclaration) 82688- if err != nil { 82689- return nil, err 82690- } 82691- locations := make([]protocol.Location, len(references)) 82692- for i, ref := range references { 82693- locations[i] = ref.location 82694- } 82695- return locations, nil 82696-} 82697- 82698-// A reference describes an identifier that refers to the same 82699-// object as the subject of a References query. 82700-type reference struct { 82701- isDeclaration bool 82702- location protocol.Location 82703- pkgPath PackagePath // of declaring package (same for all elements of the slice) 82704-} 82705- 82706-// references returns a list of all references (sorted with 82707-// definitions before uses) to the object denoted by the identifier at 82708-// the given file/position, searching the entire workspace. 82709-func references(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, includeDeclaration bool) ([]reference, error) { 82710- ctx, done := event.Start(ctx, "source.References2") 82711- defer done() 82712- 82713- // Is the cursor within the package name declaration? 82714- _, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp) 82715- if err != nil { 82716- return nil, err 82717- } 82718- 82719- var refs []reference 82720- if inPackageName { 82721- refs, err = packageReferences(ctx, snapshot, f.URI()) 82722- } else { 82723- refs, err = ordinaryReferences(ctx, snapshot, f.URI(), pp) 82724- } 82725- if err != nil { 82726- return nil, err 82727- } 82728- 82729- sort.Slice(refs, func(i, j int) bool { 82730- x, y := refs[i], refs[j] 82731- if x.isDeclaration != y.isDeclaration { 82732- return x.isDeclaration // decls < refs 82733- } 82734- return protocol.CompareLocation(x.location, y.location) < 0 82735- }) 82736- 82737- // De-duplicate by location, and optionally remove declarations. 82738- out := refs[:0] 82739- for _, ref := range refs { 82740- if !includeDeclaration && ref.isDeclaration { 82741- continue 82742- } 82743- if len(out) == 0 || out[len(out)-1].location != ref.location { 82744- out = append(out, ref) 82745- } 82746- } 82747- refs = out 82748- 82749- return refs, nil 82750-} 82751- 82752-// packageReferences returns a list of references to the package 82753-// declaration of the specified name and uri by searching among the 82754-// import declarations of all packages that directly import the target 82755-// package. 82756-func packageReferences(ctx context.Context, snapshot Snapshot, uri span.URI) ([]reference, error) { 82757- metas, err := snapshot.MetadataForFile(ctx, uri) 82758- if err != nil { 82759- return nil, err 82760- } 82761- if len(metas) == 0 { 82762- return nil, fmt.Errorf("found no package containing %s", uri) 82763- } 82764- 82765- var refs []reference 82766- 82767- // Find external references to the package declaration 82768- // from each direct import of the package. 82769- // 82770- // The narrowest package is the most broadly imported, 82771- // so we choose it for the external references. 82772- // 82773- // But if the file ends with _test.go then we need to 82774- // find the package it is testing; there's no direct way 82775- // to do that, so pick a file from the same package that 82776- // doesn't end in _test.go and start over. 82777- narrowest := metas[0] 82778- if narrowest.ForTest != "" && strings.HasSuffix(string(uri), "_test.go") { 82779- for _, f := range narrowest.CompiledGoFiles { 82780- if !strings.HasSuffix(string(f), "_test.go") { 82781- return packageReferences(ctx, snapshot, f) 82782- } 82783- } 82784- // This package has no non-test files. 82785- // Skip the search for external references. 82786- // (Conceivably one could blank-import an empty package, but why?) 82787- } else { 82788- rdeps, err := snapshot.ReverseDependencies(ctx, narrowest.ID, false) // direct 82789- if err != nil { 82790- return nil, err 82791- } 82792- for _, rdep := range rdeps { 82793- for _, uri := range rdep.CompiledGoFiles { 82794- fh, err := snapshot.GetFile(ctx, uri) 82795- if err != nil { 82796- return nil, err 82797- } 82798- f, err := snapshot.ParseGo(ctx, fh, ParseHeader) 82799- if err != nil { 82800- return nil, err 82801- } 82802- for _, imp := range f.File.Imports { 82803- if rdep.DepsByImpPath[UnquoteImportPath(imp)] == narrowest.ID { 82804- refs = append(refs, reference{ 82805- isDeclaration: false, 82806- location: mustLocation(f, imp), 82807- pkgPath: narrowest.PkgPath, 82808- }) 82809- } 82810- } 82811- } 82812- } 82813- } 82814- 82815- // Find internal "references" to the package from 82816- // of each package declaration in the target package itself. 82817- // 82818- // The widest package (possibly a test variant) has the 82819- // greatest number of files and thus we choose it for the 82820- // "internal" references. 82821- widest := metas[len(metas)-1] 82822- for _, uri := range widest.CompiledGoFiles { 82823- fh, err := snapshot.GetFile(ctx, uri) 82824- if err != nil { 82825- return nil, err 82826- } 82827- f, err := snapshot.ParseGo(ctx, fh, ParseHeader) 82828- if err != nil { 82829- return nil, err 82830- } 82831- refs = append(refs, reference{ 82832- isDeclaration: true, // (one of many) 82833- location: mustLocation(f, f.File.Name), 82834- pkgPath: widest.PkgPath, 82835- }) 82836- } 82837- 82838- return refs, nil 82839-} 82840- 82841-// ordinaryReferences computes references for all ordinary objects (not package declarations). 82842-func ordinaryReferences(ctx context.Context, snapshot Snapshot, uri span.URI, pp protocol.Position) ([]reference, error) { 82843- // Strategy: use the reference information computed by the 82844- // type checker to find the declaration. First type-check this 82845- // package to find the declaration, then type check the 82846- // declaring package (which may be different), plus variants, 82847- // to find local (in-package) references. 82848- // Global references are satisfied by the index. 82849- 82850- // Strictly speaking, a wider package could provide a different 82851- // declaration (e.g. because the _test.go files can change the 82852- // meaning of a field or method selection), but the narrower 82853- // package reports the more broadly referenced object. 82854- pkg, pgf, err := PackageForFile(ctx, snapshot, uri, NarrowestPackage) 82855- if err != nil { 82856- return nil, err 82857- } 82858- 82859- // Find the selected object (declaration or reference). 82860- pos, err := pgf.PositionPos(pp) 82861- if err != nil { 82862- return nil, err 82863- } 82864- candidates, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos) 82865- if err != nil { 82866- return nil, err 82867- } 82868- 82869- // Pick first object arbitrarily. 82870- // The case variables of a type switch have different 82871- // types but that difference is immaterial here. 82872- var obj types.Object 82873- for obj = range candidates { 82874- break 82875- } 82876- if obj == nil { 82877- return nil, ErrNoIdentFound // can't happen 82878- } 82879- 82880- // nil, error, error.Error, iota, or other built-in? 82881- if obj.Pkg() == nil { 82882- // For some reason, existing tests require that iota has no references, 82883- // nor an error. TODO(adonovan): do something more principled. 82884- if obj.Name() == "iota" { 82885- return nil, nil 82886- } 82887- 82888- return nil, fmt.Errorf("references to builtin %q are not supported", obj.Name()) 82889- } 82890- 82891- // Find metadata of all packages containing the object's defining file. 82892- // This may include the query pkg, and possibly other variants. 82893- declPosn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()) 82894- declURI := span.URIFromPath(declPosn.Filename) 82895- variants, err := snapshot.MetadataForFile(ctx, declURI) 82896- if err != nil { 82897- return nil, err 82898- } 82899- if len(variants) == 0 { 82900- return nil, fmt.Errorf("no packages for file %q", declURI) // can't happen 82901- } 82902- 82903- // Is object exported? 82904- // If so, compute scope and targets of the global search. 82905- var ( 82906- globalScope = make(map[PackageID]*Metadata) 82907- globalTargets map[PackagePath]map[objectpath.Path]unit 82908- ) 82909- // TODO(adonovan): what about generic functions. Need to consider both 82910- // uninstantiated and instantiated. The latter have no objectpath. Use Origin? 82911- if path, err := objectpath.For(obj); err == nil && obj.Exported() { 82912- pkgPath := variants[0].PkgPath // (all variants have same package path) 82913- globalTargets = map[PackagePath]map[objectpath.Path]unit{ 82914- pkgPath: {path: {}}, // primary target 82915- } 82916- 82917- // How far need we search? 82918- // For package-level objects, we need only search the direct importers. 82919- // For fields and methods, we must search transitively. 82920- transitive := obj.Pkg().Scope().Lookup(obj.Name()) != obj 82921- 82922- // The scope is the union of rdeps of each variant. 82923- // (Each set is disjoint so there's no benefit to 82924- // to combining the metadata graph traversals.) 82925- for _, m := range variants { 82926- rdeps, err := snapshot.ReverseDependencies(ctx, m.ID, transitive) 82927- if err != nil { 82928- return nil, err 82929- } 82930- for id, rdep := range rdeps { 82931- globalScope[id] = rdep 82932- } 82933- } 82934- 82935- // Is object a method? 82936- // 82937- // If so, expand the search so that the targets include 82938- // all methods that correspond to it through interface 82939- // satisfaction, and the scope includes the rdeps of 82940- // the package that declares each corresponding type. 82941- if recv := effectiveReceiver(obj); recv != nil { 82942- if err := expandMethodSearch(ctx, snapshot, obj.(*types.Func), recv, globalScope, globalTargets); err != nil { 82943- return nil, err 82944- } 82945- } 82946- } 82947- 82948- // The search functions will call report(loc) for each hit. 82949- var ( 82950- refsMu sync.Mutex 82951- refs []reference 82952- ) 82953- report := func(loc protocol.Location, isDecl bool) { 82954- ref := reference{ 82955- isDeclaration: isDecl, 82956- location: loc, 82957- pkgPath: pkg.Metadata().PkgPath, 82958- } 82959- refsMu.Lock() 82960- refs = append(refs, ref) 82961- refsMu.Unlock() 82962- } 82963- 82964- // Loop over the variants of the declaring package, 82965- // and perform both the local (in-package) and global 82966- // (cross-package) searches, in parallel. 82967- // 82968- // TODO(adonovan): opt: support LSP reference streaming. See: 82969- // - https://github.com/microsoft/vscode-languageserver-node/pull/164 82970- // - https://github.com/microsoft/language-server-protocol/pull/182 82971- // 82972- // Careful: this goroutine must not return before group.Wait. 82973- var group errgroup.Group 82974- 82975- // Compute local references for each variant. 82976- for _, m := range variants { 82977- // We want the ordinary importable package, 82978- // plus any test-augmented variants, since 82979- // declarations in _test.go files may change 82980- // the reference of a selection, or even a 82981- // field into a method or vice versa. 82982- // 82983- // But we don't need intermediate test variants, 82984- // as their local references will be covered 82985- // already by other variants. 82986- if m.IsIntermediateTestVariant() { 82987- continue 82988- } 82989- m := m 82990- group.Go(func() error { 82991- return localReferences(ctx, snapshot, declURI, declPosn.Offset, m, report) 82992- }) 82993- } 82994- 82995- // Compute global references for selected reverse dependencies. 82996- group.Go(func() error { 82997- var globalIDs []PackageID 82998- for id := range globalScope { 82999- globalIDs = append(globalIDs, id) 83000- } 83001- indexes, err := snapshot.References(ctx, globalIDs...) 83002- if err != nil { 83003- return err 83004- } 83005- for _, index := range indexes { 83006- for _, loc := range index.Lookup(globalTargets) { 83007- report(loc, false) 83008- } 83009- } 83010- return nil 83011- }) 83012- 83013- if err := group.Wait(); err != nil { 83014- return nil, err 83015- } 83016- return refs, nil 83017-} 83018- 83019-// expandMethodSearch expands the scope and targets of a global search 83020-// for an exported method to include all methods that correspond to 83021-// it through interface satisfaction. 83022-// 83023-// recv is the method's effective receiver type, for method-set computations. 83024-func expandMethodSearch(ctx context.Context, snapshot Snapshot, method *types.Func, recv types.Type, scope map[PackageID]*Metadata, targets map[PackagePath]map[objectpath.Path]unit) error { 83025- // Compute the method-set fingerprint used as a key to the global search. 83026- key, hasMethods := methodsets.KeyOf(recv) 83027- if !hasMethods { 83028- return bug.Errorf("KeyOf(%s)={} yet %s is a method", recv, method) 83029- } 83030- metas, err := snapshot.AllMetadata(ctx) 83031- if err != nil { 83032- return err 83033- } 83034- allIDs := make([]PackageID, 0, len(metas)) 83035- for _, m := range metas { 83036- allIDs = append(allIDs, m.ID) 83037- } 83038- // Search the methodset index of each package in the workspace. 83039- indexes, err := snapshot.MethodSets(ctx, allIDs...) 83040- if err != nil { 83041- return err 83042- } 83043- var mu sync.Mutex // guards scope and targets 83044- var group errgroup.Group 83045- for i, index := range indexes { 83046- i := i 83047- index := index 83048- group.Go(func() error { 83049- // Consult index for matching methods. 83050- results := index.Search(key, method.Name()) 83051- if len(results) == 0 { 83052- return nil 83053- } 83054- 83055- // Expand global search scope to include rdeps of this pkg. 83056- rdeps, err := snapshot.ReverseDependencies(ctx, allIDs[i], true) 83057- if err != nil { 83058- return err 83059- } 83060- mu.Lock() 83061- defer mu.Unlock() 83062- for _, rdep := range rdeps { 83063- scope[rdep.ID] = rdep 83064- } 83065- 83066- // Add each corresponding method the to set of global search targets. 83067- for _, res := range results { 83068- methodPkg := PackagePath(res.PkgPath) 83069- opaths, ok := targets[methodPkg] 83070- if !ok { 83071- opaths = make(map[objectpath.Path]unit) 83072- targets[methodPkg] = opaths 83073- } 83074- opaths[res.ObjectPath] = unit{} 83075- } 83076- return nil 83077- }) 83078- } 83079- return group.Wait() 83080-} 83081- 83082-// localReferences reports each reference to the object 83083-// declared at the specified URI/offset within its enclosing package m. 83084-func localReferences(ctx context.Context, snapshot Snapshot, declURI span.URI, declOffset int, m *Metadata, report func(loc protocol.Location, isDecl bool)) error { 83085- pkgs, err := snapshot.TypeCheck(ctx, m.ID) 83086- if err != nil { 83087- return err 83088- } 83089- pkg := pkgs[0] // narrowest 83090- 83091- // Find declaration of corresponding object 83092- // in this package based on (URI, offset). 83093- pgf, err := pkg.File(declURI) 83094- if err != nil { 83095- return err 83096- } 83097- pos, err := safetoken.Pos(pgf.Tok, declOffset) 83098- if err != nil { 83099- return err 83100- } 83101- targets, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos) 83102- if err != nil { 83103- return err // unreachable? (probably caught earlier) 83104- } 83105- 83106- // Report the locations of the declaration(s). 83107- // TODO(adonovan): what about for corresponding methods? Add tests. 83108- for _, node := range targets { 83109- report(mustLocation(pgf, node), true) 83110- } 83111- 83112- // If we're searching for references to a method, broaden the 83113- // search to include references to corresponding methods of 83114- // mutually assignable receiver types. 83115- // (We use a slice, but objectsAt never returns >1 methods.) 83116- var methodRecvs []types.Type 83117- var methodName string // name of an arbitrary target, iff a method 83118- for obj := range targets { 83119- if t := effectiveReceiver(obj); t != nil { 83120- methodRecvs = append(methodRecvs, t) 83121- methodName = obj.Name() 83122- } 83123- } 83124- 83125- // matches reports whether obj either is or corresponds to a target. 83126- // (Correspondence is defined as usual for interface methods.) 83127- matches := func(obj types.Object) bool { 83128- if targets[obj] != nil { 83129- return true 83130- } else if methodRecvs != nil && obj.Name() == methodName { 83131- if orecv := effectiveReceiver(obj); orecv != nil { 83132- for _, mrecv := range methodRecvs { 83133- if concreteImplementsIntf(orecv, mrecv) { 83134- return true 83135- } 83136- } 83137- } 83138- } 83139- return false 83140- } 83141- 83142- // Scan through syntax looking for uses of one of the target objects. 83143- for _, pgf := range pkg.CompiledGoFiles() { 83144- ast.Inspect(pgf.File, func(n ast.Node) bool { 83145- if id, ok := n.(*ast.Ident); ok { 83146- if obj, ok := pkg.GetTypesInfo().Uses[id]; ok && matches(obj) { 83147- report(mustLocation(pgf, id), false) 83148- } 83149- } 83150- return true 83151- }) 83152- } 83153- return nil 83154-} 83155- 83156-// effectiveReceiver returns the effective receiver type for method-set 83157-// comparisons for obj, if it is a method, or nil otherwise. 83158-func effectiveReceiver(obj types.Object) types.Type { 83159- if fn, ok := obj.(*types.Func); ok { 83160- if recv := fn.Type().(*types.Signature).Recv(); recv != nil { 83161- return methodsets.EnsurePointer(recv.Type()) 83162- } 83163- } 83164- return nil 83165-} 83166- 83167-// objectsAt returns the non-empty set of objects denoted (def or use) 83168-// by the specified position within a file syntax tree, or an error if 83169-// none were found. 83170-// 83171-// The result may contain more than one element because all case 83172-// variables of a type switch appear to be declared at the same 83173-// position. 83174-// 83175-// Each object is mapped to the syntax node that was treated as an 83176-// identifier, which is not always an ast.Ident. The second component 83177-// of the result is the innermost node enclosing pos. 83178-// 83179-// TODO(adonovan): factor in common with referencedObject. 83180-func objectsAt(info *types.Info, file *ast.File, pos token.Pos) (map[types.Object]ast.Node, ast.Node, error) { 83181- path := pathEnclosingObjNode(file, pos) 83182- if path == nil { 83183- return nil, nil, ErrNoIdentFound 83184- } 83185- 83186- targets := make(map[types.Object]ast.Node) 83187- 83188- switch leaf := path[0].(type) { 83189- case *ast.Ident: 83190- // If leaf represents an implicit type switch object or the type 83191- // switch "assign" variable, expand to all of the type switch's 83192- // implicit objects. 83193- if implicits, _ := typeSwitchImplicits(info, path); len(implicits) > 0 { 83194- for _, obj := range implicits { 83195- targets[obj] = leaf 83196- } 83197- } else { 83198- obj := info.ObjectOf(leaf) 83199- if obj == nil { 83200- return nil, nil, fmt.Errorf("%w for %q", errNoObjectFound, leaf.Name) 83201- } 83202- targets[obj] = leaf 83203- } 83204- case *ast.ImportSpec: 83205- // Look up the implicit *types.PkgName. 83206- obj := info.Implicits[leaf] 83207- if obj == nil { 83208- return nil, nil, fmt.Errorf("%w for import %s", errNoObjectFound, UnquoteImportPath(leaf)) 83209- } 83210- targets[obj] = leaf 83211- } 83212- 83213- if len(targets) == 0 { 83214- return nil, nil, fmt.Errorf("objectAt: internal error: no targets") // can't happen 83215- } 83216- return targets, path[0], nil 83217-} 83218- 83219-// mustLocation reports the location interval a syntax node, 83220-// which must belong to m.File. 83221-// 83222-// Safe for use only by references2 and implementations2. 83223-func mustLocation(pgf *ParsedGoFile, n ast.Node) protocol.Location { 83224- loc, err := pgf.NodeLocation(n) 83225- if err != nil { 83226- panic(err) // can't happen in references2 or implementations2 83227- } 83228- return loc 83229-} 83230diff -urN a/gopls/internal/lsp/source/rename_check.go b/gopls/internal/lsp/source/rename_check.go 83231--- a/gopls/internal/lsp/source/rename_check.go 2000-01-01 00:00:00.000000000 -0000 83232+++ b/gopls/internal/lsp/source/rename_check.go 1970-01-01 00:00:00.000000000 +0000 83233@@ -1,921 +0,0 @@ 83234-// Copyright 2019 The Go Authors. All rights reserved. 83235-// Use of this source code is governed by a BSD-style 83236-// license that can be found in the LICENSE file. 83237-// 83238-// Taken from golang.org/x/tools/refactor/rename. 83239- 83240-package source 83241- 83242-// This file defines the conflict-checking portion of the rename operation. 83243-// 83244-// The renamer works on a single package of type-checked syntax, and 83245-// is called in parallel for all necessary packages in the workspace, 83246-// possibly up to the transitive reverse dependencies of the 83247-// declaration. Finally the union of all edits and errors is computed. 83248-// 83249-// Renaming one object may entail renaming of others. For example: 83250-// 83251-// - An embedded field couples a Var (field) and a TypeName. 83252-// So, renaming either one requires renaming the other. 83253-// If the initial object is an embedded field, we must add its 83254-// TypeName (and its enclosing package) to the renaming set; 83255-// this is easily discovered at the outset. 83256-// 83257-// Conversely, if the initial object is a TypeName, we must observe 83258-// whether any of its references (from directly importing packages) 83259-// is coincident with an embedded field Var and, if so, initiate a 83260-// renaming of it. 83261-// 83262-// - A method of an interface type is coupled to all corresponding 83263-// methods of types that are assigned to the interface (as 83264-// discovered by the 'satisfy' pass). As a matter of usability, we 83265-// require that such renamings be initiated from the interface 83266-// method, not the concrete method. 83267- 83268-import ( 83269- "fmt" 83270- "go/ast" 83271- "go/token" 83272- "go/types" 83273- "path/filepath" 83274- "reflect" 83275- "strings" 83276- "unicode" 83277- 83278- "golang.org/x/tools/go/ast/astutil" 83279- "golang.org/x/tools/gopls/internal/lsp/safetoken" 83280- "golang.org/x/tools/refactor/satisfy" 83281-) 83282- 83283-// errorf reports an error (e.g. conflict) and prevents file modification. 83284-func (r *renamer) errorf(pos token.Pos, format string, args ...interface{}) { 83285- // Conflict error messages in the old gorename tool (whence this 83286- // logic originated) contain rich information associated with 83287- // multiple source lines, such as: 83288- // 83289- // p/a.go:1:2: renaming "x" to "y" here 83290- // p/b.go:3:4: \t would cause this reference to "y" 83291- // p/c.go:5:5: \t to become shadowed by this intervening declaration. 83292- // 83293- // Unfortunately LSP provides no means to transmit the 83294- // structure of this error, so we format the positions briefly 83295- // using dir/file.go where dir is the base name of the parent 83296- // directory. 83297- 83298- var conflict strings.Builder 83299- 83300- // Add prefix of (truncated) position. 83301- if pos != token.NoPos { 83302- // TODO(adonovan): skip position of first error if it is 83303- // on the same line as the renaming itself. 83304- posn := safetoken.StartPosition(r.pkg.FileSet(), pos).String() 83305- segments := strings.Split(filepath.ToSlash(posn), "/") 83306- if n := len(segments); n > 2 { 83307- segments = segments[n-2:] 83308- } 83309- posn = strings.Join(segments, "/") 83310- fmt.Fprintf(&conflict, "%s:", posn) 83311- 83312- if !strings.HasPrefix(format, "\t") { 83313- conflict.WriteByte(' ') 83314- } 83315- } 83316- 83317- fmt.Fprintf(&conflict, format, args...) 83318- r.conflicts = append(r.conflicts, conflict.String()) 83319-} 83320- 83321-// check performs safety checks of the renaming of the 'from' object to r.to. 83322-func (r *renamer) check(from types.Object) { 83323- if r.objsToUpdate[from] { 83324- return 83325- } 83326- r.objsToUpdate[from] = true 83327- 83328- // NB: order of conditions is important. 83329- if from_, ok := from.(*types.PkgName); ok { 83330- r.checkInFileBlock(from_) 83331- } else if from_, ok := from.(*types.Label); ok { 83332- r.checkLabel(from_) 83333- } else if isPackageLevel(from) { 83334- r.checkInPackageBlock(from) 83335- } else if v, ok := from.(*types.Var); ok && v.IsField() { 83336- r.checkStructField(v) 83337- } else if f, ok := from.(*types.Func); ok && recv(f) != nil { 83338- r.checkMethod(f) 83339- } else if isLocal(from) { 83340- r.checkInLexicalScope(from) 83341- } else { 83342- r.errorf(from.Pos(), "unexpected %s object %q (please report a bug)\n", 83343- objectKind(from), from) 83344- } 83345-} 83346- 83347-// checkInFileBlock performs safety checks for renames of objects in the file block, 83348-// i.e. imported package names. 83349-func (r *renamer) checkInFileBlock(from *types.PkgName) { 83350- // Check import name is not "init". 83351- if r.to == "init" { 83352- r.errorf(from.Pos(), "%q is not a valid imported package name", r.to) 83353- } 83354- 83355- // Check for conflicts between file and package block. 83356- if prev := from.Pkg().Scope().Lookup(r.to); prev != nil { 83357- r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", 83358- objectKind(from), from.Name(), r.to) 83359- r.errorf(prev.Pos(), "\twith this package member %s", 83360- objectKind(prev)) 83361- return // since checkInPackageBlock would report redundant errors 83362- } 83363- 83364- // Check for conflicts in lexical scope. 83365- r.checkInLexicalScope(from) 83366-} 83367- 83368-// checkInPackageBlock performs safety checks for renames of 83369-// func/var/const/type objects in the package block. 83370-func (r *renamer) checkInPackageBlock(from types.Object) { 83371- // Check that there are no references to the name from another 83372- // package if the renaming would make it unexported. 83373- if typ := r.pkg.GetTypes(); typ != from.Pkg() && ast.IsExported(r.from) && !ast.IsExported(r.to) { 83374- if id := someUse(r.pkg.GetTypesInfo(), from); id != nil { 83375- r.checkExport(id, typ, from) 83376- } 83377- } 83378- 83379- // Check that in the package block, "init" is a function, and never referenced. 83380- if r.to == "init" { 83381- kind := objectKind(from) 83382- if kind == "func" { 83383- // Reject if intra-package references to it exist. 83384- for id, obj := range r.pkg.GetTypesInfo().Uses { 83385- if obj == from { 83386- r.errorf(from.Pos(), 83387- "renaming this func %q to %q would make it a package initializer", 83388- from.Name(), r.to) 83389- r.errorf(id.Pos(), "\tbut references to it exist") 83390- break 83391- } 83392- } 83393- } else { 83394- r.errorf(from.Pos(), "you cannot have a %s at package level named %q", 83395- kind, r.to) 83396- } 83397- } 83398- 83399- // Check for conflicts between package block and all file blocks. 83400- for _, f := range r.pkg.GetSyntax() { 83401- fileScope := r.pkg.GetTypesInfo().Scopes[f] 83402- b, prev := fileScope.LookupParent(r.to, token.NoPos) 83403- if b == fileScope { 83404- r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", objectKind(from), from.Name(), r.to) 83405- var prevPos token.Pos 83406- if prev != nil { 83407- prevPos = prev.Pos() 83408- } 83409- r.errorf(prevPos, "\twith this %s", objectKind(prev)) 83410- return // since checkInPackageBlock would report redundant errors 83411- } 83412- } 83413- 83414- // Check for conflicts in lexical scope. 83415- r.checkInLexicalScope(from) 83416-} 83417- 83418-// checkInLexicalScope performs safety checks that a renaming does not 83419-// change the lexical reference structure of the specified package. 83420-// 83421-// For objects in lexical scope, there are three kinds of conflicts: 83422-// same-, sub-, and super-block conflicts. We will illustrate all three 83423-// using this example: 83424-// 83425-// var x int 83426-// var z int 83427-// 83428-// func f(y int) { 83429-// print(x) 83430-// print(y) 83431-// } 83432-// 83433-// Renaming x to z encounters a "same-block conflict", because an object 83434-// with the new name already exists, defined in the same lexical block 83435-// as the old object. 83436-// 83437-// Renaming x to y encounters a "sub-block conflict", because there exists 83438-// a reference to x from within (what would become) a hole in its scope. 83439-// The definition of y in an (inner) sub-block would cast a shadow in 83440-// the scope of the renamed variable. 83441-// 83442-// Renaming y to x encounters a "super-block conflict". This is the 83443-// converse situation: there is an existing definition of the new name 83444-// (x) in an (enclosing) super-block, and the renaming would create a 83445-// hole in its scope, within which there exist references to it. The 83446-// new name shadows the existing definition of x in the super-block. 83447-// 83448-// Removing the old name (and all references to it) is always safe, and 83449-// requires no checks. 83450-func (r *renamer) checkInLexicalScope(from types.Object) { 83451- b := from.Parent() // the block defining the 'from' object 83452- if b != nil { 83453- toBlock, to := b.LookupParent(r.to, from.Parent().End()) 83454- if toBlock == b { 83455- // same-block conflict 83456- r.errorf(from.Pos(), "renaming this %s %q to %q", 83457- objectKind(from), from.Name(), r.to) 83458- r.errorf(to.Pos(), "\tconflicts with %s in same block", 83459- objectKind(to)) 83460- return 83461- } else if toBlock != nil { 83462- // Check for super-block conflict. 83463- // The name r.to is defined in a superblock. 83464- // Is that name referenced from within this block? 83465- forEachLexicalRef(r.pkg, to, func(id *ast.Ident, block *types.Scope) bool { 83466- _, obj := block.LookupParent(from.Name(), id.Pos()) 83467- if obj == from { 83468- // super-block conflict 83469- r.errorf(from.Pos(), "renaming this %s %q to %q", 83470- objectKind(from), from.Name(), r.to) 83471- r.errorf(id.Pos(), "\twould shadow this reference") 83472- r.errorf(to.Pos(), "\tto the %s declared here", 83473- objectKind(to)) 83474- return false // stop 83475- } 83476- return true 83477- }) 83478- } 83479- } 83480- // Check for sub-block conflict. 83481- // Is there an intervening definition of r.to between 83482- // the block defining 'from' and some reference to it? 83483- forEachLexicalRef(r.pkg, from, func(id *ast.Ident, block *types.Scope) bool { 83484- // Find the block that defines the found reference. 83485- // It may be an ancestor. 83486- fromBlock, _ := block.LookupParent(from.Name(), id.Pos()) 83487- // See what r.to would resolve to in the same scope. 83488- toBlock, to := block.LookupParent(r.to, id.Pos()) 83489- if to != nil { 83490- // sub-block conflict 83491- if deeper(toBlock, fromBlock) { 83492- r.errorf(from.Pos(), "renaming this %s %q to %q", 83493- objectKind(from), from.Name(), r.to) 83494- r.errorf(id.Pos(), "\twould cause this reference to become shadowed") 83495- r.errorf(to.Pos(), "\tby this intervening %s definition", 83496- objectKind(to)) 83497- return false // stop 83498- } 83499- } 83500- return true 83501- }) 83502- 83503- // Renaming a type that is used as an embedded field 83504- // requires renaming the field too. e.g. 83505- // type T int // if we rename this to U.. 83506- // var s struct {T} 83507- // print(s.T) // ...this must change too 83508- if _, ok := from.(*types.TypeName); ok { 83509- for id, obj := range r.pkg.GetTypesInfo().Uses { 83510- if obj == from { 83511- if field := r.pkg.GetTypesInfo().Defs[id]; field != nil { 83512- r.check(field) 83513- } 83514- } 83515- } 83516- } 83517-} 83518- 83519-// deeper reports whether block x is lexically deeper than y. 83520-func deeper(x, y *types.Scope) bool { 83521- if x == y || x == nil { 83522- return false 83523- } else if y == nil { 83524- return true 83525- } else { 83526- return deeper(x.Parent(), y.Parent()) 83527- } 83528-} 83529- 83530-// forEachLexicalRef calls fn(id, block) for each identifier id in package 83531-// pkg that is a reference to obj in lexical scope. block is the 83532-// lexical block enclosing the reference. If fn returns false the 83533-// iteration is terminated and findLexicalRefs returns false. 83534-func forEachLexicalRef(pkg Package, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool { 83535- ok := true 83536- var stack []ast.Node 83537- 83538- var visit func(n ast.Node) bool 83539- visit = func(n ast.Node) bool { 83540- if n == nil { 83541- stack = stack[:len(stack)-1] // pop 83542- return false 83543- } 83544- if !ok { 83545- return false // bail out 83546- } 83547- 83548- stack = append(stack, n) // push 83549- switch n := n.(type) { 83550- case *ast.Ident: 83551- if pkg.GetTypesInfo().Uses[n] == obj { 83552- block := enclosingBlock(pkg.GetTypesInfo(), stack) 83553- if !fn(n, block) { 83554- ok = false 83555- } 83556- } 83557- return visit(nil) // pop stack 83558- 83559- case *ast.SelectorExpr: 83560- // don't visit n.Sel 83561- ast.Inspect(n.X, visit) 83562- return visit(nil) // pop stack, don't descend 83563- 83564- case *ast.CompositeLit: 83565- // Handle recursion ourselves for struct literals 83566- // so we don't visit field identifiers. 83567- tv, ok := pkg.GetTypesInfo().Types[n] 83568- if !ok { 83569- return visit(nil) // pop stack, don't descend 83570- } 83571- if _, ok := Deref(tv.Type).Underlying().(*types.Struct); ok { 83572- if n.Type != nil { 83573- ast.Inspect(n.Type, visit) 83574- } 83575- for _, elt := range n.Elts { 83576- if kv, ok := elt.(*ast.KeyValueExpr); ok { 83577- ast.Inspect(kv.Value, visit) 83578- } else { 83579- ast.Inspect(elt, visit) 83580- } 83581- } 83582- return visit(nil) // pop stack, don't descend 83583- } 83584- } 83585- return true 83586- } 83587- 83588- for _, f := range pkg.GetSyntax() { 83589- ast.Inspect(f, visit) 83590- if len(stack) != 0 { 83591- panic(stack) 83592- } 83593- if !ok { 83594- break 83595- } 83596- } 83597- return ok 83598-} 83599- 83600-// enclosingBlock returns the innermost block enclosing the specified 83601-// AST node, specified in the form of a path from the root of the file, 83602-// [file...n]. 83603-func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope { 83604- for i := range stack { 83605- n := stack[len(stack)-1-i] 83606- // For some reason, go/types always associates a 83607- // function's scope with its FuncType. 83608- // TODO(adonovan): feature or a bug? 83609- switch f := n.(type) { 83610- case *ast.FuncDecl: 83611- n = f.Type 83612- case *ast.FuncLit: 83613- n = f.Type 83614- } 83615- if b := info.Scopes[n]; b != nil { 83616- return b 83617- } 83618- } 83619- panic("no Scope for *ast.File") 83620-} 83621- 83622-func (r *renamer) checkLabel(label *types.Label) { 83623- // Check there are no identical labels in the function's label block. 83624- // (Label blocks don't nest, so this is easy.) 83625- if prev := label.Parent().Lookup(r.to); prev != nil { 83626- r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name()) 83627- r.errorf(prev.Pos(), "\twould conflict with this one") 83628- } 83629-} 83630- 83631-// checkStructField checks that the field renaming will not cause 83632-// conflicts at its declaration, or ambiguity or changes to any selection. 83633-func (r *renamer) checkStructField(from *types.Var) { 83634- // Check that the struct declaration is free of field conflicts, 83635- // and field/method conflicts. 83636- 83637- // go/types offers no easy way to get from a field (or interface 83638- // method) to its declaring struct (or interface), so we must 83639- // ascend the AST. 83640- pgf, ok := enclosingFile(r.pkg, from.Pos()) 83641- if !ok { 83642- return // not declared by syntax of this package 83643- } 83644- path, _ := astutil.PathEnclosingInterval(pgf.File, from.Pos(), from.Pos()) 83645- // path matches this pattern: 83646- // [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File] 83647- 83648- // Ascend to FieldList. 83649- var i int 83650- for { 83651- if _, ok := path[i].(*ast.FieldList); ok { 83652- break 83653- } 83654- i++ 83655- } 83656- i++ 83657- tStruct := path[i].(*ast.StructType) 83658- i++ 83659- // Ascend past parens (unlikely). 83660- for { 83661- _, ok := path[i].(*ast.ParenExpr) 83662- if !ok { 83663- break 83664- } 83665- i++ 83666- } 83667- if spec, ok := path[i].(*ast.TypeSpec); ok { 83668- // This struct is also a named type. 83669- // We must check for direct (non-promoted) field/field 83670- // and method/field conflicts. 83671- named := r.pkg.GetTypesInfo().Defs[spec.Name].Type() 83672- prev, indices, _ := types.LookupFieldOrMethod(named, true, r.pkg.GetTypes(), r.to) 83673- if len(indices) == 1 { 83674- r.errorf(from.Pos(), "renaming this field %q to %q", 83675- from.Name(), r.to) 83676- r.errorf(prev.Pos(), "\twould conflict with this %s", 83677- objectKind(prev)) 83678- return // skip checkSelections to avoid redundant errors 83679- } 83680- } else { 83681- // This struct is not a named type. 83682- // We need only check for direct (non-promoted) field/field conflicts. 83683- T := r.pkg.GetTypesInfo().Types[tStruct].Type.Underlying().(*types.Struct) 83684- for i := 0; i < T.NumFields(); i++ { 83685- if prev := T.Field(i); prev.Name() == r.to { 83686- r.errorf(from.Pos(), "renaming this field %q to %q", 83687- from.Name(), r.to) 83688- r.errorf(prev.Pos(), "\twould conflict with this field") 83689- return // skip checkSelections to avoid redundant errors 83690- } 83691- } 83692- } 83693- 83694- // Renaming an anonymous field requires renaming the type too. e.g. 83695- // print(s.T) // if we rename T to U, 83696- // type T int // this and 83697- // var s struct {T} // this must change too. 83698- if from.Anonymous() { 83699- if named, ok := from.Type().(*types.Named); ok { 83700- r.check(named.Obj()) 83701- } else if named, ok := Deref(from.Type()).(*types.Named); ok { 83702- r.check(named.Obj()) 83703- } 83704- } 83705- 83706- // Check integrity of existing (field and method) selections. 83707- r.checkSelections(from) 83708-} 83709- 83710-// checkSelections checks that all uses and selections that resolve to 83711-// the specified object would continue to do so after the renaming. 83712-func (r *renamer) checkSelections(from types.Object) { 83713- pkg := r.pkg 83714- typ := pkg.GetTypes() 83715- { 83716- if id := someUse(pkg.GetTypesInfo(), from); id != nil { 83717- if !r.checkExport(id, typ, from) { 83718- return 83719- } 83720- } 83721- 83722- for syntax, sel := range pkg.GetTypesInfo().Selections { 83723- // There may be extant selections of only the old 83724- // name or only the new name, so we must check both. 83725- // (If neither, the renaming is sound.) 83726- // 83727- // In both cases, we wish to compare the lengths 83728- // of the implicit field path (Selection.Index) 83729- // to see if the renaming would change it. 83730- // 83731- // If a selection that resolves to 'from', when renamed, 83732- // would yield a path of the same or shorter length, 83733- // this indicates ambiguity or a changed referent, 83734- // analogous to same- or sub-block lexical conflict. 83735- // 83736- // If a selection using the name 'to' would 83737- // yield a path of the same or shorter length, 83738- // this indicates ambiguity or shadowing, 83739- // analogous to same- or super-block lexical conflict. 83740- 83741- // TODO(adonovan): fix: derive from Types[syntax.X].Mode 83742- // TODO(adonovan): test with pointer, value, addressable value. 83743- isAddressable := true 83744- 83745- if sel.Obj() == from { 83746- if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil { 83747- // Renaming this existing selection of 83748- // 'from' may block access to an existing 83749- // type member named 'to'. 83750- delta := len(indices) - len(sel.Index()) 83751- if delta > 0 { 83752- continue // no ambiguity 83753- } 83754- r.selectionConflict(from, delta, syntax, obj) 83755- return 83756- } 83757- } else if sel.Obj().Name() == r.to { 83758- if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from { 83759- // Renaming 'from' may cause this existing 83760- // selection of the name 'to' to change 83761- // its meaning. 83762- delta := len(indices) - len(sel.Index()) 83763- if delta > 0 { 83764- continue // no ambiguity 83765- } 83766- r.selectionConflict(from, -delta, syntax, sel.Obj()) 83767- return 83768- } 83769- } 83770- } 83771- } 83772-} 83773- 83774-func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) { 83775- r.errorf(from.Pos(), "renaming this %s %q to %q", 83776- objectKind(from), from.Name(), r.to) 83777- 83778- switch { 83779- case delta < 0: 83780- // analogous to sub-block conflict 83781- r.errorf(syntax.Sel.Pos(), 83782- "\twould change the referent of this selection") 83783- r.errorf(obj.Pos(), "\tof this %s", objectKind(obj)) 83784- case delta == 0: 83785- // analogous to same-block conflict 83786- r.errorf(syntax.Sel.Pos(), 83787- "\twould make this reference ambiguous") 83788- r.errorf(obj.Pos(), "\twith this %s", objectKind(obj)) 83789- case delta > 0: 83790- // analogous to super-block conflict 83791- r.errorf(syntax.Sel.Pos(), 83792- "\twould shadow this selection") 83793- r.errorf(obj.Pos(), "\tof the %s declared here", 83794- objectKind(obj)) 83795- } 83796-} 83797- 83798-// checkMethod performs safety checks for renaming a method. 83799-// There are three hazards: 83800-// - declaration conflicts 83801-// - selection ambiguity/changes 83802-// - entailed renamings of assignable concrete/interface types. 83803-// 83804-// We reject renamings initiated at concrete methods if it would 83805-// change the assignability relation. For renamings of abstract 83806-// methods, we rename all methods transitively coupled to it via 83807-// assignability. 83808-func (r *renamer) checkMethod(from *types.Func) { 83809- // e.g. error.Error 83810- if from.Pkg() == nil { 83811- r.errorf(from.Pos(), "you cannot rename built-in method %s", from) 83812- return 83813- } 83814- 83815- // ASSIGNABILITY: We reject renamings of concrete methods that 83816- // would break a 'satisfy' constraint; but renamings of abstract 83817- // methods are allowed to proceed, and we rename affected 83818- // concrete and abstract methods as necessary. It is the 83819- // initial method that determines the policy. 83820- 83821- // Check for conflict at point of declaration. 83822- // Check to ensure preservation of assignability requirements. 83823- R := recv(from).Type() 83824- if types.IsInterface(R) { 83825- // Abstract method 83826- 83827- // declaration 83828- prev, _, _ := types.LookupFieldOrMethod(R, false, from.Pkg(), r.to) 83829- if prev != nil { 83830- r.errorf(from.Pos(), "renaming this interface method %q to %q", 83831- from.Name(), r.to) 83832- r.errorf(prev.Pos(), "\twould conflict with this method") 83833- return 83834- } 83835- 83836- // Check all interfaces that embed this one for 83837- // declaration conflicts too. 83838- { 83839- // Start with named interface types (better errors) 83840- for _, obj := range r.pkg.GetTypesInfo().Defs { 83841- if obj, ok := obj.(*types.TypeName); ok && types.IsInterface(obj.Type()) { 83842- f, _, _ := types.LookupFieldOrMethod( 83843- obj.Type(), false, from.Pkg(), from.Name()) 83844- if f == nil { 83845- continue 83846- } 83847- t, _, _ := types.LookupFieldOrMethod( 83848- obj.Type(), false, from.Pkg(), r.to) 83849- if t == nil { 83850- continue 83851- } 83852- r.errorf(from.Pos(), "renaming this interface method %q to %q", 83853- from.Name(), r.to) 83854- r.errorf(t.Pos(), "\twould conflict with this method") 83855- r.errorf(obj.Pos(), "\tin named interface type %q", obj.Name()) 83856- } 83857- } 83858- 83859- // Now look at all literal interface types (includes named ones again). 83860- for e, tv := range r.pkg.GetTypesInfo().Types { 83861- if e, ok := e.(*ast.InterfaceType); ok { 83862- _ = e 83863- _ = tv.Type.(*types.Interface) 83864- // TODO(adonovan): implement same check as above. 83865- } 83866- } 83867- } 83868- 83869- // assignability 83870- // 83871- // Find the set of concrete or abstract methods directly 83872- // coupled to abstract method 'from' by some 83873- // satisfy.Constraint, and rename them too. 83874- for key := range r.satisfy() { 83875- // key = (lhs, rhs) where lhs is always an interface. 83876- 83877- lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name()) 83878- if lsel == nil { 83879- continue 83880- } 83881- rmethods := r.msets.MethodSet(key.RHS) 83882- rsel := rmethods.Lookup(from.Pkg(), from.Name()) 83883- if rsel == nil { 83884- continue 83885- } 83886- 83887- // If both sides have a method of this name, 83888- // and one of them is m, the other must be coupled. 83889- var coupled *types.Func 83890- switch from { 83891- case lsel.Obj(): 83892- coupled = rsel.Obj().(*types.Func) 83893- case rsel.Obj(): 83894- coupled = lsel.Obj().(*types.Func) 83895- default: 83896- continue 83897- } 83898- 83899- // We must treat concrete-to-interface 83900- // constraints like an implicit selection C.f of 83901- // each interface method I.f, and check that the 83902- // renaming leaves the selection unchanged and 83903- // unambiguous. 83904- // 83905- // Fun fact: the implicit selection of C.f 83906- // type I interface{f()} 83907- // type C struct{I} 83908- // func (C) g() 83909- // var _ I = C{} // here 83910- // yields abstract method I.f. This can make error 83911- // messages less than obvious. 83912- // 83913- if !types.IsInterface(key.RHS) { 83914- // The logic below was derived from checkSelections. 83915- 83916- rtosel := rmethods.Lookup(from.Pkg(), r.to) 83917- if rtosel != nil { 83918- rto := rtosel.Obj().(*types.Func) 83919- delta := len(rsel.Index()) - len(rtosel.Index()) 83920- if delta < 0 { 83921- continue // no ambiguity 83922- } 83923- 83924- // TODO(adonovan): record the constraint's position. 83925- keyPos := token.NoPos 83926- 83927- r.errorf(from.Pos(), "renaming this method %q to %q", 83928- from.Name(), r.to) 83929- if delta == 0 { 83930- // analogous to same-block conflict 83931- r.errorf(keyPos, "\twould make the %s method of %s invoked via interface %s ambiguous", 83932- r.to, key.RHS, key.LHS) 83933- r.errorf(rto.Pos(), "\twith (%s).%s", 83934- recv(rto).Type(), r.to) 83935- } else { 83936- // analogous to super-block conflict 83937- r.errorf(keyPos, "\twould change the %s method of %s invoked via interface %s", 83938- r.to, key.RHS, key.LHS) 83939- r.errorf(coupled.Pos(), "\tfrom (%s).%s", 83940- recv(coupled).Type(), r.to) 83941- r.errorf(rto.Pos(), "\tto (%s).%s", 83942- recv(rto).Type(), r.to) 83943- } 83944- return // one error is enough 83945- } 83946- } 83947- 83948- if !r.changeMethods { 83949- // This should be unreachable. 83950- r.errorf(from.Pos(), "internal error: during renaming of abstract method %s", from) 83951- r.errorf(coupled.Pos(), "\tchangedMethods=false, coupled method=%s", coupled) 83952- r.errorf(from.Pos(), "\tPlease file a bug report") 83953- return 83954- } 83955- 83956- // Rename the coupled method to preserve assignability. 83957- r.check(coupled) 83958- } 83959- } else { 83960- // Concrete method 83961- 83962- // declaration 83963- prev, indices, _ := types.LookupFieldOrMethod(R, true, from.Pkg(), r.to) 83964- if prev != nil && len(indices) == 1 { 83965- r.errorf(from.Pos(), "renaming this method %q to %q", 83966- from.Name(), r.to) 83967- r.errorf(prev.Pos(), "\twould conflict with this %s", 83968- objectKind(prev)) 83969- return 83970- } 83971- 83972- // assignability 83973- // 83974- // Find the set of abstract methods coupled to concrete 83975- // method 'from' by some satisfy.Constraint, and rename 83976- // them too. 83977- // 83978- // Coupling may be indirect, e.g. I.f <-> C.f via type D. 83979- // 83980- // type I interface {f()} 83981- // type C int 83982- // type (C) f() 83983- // type D struct{C} 83984- // var _ I = D{} 83985- // 83986- for key := range r.satisfy() { 83987- // key = (lhs, rhs) where lhs is always an interface. 83988- if types.IsInterface(key.RHS) { 83989- continue 83990- } 83991- rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name()) 83992- if rsel == nil || rsel.Obj() != from { 83993- continue // rhs does not have the method 83994- } 83995- lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name()) 83996- if lsel == nil { 83997- continue 83998- } 83999- imeth := lsel.Obj().(*types.Func) 84000- 84001- // imeth is the abstract method (e.g. I.f) 84002- // and key.RHS is the concrete coupling type (e.g. D). 84003- if !r.changeMethods { 84004- r.errorf(from.Pos(), "renaming this method %q to %q", 84005- from.Name(), r.to) 84006- var pos token.Pos 84007- var iface string 84008- 84009- I := recv(imeth).Type() 84010- if named, ok := I.(*types.Named); ok { 84011- pos = named.Obj().Pos() 84012- iface = "interface " + named.Obj().Name() 84013- } else { 84014- pos = from.Pos() 84015- iface = I.String() 84016- } 84017- r.errorf(pos, "\twould make %s no longer assignable to %s", 84018- key.RHS, iface) 84019- r.errorf(imeth.Pos(), "\t(rename %s.%s if you intend to change both types)", 84020- I, from.Name()) 84021- return // one error is enough 84022- } 84023- 84024- // Rename the coupled interface method to preserve assignability. 84025- r.check(imeth) 84026- } 84027- } 84028- 84029- // Check integrity of existing (field and method) selections. 84030- // We skip this if there were errors above, to avoid redundant errors. 84031- r.checkSelections(from) 84032-} 84033- 84034-func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool { 84035- // Reject cross-package references if r.to is unexported. 84036- // (Such references may be qualified identifiers or field/method 84037- // selections.) 84038- if !ast.IsExported(r.to) && pkg != from.Pkg() { 84039- r.errorf(from.Pos(), 84040- "renaming %q to %q would make it unexported", 84041- from.Name(), r.to) 84042- r.errorf(id.Pos(), "\tbreaking references from packages such as %q", 84043- pkg.Path()) 84044- return false 84045- } 84046- return true 84047-} 84048- 84049-// satisfy returns the set of interface satisfaction constraints. 84050-func (r *renamer) satisfy() map[satisfy.Constraint]bool { 84051- if r.satisfyConstraints == nil { 84052- // Compute on demand: it's expensive. 84053- var f satisfy.Finder 84054- pkg := r.pkg 84055- { 84056- // From satisfy.Finder documentation: 84057- // 84058- // The package must be free of type errors, and 84059- // info.{Defs,Uses,Selections,Types} must have been populated by the 84060- // type-checker. 84061- // 84062- // Only proceed if all packages have no errors. 84063- if pkg.HasParseErrors() || pkg.HasTypeErrors() { 84064- r.errorf(token.NoPos, // we don't have a position for this error. 84065- "renaming %q to %q not possible because %q has errors", 84066- r.from, r.to, pkg.Metadata().PkgPath) 84067- return nil 84068- } 84069- f.Find(pkg.GetTypesInfo(), pkg.GetSyntax()) 84070- } 84071- r.satisfyConstraints = f.Result 84072- } 84073- return r.satisfyConstraints 84074-} 84075- 84076-// -- helpers ---------------------------------------------------------- 84077- 84078-// recv returns the method's receiver. 84079-func recv(meth *types.Func) *types.Var { 84080- return meth.Type().(*types.Signature).Recv() 84081-} 84082- 84083-// someUse returns an arbitrary use of obj within info. 84084-func someUse(info *types.Info, obj types.Object) *ast.Ident { 84085- for id, o := range info.Uses { 84086- if o == obj { 84087- return id 84088- } 84089- } 84090- return nil 84091-} 84092- 84093-func objectKind(obj types.Object) string { 84094- if obj == nil { 84095- return "nil object" 84096- } 84097- switch obj := obj.(type) { 84098- case *types.PkgName: 84099- return "imported package name" 84100- case *types.TypeName: 84101- return "type" 84102- case *types.Var: 84103- if obj.IsField() { 84104- return "field" 84105- } 84106- case *types.Func: 84107- if obj.Type().(*types.Signature).Recv() != nil { 84108- return "method" 84109- } 84110- } 84111- // label, func, var, const 84112- return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types.")) 84113-} 84114- 84115-// NB: for renamings, blank is not considered valid. 84116-func isValidIdentifier(id string) bool { 84117- if id == "" || id == "_" { 84118- return false 84119- } 84120- for i, r := range id { 84121- if !isLetter(r) && (i == 0 || !isDigit(r)) { 84122- return false 84123- } 84124- } 84125- return token.Lookup(id) == token.IDENT 84126-} 84127- 84128-// isLocal reports whether obj is local to some function. 84129-// Precondition: not a struct field or interface method. 84130-func isLocal(obj types.Object) bool { 84131- // [... 5=stmt 4=func 3=file 2=pkg 1=universe] 84132- var depth int 84133- for scope := obj.Parent(); scope != nil; scope = scope.Parent() { 84134- depth++ 84135- } 84136- return depth >= 4 84137-} 84138- 84139-func isPackageLevel(obj types.Object) bool { 84140- if obj == nil { 84141- return false 84142- } 84143- return obj.Pkg().Scope().Lookup(obj.Name()) == obj 84144-} 84145- 84146-// -- Plundered from go/scanner: --------------------------------------- 84147- 84148-func isLetter(ch rune) bool { 84149- return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) 84150-} 84151- 84152-func isDigit(ch rune) bool { 84153- return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) 84154-} 84155diff -urN a/gopls/internal/lsp/source/rename.go b/gopls/internal/lsp/source/rename.go 84156--- a/gopls/internal/lsp/source/rename.go 2000-01-01 00:00:00.000000000 -0000 84157+++ b/gopls/internal/lsp/source/rename.go 1970-01-01 00:00:00.000000000 +0000 84158@@ -1,1244 +0,0 @@ 84159-// Copyright 2019 The Go Authors. All rights reserved. 84160-// Use of this source code is governed by a BSD-style 84161-// license that can be found in the LICENSE file. 84162- 84163-package source 84164- 84165-// TODO(adonovan): 84166-// 84167-// - method of generic concrete type -> arbitrary instances of same 84168-// 84169-// - make satisfy work across packages. 84170-// 84171-// - tests, tests, tests: 84172-// - play with renamings in the k8s tree. 84173-// - generics 84174-// - error cases (e.g. conflicts) 84175-// - renaming a symbol declared in the module cache 84176-// (currently proceeds with half of the renaming!) 84177-// - make sure all tests have both a local and a cross-package analogue. 84178-// - look at coverage 84179-// - special cases: embedded fields, interfaces, test variants, 84180-// function-local things with uppercase names; 84181-// packages with type errors (currently 'satisfy' rejects them), 84182-// pakage with missing imports; 84183-// 84184-// - measure performance in k8s. 84185-// 84186-// - The original gorename tool assumed well-typedness, but the gopls feature 84187-// does no such check (which actually makes it much more useful). 84188-// Audit to ensure it is safe on ill-typed code. 84189-// 84190-// - Generics support was no doubt buggy before but incrementalization 84191-// may have exacerbated it. If the problem were just about objects, 84192-// defs and uses it would be fairly simple, but type assignability 84193-// comes into play in the 'satisfy' check for method renamings. 84194-// De-instantiating Vector[int] to Vector[T] changes its type. 84195-// We need to come up with a theory for the satisfy check that 84196-// works with generics, and across packages. We currently have no 84197-// simple way to pass types between packages (think: objectpath for 84198-// types), though presumably exportdata could be pressed into service. 84199-// 84200-// - FileID-based de-duplication of edits to different URIs for the same file. 84201- 84202-import ( 84203- "context" 84204- "errors" 84205- "fmt" 84206- "go/ast" 84207- "go/token" 84208- "go/types" 84209- "path" 84210- "path/filepath" 84211- "regexp" 84212- "sort" 84213- "strconv" 84214- "strings" 84215- 84216- "golang.org/x/mod/modfile" 84217- "golang.org/x/tools/go/ast/astutil" 84218- "golang.org/x/tools/go/types/objectpath" 84219- "golang.org/x/tools/go/types/typeutil" 84220- "golang.org/x/tools/gopls/internal/lsp/protocol" 84221- "golang.org/x/tools/gopls/internal/lsp/safetoken" 84222- "golang.org/x/tools/gopls/internal/span" 84223- "golang.org/x/tools/internal/bug" 84224- "golang.org/x/tools/internal/diff" 84225- "golang.org/x/tools/internal/event" 84226- "golang.org/x/tools/internal/typeparams" 84227- "golang.org/x/tools/refactor/satisfy" 84228-) 84229- 84230-// A renamer holds state of a single call to renameObj, which renames 84231-// an object (or several coupled objects) within a single type-checked 84232-// syntax package. 84233-type renamer struct { 84234- pkg Package // the syntax package in which the renaming is applied 84235- objsToUpdate map[types.Object]bool // records progress of calls to check 84236- hadConflicts bool 84237- conflicts []string 84238- from, to string 84239- satisfyConstraints map[satisfy.Constraint]bool 84240- msets typeutil.MethodSetCache 84241- changeMethods bool 84242-} 84243- 84244-// A PrepareItem holds the result of a "prepare rename" operation: 84245-// the source range and value of a selected identifier. 84246-type PrepareItem struct { 84247- Range protocol.Range 84248- Text string 84249-} 84250- 84251-// PrepareRename searches for a valid renaming at position pp. 84252-// 84253-// The returned usererr is intended to be displayed to the user to explain why 84254-// the prepare fails. Probably we could eliminate the redundancy in returning 84255-// two errors, but for now this is done defensively. 84256-func PrepareRename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position) (_ *PrepareItem, usererr, err error) { 84257- ctx, done := event.Start(ctx, "source.PrepareRename") 84258- defer done() 84259- 84260- // Is the cursor within the package name declaration? 84261- if pgf, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp); err != nil { 84262- return nil, err, err 84263- } else if inPackageName { 84264- item, err := prepareRenamePackageName(ctx, snapshot, pgf) 84265- return item, err, err 84266- } 84267- 84268- // Ordinary (non-package) renaming. 84269- // 84270- // Type-check the current package, locate the reference at the position, 84271- // validate the object, and report its name and range. 84272- // 84273- // TODO(adonovan): in all cases below, we return usererr=nil, 84274- // which means we return (nil, nil) at the protocol 84275- // layer. This seems like a bug, or at best an exploitation of 84276- // knowledge of VSCode-specific behavior. Can we avoid that? 84277- pkg, pgf, err := PackageForFile(ctx, snapshot, f.URI(), NarrowestPackage) 84278- if err != nil { 84279- return nil, nil, err 84280- } 84281- pos, err := pgf.PositionPos(pp) 84282- if err != nil { 84283- return nil, nil, err 84284- } 84285- targets, node, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos) 84286- if err != nil { 84287- return nil, nil, err 84288- } 84289- var obj types.Object 84290- for obj = range targets { 84291- break // pick one arbitrarily 84292- } 84293- if err := checkRenamable(obj); err != nil { 84294- return nil, nil, err 84295- } 84296- rng, err := pgf.NodeRange(node) 84297- if err != nil { 84298- return nil, nil, err 84299- } 84300- if _, isImport := node.(*ast.ImportSpec); isImport { 84301- // We're not really renaming the import path. 84302- rng.End = rng.Start 84303- } 84304- return &PrepareItem{ 84305- Range: rng, 84306- Text: obj.Name(), 84307- }, nil, nil 84308-} 84309- 84310-func prepareRenamePackageName(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile) (*PrepareItem, error) { 84311- // Does the client support file renaming? 84312- fileRenameSupported := false 84313- for _, op := range snapshot.View().Options().SupportedResourceOperations { 84314- if op == protocol.Rename { 84315- fileRenameSupported = true 84316- break 84317- } 84318- } 84319- if !fileRenameSupported { 84320- return nil, errors.New("can't rename package: LSP client does not support file renaming") 84321- } 84322- 84323- // Check validity of the metadata for the file's containing package. 84324- fileMeta, err := snapshot.MetadataForFile(ctx, pgf.URI) 84325- if err != nil { 84326- return nil, err 84327- } 84328- if len(fileMeta) == 0 { 84329- return nil, fmt.Errorf("no packages found for file %q", pgf.URI) 84330- } 84331- meta := fileMeta[0] 84332- if meta.Name == "main" { 84333- return nil, fmt.Errorf("can't rename package \"main\"") 84334- } 84335- if strings.HasSuffix(string(meta.Name), "_test") { 84336- return nil, fmt.Errorf("can't rename x_test packages") 84337- } 84338- if meta.Module == nil { 84339- return nil, fmt.Errorf("can't rename package: missing module information for package %q", meta.PkgPath) 84340- } 84341- if meta.Module.Path == string(meta.PkgPath) { 84342- return nil, fmt.Errorf("can't rename package: package path %q is the same as module path %q", meta.PkgPath, meta.Module.Path) 84343- } 84344- 84345- // Return the location of the package declaration. 84346- rng, err := pgf.NodeRange(pgf.File.Name) 84347- if err != nil { 84348- return nil, err 84349- } 84350- return &PrepareItem{ 84351- Range: rng, 84352- Text: string(meta.Name), 84353- }, nil 84354-} 84355- 84356-func checkRenamable(obj types.Object) error { 84357- switch obj := obj.(type) { 84358- case *types.Var: 84359- if obj.Embedded() { 84360- return fmt.Errorf("can't rename embedded fields: rename the type directly or name the field") 84361- } 84362- case *types.Builtin, *types.Nil: 84363- return fmt.Errorf("%s is built in and cannot be renamed", obj.Name()) 84364- } 84365- if obj.Pkg() == nil || obj.Pkg().Path() == "unsafe" { 84366- // e.g. error.Error, unsafe.Pointer 84367- return fmt.Errorf("%s is built in and cannot be renamed", obj.Name()) 84368- } 84369- if obj.Name() == "_" { 84370- return errors.New("can't rename \"_\"") 84371- } 84372- return nil 84373-} 84374- 84375-// Rename returns a map of TextEdits for each file modified when renaming a 84376-// given identifier within a package and a boolean value of true for renaming 84377-// package and false otherwise. 84378-func Rename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, newName string) (map[span.URI][]protocol.TextEdit, bool, error) { 84379- ctx, done := event.Start(ctx, "source.Rename") 84380- defer done() 84381- 84382- if !isValidIdentifier(newName) { 84383- return nil, false, fmt.Errorf("invalid identifier to rename: %q", newName) 84384- } 84385- 84386- // Cursor within package name declaration? 84387- _, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp) 84388- if err != nil { 84389- return nil, false, err 84390- } 84391- 84392- var editMap map[span.URI][]diff.Edit 84393- if inPackageName { 84394- editMap, err = renamePackageName(ctx, snapshot, f, PackageName(newName)) 84395- } else { 84396- editMap, err = renameOrdinary(ctx, snapshot, f, pp, newName) 84397- } 84398- if err != nil { 84399- return nil, false, err 84400- } 84401- 84402- // Convert edits to protocol form. 84403- result := make(map[span.URI][]protocol.TextEdit) 84404- for uri, edits := range editMap { 84405- // Sort and de-duplicate edits. 84406- // 84407- // Overlapping edits may arise in local renamings (due 84408- // to type switch implicits) and globals ones (due to 84409- // processing multiple package variants). 84410- // 84411- // We assume renaming produces diffs that are all 84412- // replacements (no adjacent insertions that might 84413- // become reordered) and that are either identical or 84414- // non-overlapping. 84415- diff.SortEdits(edits) 84416- filtered := edits[:0] 84417- for i, edit := range edits { 84418- if i == 0 || edit != filtered[len(filtered)-1] { 84419- filtered = append(filtered, edit) 84420- } 84421- } 84422- edits = filtered 84423- 84424- // TODO(adonovan): the logic above handles repeat edits to the 84425- // same file URI (e.g. as a member of package p and p_test) but 84426- // is not sufficient to handle file-system level aliasing arising 84427- // from symbolic or hard links. For that, we should use a 84428- // robustio-FileID-keyed map. 84429- // See https://go.dev/cl/457615 for example. 84430- // This really occurs in practice, e.g. kubernetes has 84431- // vendor/k8s.io/kubectl -> ../../staging/src/k8s.io/kubectl. 84432- fh, err := snapshot.GetFile(ctx, uri) 84433- if err != nil { 84434- return nil, false, err 84435- } 84436- data, err := fh.Read() 84437- if err != nil { 84438- return nil, false, err 84439- } 84440- m := protocol.NewMapper(uri, data) 84441- protocolEdits, err := ToProtocolEdits(m, edits) 84442- if err != nil { 84443- return nil, false, err 84444- } 84445- result[uri] = protocolEdits 84446- } 84447- 84448- return result, inPackageName, nil 84449-} 84450- 84451-// renameOrdinary renames an ordinary (non-package) name throughout the workspace. 84452-func renameOrdinary(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, newName string) (map[span.URI][]diff.Edit, error) { 84453- // Type-check the referring package and locate the object(s). 84454- // We choose the widest variant as, for non-exported 84455- // identifiers, it is the only package we need. 84456- pkg, pgf, err := PackageForFile(ctx, snapshot, f.URI(), WidestPackage) 84457- if err != nil { 84458- return nil, err 84459- } 84460- pos, err := pgf.PositionPos(pp) 84461- if err != nil { 84462- return nil, err 84463- } 84464- targets, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos) 84465- if err != nil { 84466- return nil, err 84467- } 84468- 84469- // Pick a representative object arbitrarily. 84470- // (All share the same name, pos, and kind.) 84471- var obj types.Object 84472- for obj = range targets { 84473- break 84474- } 84475- if obj.Name() == newName { 84476- return nil, fmt.Errorf("old and new names are the same: %s", newName) 84477- } 84478- if err := checkRenamable(obj); err != nil { 84479- return nil, err 84480- } 84481- 84482- // Find objectpath, if object is exported ("" otherwise). 84483- var declObjPath objectpath.Path 84484- if obj.Exported() { 84485- // objectpath.For requires the origin of a generic 84486- // function or type, not an instantiation (a bug?). 84487- // Unfortunately we can't call {Func,TypeName}.Origin 84488- // as these are not available in go/types@go1.18. 84489- // So we take a scenic route. 84490- switch obj.(type) { // avoid "obj :=" since cases reassign the var 84491- case *types.TypeName: 84492- if named, ok := obj.Type().(*types.Named); ok { 84493- obj = named.Obj() 84494- } 84495- case *types.Func: 84496- obj = funcOrigin(obj.(*types.Func)) 84497- case *types.Var: 84498- // TODO(adonovan): do vars need the origin treatment too? (issue #58462) 84499- } 84500- if path, err := objectpath.For(obj); err == nil { 84501- declObjPath = path 84502- } 84503- } 84504- 84505- // Nonexported? Search locally. 84506- if declObjPath == "" { 84507- var objects []types.Object 84508- for obj := range targets { 84509- objects = append(objects, obj) 84510- } 84511- editMap, _, err := renameObjects(ctx, snapshot, newName, pkg, objects...) 84512- return editMap, err 84513- } 84514- 84515- // Exported: search globally. 84516- // 84517- // For exported package-level var/const/func/type objects, the 84518- // search scope is just the direct importers. 84519- // 84520- // For exported fields and methods, the scope is the 84521- // transitive rdeps. (The exportedness of the field's struct 84522- // or method's receiver is irrelevant.) 84523- transitive := false 84524- switch obj.(type) { 84525- case *types.TypeName: 84526- // Renaming an exported package-level type 84527- // requires us to inspect all transitive rdeps 84528- // in the event that the type is embedded. 84529- // 84530- // TODO(adonovan): opt: this is conservative 84531- // but inefficient. Instead, expand the scope 84532- // of the search only if we actually encounter 84533- // an embedding of the type, and only then to 84534- // the rdeps of the embedding package. 84535- if obj.Parent() == obj.Pkg().Scope() { 84536- transitive = true 84537- } 84538- 84539- case *types.Var: 84540- if obj.(*types.Var).IsField() { 84541- transitive = true // field 84542- } 84543- 84544- // TODO(adonovan): opt: process only packages that 84545- // contain a reference (xrefs) to the target field. 84546- 84547- case *types.Func: 84548- if obj.Type().(*types.Signature).Recv() != nil { 84549- transitive = true // method 84550- } 84551- 84552- // It's tempting to optimize by skipping 84553- // packages that don't contain a reference to 84554- // the method in the xrefs index, but we still 84555- // need to apply the satisfy check to those 84556- // packages to find assignment statements that 84557- // might expands the scope of the renaming. 84558- } 84559- 84560- // Type-check all the packages to inspect. 84561- declURI := span.URIFromPath(pkg.FileSet().File(obj.Pos()).Name()) 84562- pkgs, err := typeCheckReverseDependencies(ctx, snapshot, declURI, transitive) 84563- if err != nil { 84564- return nil, err 84565- } 84566- 84567- // Apply the renaming to the (initial) object. 84568- declPkgPath := PackagePath(obj.Pkg().Path()) 84569- return renameExported(ctx, snapshot, pkgs, declPkgPath, declObjPath, newName) 84570-} 84571- 84572-// funcOrigin is a go1.18-portable implementation of (*types.Func).Origin. 84573-func funcOrigin(fn *types.Func) *types.Func { 84574- // Method? 84575- if fn.Type().(*types.Signature).Recv() != nil { 84576- return typeparams.OriginMethod(fn) 84577- } 84578- 84579- // Package-level function? 84580- // (Assume the origin has the same position.) 84581- gen := fn.Pkg().Scope().Lookup(fn.Name()) 84582- if gen != nil && gen.Pos() == fn.Pos() { 84583- return gen.(*types.Func) 84584- } 84585- 84586- return fn 84587-} 84588- 84589-// typeCheckReverseDependencies returns the type-checked packages for 84590-// the reverse dependencies of all packages variants containing 84591-// file declURI. The packages are in some topological order. 84592-// 84593-// It includes all variants (even intermediate test variants) for the 84594-// purposes of computing reverse dependencies, but discards ITVs for 84595-// the actual renaming work. 84596-// 84597-// (This neglects obscure edge cases where a _test.go file changes the 84598-// selectors used only in an ITV, but life is short. Also sin must be 84599-// punished.) 84600-func typeCheckReverseDependencies(ctx context.Context, snapshot Snapshot, declURI span.URI, transitive bool) ([]Package, error) { 84601- variants, err := snapshot.MetadataForFile(ctx, declURI) 84602- if err != nil { 84603- return nil, err 84604- } 84605- allRdeps := make(map[PackageID]*Metadata) 84606- for _, variant := range variants { 84607- rdeps, err := snapshot.ReverseDependencies(ctx, variant.ID, transitive) 84608- if err != nil { 84609- return nil, err 84610- } 84611- allRdeps[variant.ID] = variant // include self 84612- for id, meta := range rdeps { 84613- allRdeps[id] = meta 84614- } 84615- } 84616- var ids []PackageID 84617- for id, meta := range allRdeps { 84618- if meta.IsIntermediateTestVariant() { 84619- continue 84620- } 84621- ids = append(ids, id) 84622- } 84623- 84624- // Sort the packages into some topological order of the 84625- // (unfiltered) metadata graph. 84626- SortPostOrder(snapshot, ids) 84627- 84628- // Dependencies must be visited first since they can expand 84629- // the search set. Ideally we would process the (filtered) set 84630- // of packages in the parallel postorder of the snapshot's 84631- // (unfiltered) metadata graph, but this is quite tricky 84632- // without a good graph abstraction. 84633- // 84634- // For now, we visit packages sequentially in order of 84635- // ascending height, like an inverted breadth-first search. 84636- // 84637- // Type checking is by far the dominant cost, so 84638- // overlapping it with renaming may not be worthwhile. 84639- return snapshot.TypeCheck(ctx, ids...) 84640-} 84641- 84642-// SortPostOrder sorts the IDs so that if x depends on y, then y appears before x. 84643-func SortPostOrder(meta MetadataSource, ids []PackageID) { 84644- postorder := make(map[PackageID]int) 84645- order := 0 84646- var visit func(PackageID) 84647- visit = func(id PackageID) { 84648- if _, ok := postorder[id]; !ok { 84649- postorder[id] = -1 // break recursion 84650- if m := meta.Metadata(id); m != nil { 84651- for _, depID := range m.DepsByPkgPath { 84652- visit(depID) 84653- } 84654- } 84655- order++ 84656- postorder[id] = order 84657- } 84658- } 84659- for _, id := range ids { 84660- visit(id) 84661- } 84662- sort.Slice(ids, func(i, j int) bool { 84663- return postorder[ids[i]] < postorder[ids[j]] 84664- }) 84665-} 84666- 84667-// renameExported renames the object denoted by (pkgPath, objPath) 84668-// within the specified packages, along with any other objects that 84669-// must be renamed as a consequence. The slice of packages must be 84670-// topologically ordered. 84671-func renameExported(ctx context.Context, snapshot Snapshot, pkgs []Package, declPkgPath PackagePath, declObjPath objectpath.Path, newName string) (map[span.URI][]diff.Edit, error) { 84672- 84673- // A target is a name for an object that is stable across types.Packages. 84674- type target struct { 84675- pkg PackagePath 84676- obj objectpath.Path 84677- } 84678- 84679- // Populate the initial set of target objects. 84680- // This set may grow as we discover the consequences of each renaming. 84681- // 84682- // TODO(adonovan): strictly, each cone of reverse dependencies 84683- // of a single variant should have its own target map that 84684- // monotonically expands as we go up the import graph, because 84685- // declarations in test files can alter the set of 84686- // package-level names and change the meaning of field and 84687- // method selectors. So if we parallelize the graph 84688- // visitation (see above), we should also compute the targets 84689- // as a union of dependencies. 84690- // 84691- // Or we could decide that the logic below is fast enough not 84692- // to need parallelism. In small measurements so far the 84693- // type-checking step is about 95% and the renaming only 5%. 84694- targets := map[target]bool{{declPkgPath, declObjPath}: true} 84695- 84696- // Apply the renaming operation to each package. 84697- allEdits := make(map[span.URI][]diff.Edit) 84698- for _, pkg := range pkgs { 84699- 84700- // Resolved target objects within package pkg. 84701- var objects []types.Object 84702- for t := range targets { 84703- p := pkg.DependencyTypes(t.pkg) 84704- if p == nil { 84705- continue // indirect dependency of no consequence 84706- } 84707- obj, err := objectpath.Object(p, t.obj) 84708- if err != nil { 84709- // Though this can happen with regular export data 84710- // due to trimming of inconsequential objects, 84711- // it can't happen if we load dependencies from full 84712- // syntax (as today) or shallow export data (soon), 84713- // as both are complete. 84714- bug.Reportf("objectpath.Object(%v, %v) failed: %v", p, t.obj, err) 84715- continue 84716- } 84717- objects = append(objects, obj) 84718- } 84719- if len(objects) == 0 { 84720- continue // no targets of consequence to this package 84721- } 84722- 84723- // Apply the renaming. 84724- editMap, moreObjects, err := renameObjects(ctx, snapshot, newName, pkg, objects...) 84725- if err != nil { 84726- return nil, err 84727- } 84728- 84729- // It is safe to concatenate the edits as they are non-overlapping 84730- // (or identical, in which case they will be de-duped by Rename). 84731- for uri, edits := range editMap { 84732- allEdits[uri] = append(allEdits[uri], edits...) 84733- } 84734- 84735- // Expand the search set? 84736- for obj := range moreObjects { 84737- objpath, err := objectpath.For(obj) 84738- if err != nil { 84739- continue // not exported 84740- } 84741- target := target{PackagePath(obj.Pkg().Path()), objpath} 84742- targets[target] = true 84743- 84744- // TODO(adonovan): methods requires dynamic 84745- // programming of the product targets x 84746- // packages as any package might add a new 84747- // target (from a foward dep) as a 84748- // consequence, and any target might imply a 84749- // new set of rdeps. See golang/go#58461. 84750- } 84751- } 84752- 84753- return allEdits, nil 84754-} 84755- 84756-// renamePackageName renames package declarations, imports, and go.mod files. 84757-func renamePackageName(ctx context.Context, s Snapshot, f FileHandle, newName PackageName) (map[span.URI][]diff.Edit, error) { 84758- // Rename the package decl and all imports. 84759- renamingEdits, err := renamePackage(ctx, s, f, newName) 84760- if err != nil { 84761- return nil, err 84762- } 84763- 84764- // Update the last component of the file's enclosing directory. 84765- oldBase := filepath.Dir(f.URI().Filename()) 84766- newPkgDir := filepath.Join(filepath.Dir(oldBase), string(newName)) 84767- 84768- // Update any affected replace directives in go.mod files. 84769- // TODO(adonovan): extract into its own function. 84770- // 84771- // TODO: should this operate on all go.mod files, irrespective of whether they are included in the workspace? 84772- // Get all active mod files in the workspace 84773- modFiles := s.ModFiles() 84774- for _, m := range modFiles { 84775- fh, err := s.GetFile(ctx, m) 84776- if err != nil { 84777- return nil, err 84778- } 84779- pm, err := s.ParseMod(ctx, fh) 84780- if err != nil { 84781- return nil, err 84782- } 84783- 84784- modFileDir := filepath.Dir(pm.URI.Filename()) 84785- affectedReplaces := []*modfile.Replace{} 84786- 84787- // Check if any replace directives need to be fixed 84788- for _, r := range pm.File.Replace { 84789- if !strings.HasPrefix(r.New.Path, "/") && !strings.HasPrefix(r.New.Path, "./") && !strings.HasPrefix(r.New.Path, "../") { 84790- continue 84791- } 84792- 84793- replacedPath := r.New.Path 84794- if strings.HasPrefix(r.New.Path, "./") || strings.HasPrefix(r.New.Path, "../") { 84795- replacedPath = filepath.Join(modFileDir, r.New.Path) 84796- } 84797- 84798- // TODO: Is there a risk of converting a '\' delimited replacement to a '/' delimited replacement? 84799- if !strings.HasPrefix(filepath.ToSlash(replacedPath)+"/", filepath.ToSlash(oldBase)+"/") { 84800- continue // not affected by the package renaming 84801- } 84802- 84803- affectedReplaces = append(affectedReplaces, r) 84804- } 84805- 84806- if len(affectedReplaces) == 0 { 84807- continue 84808- } 84809- copied, err := modfile.Parse("", pm.Mapper.Content, nil) 84810- if err != nil { 84811- return nil, err 84812- } 84813- 84814- for _, r := range affectedReplaces { 84815- replacedPath := r.New.Path 84816- if strings.HasPrefix(r.New.Path, "./") || strings.HasPrefix(r.New.Path, "../") { 84817- replacedPath = filepath.Join(modFileDir, r.New.Path) 84818- } 84819- 84820- suffix := strings.TrimPrefix(replacedPath, string(oldBase)) 84821- 84822- newReplacedPath, err := filepath.Rel(modFileDir, newPkgDir+suffix) 84823- if err != nil { 84824- return nil, err 84825- } 84826- 84827- newReplacedPath = filepath.ToSlash(newReplacedPath) 84828- 84829- if !strings.HasPrefix(newReplacedPath, "/") && !strings.HasPrefix(newReplacedPath, "../") { 84830- newReplacedPath = "./" + newReplacedPath 84831- } 84832- 84833- if err := copied.AddReplace(r.Old.Path, "", newReplacedPath, ""); err != nil { 84834- return nil, err 84835- } 84836- } 84837- 84838- copied.Cleanup() 84839- newContent, err := copied.Format() 84840- if err != nil { 84841- return nil, err 84842- } 84843- 84844- // Calculate the edits to be made due to the change. 84845- edits := s.View().Options().ComputeEdits(string(pm.Mapper.Content), string(newContent)) 84846- renamingEdits[pm.URI] = append(renamingEdits[pm.URI], edits...) 84847- } 84848- 84849- return renamingEdits, nil 84850-} 84851- 84852-// renamePackage computes all workspace edits required to rename the package 84853-// described by the given metadata, to newName, by renaming its package 84854-// directory. 84855-// 84856-// It updates package clauses and import paths for the renamed package as well 84857-// as any other packages affected by the directory renaming among packages 84858-// described by allMetadata. 84859-func renamePackage(ctx context.Context, s Snapshot, f FileHandle, newName PackageName) (map[span.URI][]diff.Edit, error) { 84860- if strings.HasSuffix(string(newName), "_test") { 84861- return nil, fmt.Errorf("cannot rename to _test package") 84862- } 84863- 84864- // We need metadata for the relevant package and module paths. 84865- // These should be the same for all packages containing the file. 84866- metas, err := s.MetadataForFile(ctx, f.URI()) 84867- if err != nil { 84868- return nil, err 84869- } 84870- if len(metas) == 0 { 84871- return nil, fmt.Errorf("no packages found for file %q", f.URI()) 84872- } 84873- meta := metas[0] // narrowest 84874- 84875- oldPkgPath := meta.PkgPath 84876- if meta.Module == nil { 84877- return nil, fmt.Errorf("cannot rename package: missing module information for package %q", meta.PkgPath) 84878- } 84879- modulePath := PackagePath(meta.Module.Path) 84880- if modulePath == oldPkgPath { 84881- return nil, fmt.Errorf("cannot rename package: module path %q is the same as the package path, so renaming the package directory would have no effect", modulePath) 84882- } 84883- 84884- newPathPrefix := path.Join(path.Dir(string(oldPkgPath)), string(newName)) 84885- 84886- // We must inspect all packages, not just direct importers, 84887- // because we also rename subpackages, which may be unrelated. 84888- // (If the renamed package imports a subpackage it may require 84889- // edits to both its package and import decls.) 84890- allMetadata, err := s.AllMetadata(ctx) 84891- if err != nil { 84892- return nil, err 84893- } 84894- 84895- // Rename package and import declarations in all relevant packages. 84896- edits := make(map[span.URI][]diff.Edit) 84897- for _, m := range allMetadata { 84898- // Special case: x_test packages for the renamed package will not have the 84899- // package path as as a dir prefix, but still need their package clauses 84900- // renamed. 84901- if m.PkgPath == oldPkgPath+"_test" { 84902- if err := renamePackageClause(ctx, m, s, newName+"_test", edits); err != nil { 84903- return nil, err 84904- } 84905- continue 84906- } 84907- 84908- // Subtle: check this condition before checking for valid module info 84909- // below, because we should not fail this operation if unrelated packages 84910- // lack module info. 84911- if !strings.HasPrefix(string(m.PkgPath)+"/", string(oldPkgPath)+"/") { 84912- continue // not affected by the package renaming 84913- } 84914- 84915- if m.Module == nil { 84916- // This check will always fail under Bazel. 84917- return nil, fmt.Errorf("cannot rename package: missing module information for package %q", m.PkgPath) 84918- } 84919- 84920- if modulePath != PackagePath(m.Module.Path) { 84921- continue // don't edit imports if nested package and renaming package have different module paths 84922- } 84923- 84924- // Renaming a package consists of changing its import path and package name. 84925- suffix := strings.TrimPrefix(string(m.PkgPath), string(oldPkgPath)) 84926- newPath := newPathPrefix + suffix 84927- 84928- pkgName := m.Name 84929- if m.PkgPath == oldPkgPath { 84930- pkgName = PackageName(newName) 84931- 84932- if err := renamePackageClause(ctx, m, s, newName, edits); err != nil { 84933- return nil, err 84934- } 84935- } 84936- 84937- imp := ImportPath(newPath) // TODO(adonovan): what if newPath has vendor/ prefix? 84938- if err := renameImports(ctx, s, m, imp, pkgName, edits); err != nil { 84939- return nil, err 84940- } 84941- } 84942- 84943- return edits, nil 84944-} 84945- 84946-// renamePackageClause computes edits renaming the package clause of files in 84947-// the package described by the given metadata, to newName. 84948-// 84949-// Edits are written into the edits map. 84950-func renamePackageClause(ctx context.Context, m *Metadata, snapshot Snapshot, newName PackageName, edits map[span.URI][]diff.Edit) error { 84951- // Rename internal references to the package in the renaming package. 84952- for _, uri := range m.CompiledGoFiles { 84953- fh, err := snapshot.GetFile(ctx, uri) 84954- if err != nil { 84955- return err 84956- } 84957- f, err := snapshot.ParseGo(ctx, fh, ParseHeader) 84958- if err != nil { 84959- return err 84960- } 84961- if f.File.Name == nil { 84962- continue // no package declaration 84963- } 84964- 84965- edit, err := posEdit(f.Tok, f.File.Name.Pos(), f.File.Name.End(), string(newName)) 84966- if err != nil { 84967- return err 84968- } 84969- edits[f.URI] = append(edits[f.URI], edit) 84970- } 84971- 84972- return nil 84973-} 84974- 84975-// renameImports computes the set of edits to imports resulting from renaming 84976-// the package described by the given metadata, to a package with import path 84977-// newPath and name newName. 84978-// 84979-// Edits are written into the edits map. 84980-func renameImports(ctx context.Context, snapshot Snapshot, m *Metadata, newPath ImportPath, newName PackageName, allEdits map[span.URI][]diff.Edit) error { 84981- rdeps, err := snapshot.ReverseDependencies(ctx, m.ID, false) // find direct importers 84982- if err != nil { 84983- return err 84984- } 84985- 84986- // Pass 1: rename import paths in import declarations. 84987- needsTypeCheck := make(map[PackageID][]span.URI) 84988- for _, rdep := range rdeps { 84989- if rdep.IsIntermediateTestVariant() { 84990- continue // for renaming, these variants are redundant 84991- } 84992- 84993- for _, uri := range rdep.CompiledGoFiles { 84994- fh, err := snapshot.GetFile(ctx, uri) 84995- if err != nil { 84996- return err 84997- } 84998- f, err := snapshot.ParseGo(ctx, fh, ParseHeader) 84999- if err != nil { 85000- return err 85001- } 85002- if f.File.Name == nil { 85003- continue // no package declaration 85004- } 85005- for _, imp := range f.File.Imports { 85006- if rdep.DepsByImpPath[UnquoteImportPath(imp)] != m.ID { 85007- continue // not the import we're looking for 85008- } 85009- 85010- // If the import does not explicitly specify 85011- // a local name, then we need to invoke the 85012- // type checker to locate references to update. 85013- // 85014- // TODO(adonovan): is this actually true? 85015- // Renaming an import with a local name can still 85016- // cause conflicts: shadowing of built-ins, or of 85017- // package-level decls in the same or another file. 85018- if imp.Name == nil { 85019- needsTypeCheck[rdep.ID] = append(needsTypeCheck[rdep.ID], uri) 85020- } 85021- 85022- // Create text edit for the import path (string literal). 85023- edit, err := posEdit(f.Tok, imp.Path.Pos(), imp.Path.End(), strconv.Quote(string(newPath))) 85024- if err != nil { 85025- return err 85026- } 85027- allEdits[uri] = append(allEdits[uri], edit) 85028- } 85029- } 85030- } 85031- 85032- // If the imported package's name hasn't changed, 85033- // we don't need to rename references within each file. 85034- if newName == m.Name { 85035- return nil 85036- } 85037- 85038- // Pass 2: rename local name (types.PkgName) of imported 85039- // package throughout one or more files of the package. 85040- ids := make([]PackageID, 0, len(needsTypeCheck)) 85041- for id := range needsTypeCheck { 85042- ids = append(ids, id) 85043- } 85044- pkgs, err := snapshot.TypeCheck(ctx, ids...) 85045- if err != nil { 85046- return err 85047- } 85048- for i, id := range ids { 85049- pkg := pkgs[i] 85050- for _, uri := range needsTypeCheck[id] { 85051- f, err := pkg.File(uri) 85052- if err != nil { 85053- return err 85054- } 85055- for _, imp := range f.File.Imports { 85056- if imp.Name != nil { 85057- continue // has explicit local name 85058- } 85059- if rdeps[id].DepsByImpPath[UnquoteImportPath(imp)] != m.ID { 85060- continue // not the import we're looking for 85061- } 85062- 85063- pkgname := pkg.GetTypesInfo().Implicits[imp].(*types.PkgName) 85064- 85065- pkgScope := pkg.GetTypes().Scope() 85066- fileScope := pkg.GetTypesInfo().Scopes[f.File] 85067- 85068- localName := string(newName) 85069- try := 0 85070- 85071- // Keep trying with fresh names until one succeeds. 85072- // 85073- // TODO(adonovan): fix: this loop is not sufficient to choose a name 85074- // that is guaranteed to be conflict-free; renameObj may still fail. 85075- // So the retry loop should be around renameObj, and we shouldn't 85076- // bother with scopes here. 85077- for fileScope.Lookup(localName) != nil || pkgScope.Lookup(localName) != nil { 85078- try++ 85079- localName = fmt.Sprintf("%s%d", newName, try) 85080- } 85081- 85082- // renameObj detects various conflicts, including: 85083- // - new name conflicts with a package-level decl in this file; 85084- // - new name hides a package-level decl in another file that 85085- // is actually referenced in this file; 85086- // - new name hides a built-in that is actually referenced 85087- // in this file; 85088- // - a reference in this file to the old package name would 85089- // become shadowed by an intervening declaration that 85090- // uses the new name. 85091- // It returns the edits if no conflict was detected. 85092- editMap, _, err := renameObjects(ctx, snapshot, localName, pkg, pkgname) 85093- if err != nil { 85094- return err 85095- } 85096- 85097- // If the chosen local package name matches the package's 85098- // new name, delete the change that would have inserted 85099- // an explicit local name, which is always the lexically 85100- // first change. 85101- if localName == string(newName) { 85102- edits, ok := editMap[uri] 85103- if !ok { 85104- return fmt.Errorf("internal error: no changes for %s", uri) 85105- } 85106- diff.SortEdits(edits) 85107- editMap[uri] = edits[1:] 85108- } 85109- for uri, edits := range editMap { 85110- allEdits[uri] = append(allEdits[uri], edits...) 85111- } 85112- } 85113- } 85114- } 85115- return nil 85116-} 85117- 85118-// renameObjects computes the edits to the type-checked syntax package pkg 85119-// required to rename a set of target objects to newName. 85120-// 85121-// It also returns the set of objects that were found (due to 85122-// corresponding methods and embedded fields) to require renaming as a 85123-// consequence of the requested renamings. 85124-// 85125-// It returns an error if the renaming would cause a conflict. 85126-func renameObjects(ctx context.Context, snapshot Snapshot, newName string, pkg Package, targets ...types.Object) (map[span.URI][]diff.Edit, map[types.Object]bool, error) { 85127- r := renamer{ 85128- pkg: pkg, 85129- objsToUpdate: make(map[types.Object]bool), 85130- from: targets[0].Name(), 85131- to: newName, 85132- } 85133- 85134- // A renaming initiated at an interface method indicates the 85135- // intention to rename abstract and concrete methods as needed 85136- // to preserve assignability. 85137- // TODO(adonovan): pull this into the caller. 85138- for _, obj := range targets { 85139- if obj, ok := obj.(*types.Func); ok { 85140- recv := obj.Type().(*types.Signature).Recv() 85141- if recv != nil && types.IsInterface(recv.Type().Underlying()) { 85142- r.changeMethods = true 85143- break 85144- } 85145- } 85146- } 85147- 85148- // Check that the renaming of the identifier is ok. 85149- for _, obj := range targets { 85150- r.check(obj) 85151- if len(r.conflicts) > 0 { 85152- // Stop at first error. 85153- return nil, nil, fmt.Errorf("%s", strings.Join(r.conflicts, "\n")) 85154- } 85155- } 85156- 85157- editMap, err := r.update() 85158- if err != nil { 85159- return nil, nil, err 85160- } 85161- 85162- // Remove initial targets so that only 'consequences' remain. 85163- for _, obj := range targets { 85164- delete(r.objsToUpdate, obj) 85165- } 85166- return editMap, r.objsToUpdate, nil 85167-} 85168- 85169-// Rename all references to the target objects. 85170-func (r *renamer) update() (map[span.URI][]diff.Edit, error) { 85171- result := make(map[span.URI][]diff.Edit) 85172- 85173- // shouldUpdate reports whether obj is one of (or an 85174- // instantiation of one of) the target objects. 85175- shouldUpdate := func(obj types.Object) bool { 85176- if r.objsToUpdate[obj] { 85177- return true 85178- } 85179- if fn, ok := obj.(*types.Func); ok && r.objsToUpdate[funcOrigin(fn)] { 85180- return true 85181- } 85182- return false 85183- } 85184- 85185- // Find all identifiers in the package that define or use a 85186- // renamed object. We iterate over info as it is more efficent 85187- // than calling ast.Inspect for each of r.pkg.CompiledGoFiles(). 85188- type item struct { 85189- node ast.Node // Ident, ImportSpec (obj=PkgName), or CaseClause (obj=Var) 85190- obj types.Object 85191- isDef bool 85192- } 85193- var items []item 85194- info := r.pkg.GetTypesInfo() 85195- for id, obj := range info.Uses { 85196- if shouldUpdate(obj) { 85197- items = append(items, item{id, obj, false}) 85198- } 85199- } 85200- for id, obj := range info.Defs { 85201- if shouldUpdate(obj) { 85202- items = append(items, item{id, obj, true}) 85203- } 85204- } 85205- for node, obj := range info.Implicits { 85206- if shouldUpdate(obj) { 85207- switch node.(type) { 85208- case *ast.ImportSpec, *ast.CaseClause: 85209- items = append(items, item{node, obj, true}) 85210- } 85211- } 85212- } 85213- sort.Slice(items, func(i, j int) bool { 85214- return items[i].node.Pos() < items[j].node.Pos() 85215- }) 85216- 85217- // Update each identifier. 85218- for _, item := range items { 85219- pgf, ok := enclosingFile(r.pkg, item.node.Pos()) 85220- if !ok { 85221- bug.Reportf("edit does not belong to syntax of package %q", r.pkg) 85222- continue 85223- } 85224- 85225- // Renaming a types.PkgName may result in the addition or removal of an identifier, 85226- // so we deal with this separately. 85227- if pkgName, ok := item.obj.(*types.PkgName); ok && item.isDef { 85228- edit, err := r.updatePkgName(pgf, pkgName) 85229- if err != nil { 85230- return nil, err 85231- } 85232- result[pgf.URI] = append(result[pgf.URI], edit) 85233- continue 85234- } 85235- 85236- // Workaround the unfortunate lack of a Var object 85237- // for x in "switch x := expr.(type) {}" by adjusting 85238- // the case clause to the switch ident. 85239- // This may result in duplicate edits, but we de-dup later. 85240- if _, ok := item.node.(*ast.CaseClause); ok { 85241- path, _ := astutil.PathEnclosingInterval(pgf.File, item.obj.Pos(), item.obj.Pos()) 85242- item.node = path[0].(*ast.Ident) 85243- } 85244- 85245- // Replace the identifier with r.to. 85246- edit, err := posEdit(pgf.Tok, item.node.Pos(), item.node.End(), r.to) 85247- if err != nil { 85248- return nil, err 85249- } 85250- 85251- result[pgf.URI] = append(result[pgf.URI], edit) 85252- 85253- if !item.isDef { // uses do not have doc comments to update. 85254- continue 85255- } 85256- 85257- doc := docComment(pgf, item.node.(*ast.Ident)) 85258- if doc == nil { 85259- continue 85260- } 85261- 85262- // Perform the rename in doc comments declared in the original package. 85263- // go/parser strips out \r\n returns from the comment text, so go 85264- // line-by-line through the comment text to get the correct positions. 85265- docRegexp := regexp.MustCompile(`\b` + r.from + `\b`) // valid identifier => valid regexp 85266- for _, comment := range doc.List { 85267- if isDirective(comment.Text) { 85268- continue 85269- } 85270- // TODO(adonovan): why are we looping over lines? 85271- // Just run the loop body once over the entire multiline comment. 85272- lines := strings.Split(comment.Text, "\n") 85273- tokFile := pgf.Tok 85274- commentLine := tokFile.Line(comment.Pos()) 85275- uri := span.URIFromPath(tokFile.Name()) 85276- for i, line := range lines { 85277- lineStart := comment.Pos() 85278- if i > 0 { 85279- lineStart = tokFile.LineStart(commentLine + i) 85280- } 85281- for _, locs := range docRegexp.FindAllIndex([]byte(line), -1) { 85282- edit, err := posEdit(tokFile, lineStart+token.Pos(locs[0]), lineStart+token.Pos(locs[1]), r.to) 85283- if err != nil { 85284- return nil, err // can't happen 85285- } 85286- result[uri] = append(result[uri], edit) 85287- } 85288- } 85289- } 85290- } 85291- 85292- return result, nil 85293-} 85294- 85295-// docComment returns the doc for an identifier within the specified file. 85296-func docComment(pgf *ParsedGoFile, id *ast.Ident) *ast.CommentGroup { 85297- nodes, _ := astutil.PathEnclosingInterval(pgf.File, id.Pos(), id.End()) 85298- for _, node := range nodes { 85299- switch decl := node.(type) { 85300- case *ast.FuncDecl: 85301- return decl.Doc 85302- case *ast.Field: 85303- return decl.Doc 85304- case *ast.GenDecl: 85305- return decl.Doc 85306- // For {Type,Value}Spec, if the doc on the spec is absent, 85307- // search for the enclosing GenDecl 85308- case *ast.TypeSpec: 85309- if decl.Doc != nil { 85310- return decl.Doc 85311- } 85312- case *ast.ValueSpec: 85313- if decl.Doc != nil { 85314- return decl.Doc 85315- } 85316- case *ast.Ident: 85317- case *ast.AssignStmt: 85318- // *ast.AssignStmt doesn't have an associated comment group. 85319- // So, we try to find a comment just before the identifier. 85320- 85321- // Try to find a comment group only for short variable declarations (:=). 85322- if decl.Tok != token.DEFINE { 85323- return nil 85324- } 85325- 85326- identLine := pgf.Tok.Line(id.Pos()) 85327- for _, comment := range nodes[len(nodes)-1].(*ast.File).Comments { 85328- if comment.Pos() > id.Pos() { 85329- // Comment is after the identifier. 85330- continue 85331- } 85332- 85333- lastCommentLine := pgf.Tok.Line(comment.End()) 85334- if lastCommentLine+1 == identLine { 85335- return comment 85336- } 85337- } 85338- default: 85339- return nil 85340- } 85341- } 85342- return nil 85343-} 85344- 85345-// updatePkgName returns the updates to rename a pkgName in the import spec by 85346-// only modifying the package name portion of the import declaration. 85347-func (r *renamer) updatePkgName(pgf *ParsedGoFile, pkgName *types.PkgName) (diff.Edit, error) { 85348- // Modify ImportSpec syntax to add or remove the Name as needed. 85349- path, _ := astutil.PathEnclosingInterval(pgf.File, pkgName.Pos(), pkgName.Pos()) 85350- if len(path) < 2 { 85351- return diff.Edit{}, fmt.Errorf("no path enclosing interval for %s", pkgName.Name()) 85352- } 85353- spec, ok := path[1].(*ast.ImportSpec) 85354- if !ok { 85355- return diff.Edit{}, fmt.Errorf("failed to update PkgName for %s", pkgName.Name()) 85356- } 85357- 85358- newText := "" 85359- if pkgName.Imported().Name() != r.to { 85360- newText = r.to + " " 85361- } 85362- 85363- // Replace the portion (possibly empty) of the spec before the path: 85364- // local "path" or "path" 85365- // -> <- -><- 85366- return posEdit(pgf.Tok, spec.Pos(), spec.Path.Pos(), newText) 85367-} 85368- 85369-// parsePackageNameDecl is a convenience function that parses and 85370-// returns the package name declaration of file fh, and reports 85371-// whether the position ppos lies within it. 85372-// 85373-// Note: also used by references2. 85374-func parsePackageNameDecl(ctx context.Context, snapshot Snapshot, fh FileHandle, ppos protocol.Position) (*ParsedGoFile, bool, error) { 85375- pgf, err := snapshot.ParseGo(ctx, fh, ParseHeader) 85376- if err != nil { 85377- return nil, false, err 85378- } 85379- // Careful: because we used ParseHeader, 85380- // pgf.Pos(ppos) may be beyond EOF => (0, err). 85381- pos, _ := pgf.PositionPos(ppos) 85382- return pgf, pgf.File.Name.Pos() <= pos && pos <= pgf.File.Name.End(), nil 85383-} 85384- 85385-// enclosingFile returns the CompiledGoFile of pkg that contains the specified position. 85386-func enclosingFile(pkg Package, pos token.Pos) (*ParsedGoFile, bool) { 85387- for _, pgf := range pkg.CompiledGoFiles() { 85388- if pgf.File.Pos() <= pos && pos <= pgf.File.End() { 85389- return pgf, true 85390- } 85391- } 85392- return nil, false 85393-} 85394- 85395-// posEdit returns an edit to replace the (start, end) range of tf with 'new'. 85396-func posEdit(tf *token.File, start, end token.Pos, new string) (diff.Edit, error) { 85397- startOffset, endOffset, err := safetoken.Offsets(tf, start, end) 85398- if err != nil { 85399- return diff.Edit{}, err 85400- } 85401- return diff.Edit{Start: startOffset, End: endOffset, New: new}, nil 85402-} 85403diff -urN a/gopls/internal/lsp/source/signature_help.go b/gopls/internal/lsp/source/signature_help.go 85404--- a/gopls/internal/lsp/source/signature_help.go 2000-01-01 00:00:00.000000000 -0000 85405+++ b/gopls/internal/lsp/source/signature_help.go 1970-01-01 00:00:00.000000000 +0000 85406@@ -1,185 +0,0 @@ 85407-// Copyright 2018 The Go Authors. All rights reserved. 85408-// Use of this source code is governed by a BSD-style 85409-// license that can be found in the LICENSE file. 85410- 85411-package source 85412- 85413-import ( 85414- "context" 85415- "fmt" 85416- "go/ast" 85417- "go/token" 85418- "go/types" 85419- "strings" 85420- 85421- "golang.org/x/tools/go/ast/astutil" 85422- "golang.org/x/tools/gopls/internal/lsp/protocol" 85423- "golang.org/x/tools/internal/event" 85424-) 85425- 85426-func SignatureHelp(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.SignatureInformation, int, error) { 85427- ctx, done := event.Start(ctx, "source.SignatureHelp") 85428- defer done() 85429- 85430- // We need full type-checking here, as we must type-check function bodies in 85431- // order to provide signature help at the requested position. 85432- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 85433- if err != nil { 85434- return nil, 0, fmt.Errorf("getting file for SignatureHelp: %w", err) 85435- } 85436- pos, err := pgf.PositionPos(position) 85437- if err != nil { 85438- return nil, 0, err 85439- } 85440- // Find a call expression surrounding the query position. 85441- var callExpr *ast.CallExpr 85442- path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos) 85443- if path == nil { 85444- return nil, 0, fmt.Errorf("cannot find node enclosing position") 85445- } 85446-FindCall: 85447- for _, node := range path { 85448- switch node := node.(type) { 85449- case *ast.CallExpr: 85450- if pos >= node.Lparen && pos <= node.Rparen { 85451- callExpr = node 85452- break FindCall 85453- } 85454- case *ast.FuncLit, *ast.FuncType: 85455- // The user is within an anonymous function, 85456- // which may be the parameter to the *ast.CallExpr. 85457- // Don't show signature help in this case. 85458- return nil, 0, fmt.Errorf("no signature help within a function declaration") 85459- case *ast.BasicLit: 85460- if node.Kind == token.STRING { 85461- return nil, 0, fmt.Errorf("no signature help within a string literal") 85462- } 85463- } 85464- 85465- } 85466- if callExpr == nil || callExpr.Fun == nil { 85467- return nil, 0, fmt.Errorf("cannot find an enclosing function") 85468- } 85469- 85470- qf := Qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo()) 85471- 85472- // Get the object representing the function, if available. 85473- // There is no object in certain cases such as calling a function returned by 85474- // a function (e.g. "foo()()"). 85475- var obj types.Object 85476- switch t := callExpr.Fun.(type) { 85477- case *ast.Ident: 85478- obj = pkg.GetTypesInfo().ObjectOf(t) 85479- case *ast.SelectorExpr: 85480- obj = pkg.GetTypesInfo().ObjectOf(t.Sel) 85481- } 85482- 85483- // Handle builtin functions separately. 85484- if obj, ok := obj.(*types.Builtin); ok { 85485- return builtinSignature(ctx, snapshot, callExpr, obj.Name(), pos) 85486- } 85487- 85488- // Get the type information for the function being called. 85489- sigType := pkg.GetTypesInfo().TypeOf(callExpr.Fun) 85490- if sigType == nil { 85491- return nil, 0, fmt.Errorf("cannot get type for Fun %[1]T (%[1]v)", callExpr.Fun) 85492- } 85493- 85494- sig, _ := sigType.Underlying().(*types.Signature) 85495- if sig == nil { 85496- return nil, 0, fmt.Errorf("cannot find signature for Fun %[1]T (%[1]v)", callExpr.Fun) 85497- } 85498- 85499- activeParam := activeParameter(callExpr, sig.Params().Len(), sig.Variadic(), pos) 85500- 85501- var ( 85502- name string 85503- comment *ast.CommentGroup 85504- ) 85505- if obj != nil { 85506- d, err := HoverDocForObject(ctx, snapshot, pkg.FileSet(), obj) 85507- if err != nil { 85508- return nil, 0, err 85509- } 85510- name = obj.Name() 85511- comment = d 85512- } else { 85513- name = "func" 85514- } 85515- mq := MetadataQualifierForFile(snapshot, pgf.File, pkg.Metadata()) 85516- s, err := NewSignature(ctx, snapshot, pkg, sig, comment, qf, mq) 85517- if err != nil { 85518- return nil, 0, err 85519- } 85520- paramInfo := make([]protocol.ParameterInformation, 0, len(s.params)) 85521- for _, p := range s.params { 85522- paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p}) 85523- } 85524- return &protocol.SignatureInformation{ 85525- Label: name + s.Format(), 85526- Documentation: stringToSigInfoDocumentation(s.doc, snapshot.View().Options()), 85527- Parameters: paramInfo, 85528- }, activeParam, nil 85529-} 85530- 85531-func builtinSignature(ctx context.Context, snapshot Snapshot, callExpr *ast.CallExpr, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) { 85532- sig, err := NewBuiltinSignature(ctx, snapshot, name) 85533- if err != nil { 85534- return nil, 0, err 85535- } 85536- paramInfo := make([]protocol.ParameterInformation, 0, len(sig.params)) 85537- for _, p := range sig.params { 85538- paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p}) 85539- } 85540- activeParam := activeParameter(callExpr, len(sig.params), sig.variadic, pos) 85541- return &protocol.SignatureInformation{ 85542- Label: sig.name + sig.Format(), 85543- Documentation: stringToSigInfoDocumentation(sig.doc, snapshot.View().Options()), 85544- Parameters: paramInfo, 85545- }, activeParam, nil 85546- 85547-} 85548- 85549-func activeParameter(callExpr *ast.CallExpr, numParams int, variadic bool, pos token.Pos) (activeParam int) { 85550- if len(callExpr.Args) == 0 { 85551- return 0 85552- } 85553- // First, check if the position is even in the range of the arguments. 85554- start, end := callExpr.Lparen, callExpr.Rparen 85555- if !(start <= pos && pos <= end) { 85556- return 0 85557- } 85558- for _, expr := range callExpr.Args { 85559- if start == token.NoPos { 85560- start = expr.Pos() 85561- } 85562- end = expr.End() 85563- if start <= pos && pos <= end { 85564- break 85565- } 85566- // Don't advance the active parameter for the last parameter of a variadic function. 85567- if !variadic || activeParam < numParams-1 { 85568- activeParam++ 85569- } 85570- start = expr.Pos() + 1 // to account for commas 85571- } 85572- return activeParam 85573-} 85574- 85575-func stringToSigInfoDocumentation(s string, options *Options) *protocol.Or_SignatureInformation_documentation { 85576- v := s 85577- k := protocol.PlainText 85578- if options.PreferredContentFormat == protocol.Markdown { 85579- v = CommentToMarkdown(s, options) 85580- // whether or not content is newline terminated may not matter for LSP clients, 85581- // but our tests expect trailing newlines to be stripped. 85582- v = strings.TrimSuffix(v, "\n") // TODO(pjw): change the golden files 85583- k = protocol.Markdown 85584- } 85585- return &protocol.Or_SignatureInformation_documentation{ 85586- Value: protocol.MarkupContent{ 85587- Kind: k, 85588- Value: v, 85589- }, 85590- } 85591-} 85592diff -urN a/gopls/internal/lsp/source/stub.go b/gopls/internal/lsp/source/stub.go 85593--- a/gopls/internal/lsp/source/stub.go 2000-01-01 00:00:00.000000000 -0000 85594+++ b/gopls/internal/lsp/source/stub.go 1970-01-01 00:00:00.000000000 +0000 85595@@ -1,238 +0,0 @@ 85596-// Copyright 2022 The Go Authors. All rights reserved. 85597-// Use of this source code is governed by a BSD-style 85598-// license that can be found in the LICENSE file. 85599- 85600-package source 85601- 85602-import ( 85603- "bytes" 85604- "context" 85605- "fmt" 85606- "go/format" 85607- "go/parser" 85608- "go/token" 85609- "go/types" 85610- "io" 85611- "path" 85612- "strings" 85613- 85614- "golang.org/x/tools/go/analysis" 85615- "golang.org/x/tools/go/ast/astutil" 85616- "golang.org/x/tools/gopls/internal/lsp/analysis/stubmethods" 85617- "golang.org/x/tools/gopls/internal/lsp/protocol" 85618- "golang.org/x/tools/gopls/internal/lsp/safetoken" 85619- "golang.org/x/tools/internal/bug" 85620- "golang.org/x/tools/internal/typeparams" 85621-) 85622- 85623-// stubSuggestedFixFunc returns a suggested fix to declare the missing 85624-// methods of the concrete type that is assigned to an interface type 85625-// at the cursor position. 85626-func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle, rng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) { 85627- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 85628- if err != nil { 85629- return nil, nil, fmt.Errorf("GetTypedFile: %w", err) 85630- } 85631- start, end, err := pgf.RangePos(rng) 85632- if err != nil { 85633- return nil, nil, err 85634- } 85635- nodes, _ := astutil.PathEnclosingInterval(pgf.File, start, end) 85636- si := stubmethods.GetStubInfo(pkg.FileSet(), pkg.GetTypesInfo(), nodes, start) 85637- if si == nil { 85638- return nil, nil, fmt.Errorf("nil interface request") 85639- } 85640- return stub(ctx, snapshot, si) 85641-} 85642- 85643-// stub returns a suggested fix to declare the missing methods of si.Concrete. 85644-func stub(ctx context.Context, snapshot Snapshot, si *stubmethods.StubInfo) (*token.FileSet, *analysis.SuggestedFix, error) { 85645- // A function-local type cannot be stubbed 85646- // since there's nowhere to put the methods. 85647- conc := si.Concrete.Obj() 85648- if conc.Parent() != conc.Pkg().Scope() { 85649- return nil, nil, fmt.Errorf("local type %q cannot be stubbed", conc.Name()) 85650- } 85651- 85652- // Parse the file declaring the concrete type. 85653- declPGF, _, err := parseFull(ctx, snapshot, si.Fset, conc.Pos()) 85654- if err != nil { 85655- return nil, nil, fmt.Errorf("failed to parse file %q declaring implementation type: %w", declPGF.URI, err) 85656- } 85657- if declPGF.Fixed { 85658- return nil, nil, fmt.Errorf("file contains parse errors: %s", declPGF.URI) 85659- } 85660- 85661- // Build import environment for the declaring file. 85662- importEnv := make(map[ImportPath]string) // value is local name 85663- for _, imp := range declPGF.File.Imports { 85664- importPath := UnquoteImportPath(imp) 85665- var name string 85666- if imp.Name != nil { 85667- name = imp.Name.Name 85668- if name == "_" { 85669- continue 85670- } else if name == "." { 85671- name = "" // see types.Qualifier 85672- } 85673- } else { 85674- // TODO(adonovan): may omit a vendor/ prefix; consult the Metadata. 85675- name = path.Base(string(importPath)) 85676- } 85677- importEnv[importPath] = name // latest alias wins 85678- } 85679- 85680- // Find subset of interface methods that the concrete type lacks. 85681- var missing []*types.Func 85682- ifaceType := si.Interface.Type().Underlying().(*types.Interface) 85683- for i := 0; i < ifaceType.NumMethods(); i++ { 85684- imethod := ifaceType.Method(i) 85685- cmethod, _, _ := types.LookupFieldOrMethod(si.Concrete, si.Pointer, imethod.Pkg(), imethod.Name()) 85686- if cmethod == nil { 85687- missing = append(missing, imethod) 85688- continue 85689- } 85690- 85691- if _, ok := cmethod.(*types.Var); ok { 85692- // len(LookupFieldOrMethod.index) = 1 => conflict, >1 => shadow. 85693- return nil, nil, fmt.Errorf("adding method %s.%s would conflict with (or shadow) existing field", 85694- conc.Name(), imethod.Name()) 85695- } 85696- 85697- if !types.Identical(cmethod.Type(), imethod.Type()) { 85698- return nil, nil, fmt.Errorf("method %s.%s already exists but has the wrong type: got %s, want %s", 85699- conc.Name(), imethod.Name(), cmethod.Type(), imethod.Type()) 85700- } 85701- } 85702- if len(missing) == 0 { 85703- return nil, nil, fmt.Errorf("no missing methods found") 85704- } 85705- 85706- // Create a package name qualifier that uses the 85707- // locally appropriate imported package name. 85708- // It records any needed new imports. 85709- // TODO(adonovan): factor with source.FormatVarType, stubmethods.RelativeToFiles? 85710- // 85711- // Prior to CL 469155 this logic preserved any renaming 85712- // imports from the file that declares the interface 85713- // method--ostensibly the preferred name for imports of 85714- // frequently renamed packages such as protobufs. 85715- // Now we use the package's declared name. If this turns out 85716- // to be a mistake, then use parseHeader(si.iface.Pos()). 85717- // 85718- type newImport struct{ name, importPath string } 85719- var newImports []newImport // for AddNamedImport 85720- qual := func(pkg *types.Package) string { 85721- // TODO(adonovan): don't ignore vendor prefix. 85722- importPath := ImportPath(pkg.Path()) 85723- name, ok := importEnv[importPath] 85724- if !ok { 85725- // Insert new import using package's declared name. 85726- // 85727- // TODO(adonovan): resolve conflict between declared 85728- // name and existing file-level (declPGF.File.Imports) 85729- // or package-level (si.Concrete.Pkg.Scope) decls by 85730- // generating a fresh name. 85731- name = pkg.Name() 85732- importEnv[importPath] = name 85733- new := newImport{importPath: string(importPath)} 85734- // For clarity, use a renaming import whenever the 85735- // local name does not match the path's last segment. 85736- if name != path.Base(new.importPath) { 85737- new.name = name 85738- } 85739- newImports = append(newImports, new) 85740- } 85741- return name 85742- } 85743- 85744- // Format interface name (used only in a comment). 85745- iface := si.Interface.Name() 85746- if ipkg := si.Interface.Pkg(); ipkg != nil && ipkg != conc.Pkg() { 85747- iface = ipkg.Name() + "." + iface 85748- } 85749- 85750- // Pointer receiver? 85751- var star string 85752- if si.Pointer { 85753- star = "*" 85754- } 85755- 85756- // Format the new methods. 85757- var newMethods bytes.Buffer 85758- for _, method := range missing { 85759- fmt.Fprintf(&newMethods, `// %s implements %s 85760-func (%s%s%s) %s%s { 85761- panic("unimplemented") 85762-} 85763-`, 85764- method.Name(), 85765- iface, 85766- star, 85767- si.Concrete.Obj().Name(), 85768- FormatTypeParams(typeparams.ForNamed(si.Concrete)), 85769- method.Name(), 85770- strings.TrimPrefix(types.TypeString(method.Type(), qual), "func")) 85771- } 85772- 85773- // Compute insertion point for new methods: 85774- // after the top-level declaration enclosing the (package-level) type. 85775- insertOffset, err := safetoken.Offset(declPGF.Tok, declPGF.File.End()) 85776- if err != nil { 85777- return nil, nil, bug.Errorf("internal error: end position outside file bounds: %v", err) 85778- } 85779- concOffset, err := safetoken.Offset(si.Fset.File(conc.Pos()), conc.Pos()) 85780- if err != nil { 85781- return nil, nil, bug.Errorf("internal error: finding type decl offset: %v", err) 85782- } 85783- for _, decl := range declPGF.File.Decls { 85784- declEndOffset, err := safetoken.Offset(declPGF.Tok, decl.End()) 85785- if err != nil { 85786- return nil, nil, bug.Errorf("internal error: finding decl offset: %v", err) 85787- } 85788- if declEndOffset > concOffset { 85789- insertOffset = declEndOffset 85790- break 85791- } 85792- } 85793- 85794- // Splice the new methods into the file content. 85795- var buf bytes.Buffer 85796- input := declPGF.Mapper.Content // unfixed content of file 85797- buf.Write(input[:insertOffset]) 85798- buf.WriteByte('\n') 85799- io.Copy(&buf, &newMethods) 85800- buf.Write(input[insertOffset:]) 85801- 85802- // Re-parse the file. 85803- fset := token.NewFileSet() 85804- newF, err := parser.ParseFile(fset, declPGF.File.Name.Name, buf.Bytes(), parser.ParseComments) 85805- if err != nil { 85806- return nil, nil, fmt.Errorf("could not reparse file: %w", err) 85807- } 85808- 85809- // Splice the new imports into the syntax tree. 85810- for _, imp := range newImports { 85811- astutil.AddNamedImport(fset, newF, imp.name, imp.importPath) 85812- } 85813- 85814- // Pretty-print. 85815- var output strings.Builder 85816- if err := format.Node(&output, fset, newF); err != nil { 85817- return nil, nil, fmt.Errorf("format.Node: %w", err) 85818- } 85819- 85820- // Report the diff. 85821- diffs := snapshot.View().Options().ComputeEdits(string(input), output.String()) 85822- var edits []analysis.TextEdit 85823- for _, edit := range diffs { 85824- edits = append(edits, analysis.TextEdit{ 85825- Pos: declPGF.Tok.Pos(edit.Start), 85826- End: declPGF.Tok.Pos(edit.End), 85827- NewText: []byte(edit.New), 85828- }) 85829- } 85830- return FileSetFor(declPGF.Tok), // edits use declPGF.Tok 85831- &analysis.SuggestedFix{TextEdits: edits}, 85832- nil 85833-} 85834diff -urN a/gopls/internal/lsp/source/symbols.go b/gopls/internal/lsp/source/symbols.go 85835--- a/gopls/internal/lsp/source/symbols.go 2000-01-01 00:00:00.000000000 -0000 85836+++ b/gopls/internal/lsp/source/symbols.go 1970-01-01 00:00:00.000000000 +0000 85837@@ -1,227 +0,0 @@ 85838-// Copyright 2019 The Go Authors. All rights reserved. 85839-// Use of this source code is governed by a BSD-style 85840-// license that can be found in the LICENSE file. 85841- 85842-package source 85843- 85844-import ( 85845- "context" 85846- "fmt" 85847- "go/ast" 85848- "go/token" 85849- "go/types" 85850- 85851- "golang.org/x/tools/gopls/internal/lsp/protocol" 85852- "golang.org/x/tools/internal/event" 85853-) 85854- 85855-func DocumentSymbols(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.DocumentSymbol, error) { 85856- ctx, done := event.Start(ctx, "source.DocumentSymbols") 85857- defer done() 85858- 85859- pgf, err := snapshot.ParseGo(ctx, fh, ParseFull) 85860- if err != nil { 85861- return nil, fmt.Errorf("getting file for DocumentSymbols: %w", err) 85862- } 85863- 85864- // Build symbols for file declarations. When encountering a declaration with 85865- // errors (typically because positions are invalid), we skip the declaration 85866- // entirely. VS Code fails to show any symbols if one of the top-level 85867- // symbols is missing position information. 85868- var symbols []protocol.DocumentSymbol 85869- for _, decl := range pgf.File.Decls { 85870- switch decl := decl.(type) { 85871- case *ast.FuncDecl: 85872- if decl.Name.Name == "_" { 85873- continue 85874- } 85875- fs, err := funcSymbol(pgf.Mapper, pgf.Tok, decl) 85876- if err == nil { 85877- // If function is a method, prepend the type of the method. 85878- if decl.Recv != nil && len(decl.Recv.List) > 0 { 85879- fs.Name = fmt.Sprintf("(%s).%s", types.ExprString(decl.Recv.List[0].Type), fs.Name) 85880- } 85881- symbols = append(symbols, fs) 85882- } 85883- case *ast.GenDecl: 85884- for _, spec := range decl.Specs { 85885- switch spec := spec.(type) { 85886- case *ast.TypeSpec: 85887- if spec.Name.Name == "_" { 85888- continue 85889- } 85890- ts, err := typeSymbol(pgf.Mapper, pgf.Tok, spec) 85891- if err == nil { 85892- symbols = append(symbols, ts) 85893- } 85894- case *ast.ValueSpec: 85895- for _, name := range spec.Names { 85896- if name.Name == "_" { 85897- continue 85898- } 85899- vs, err := varSymbol(pgf.Mapper, pgf.Tok, spec, name, decl.Tok == token.CONST) 85900- if err == nil { 85901- symbols = append(symbols, vs) 85902- } 85903- } 85904- } 85905- } 85906- } 85907- } 85908- return symbols, nil 85909-} 85910- 85911-func funcSymbol(m *protocol.Mapper, tf *token.File, decl *ast.FuncDecl) (protocol.DocumentSymbol, error) { 85912- s := protocol.DocumentSymbol{ 85913- Name: decl.Name.Name, 85914- Kind: protocol.Function, 85915- } 85916- if decl.Recv != nil { 85917- s.Kind = protocol.Method 85918- } 85919- var err error 85920- s.Range, err = m.NodeRange(tf, decl) 85921- if err != nil { 85922- return protocol.DocumentSymbol{}, err 85923- } 85924- s.SelectionRange, err = m.NodeRange(tf, decl.Name) 85925- if err != nil { 85926- return protocol.DocumentSymbol{}, err 85927- } 85928- s.Detail = types.ExprString(decl.Type) 85929- return s, nil 85930-} 85931- 85932-func typeSymbol(m *protocol.Mapper, tf *token.File, spec *ast.TypeSpec) (protocol.DocumentSymbol, error) { 85933- s := protocol.DocumentSymbol{ 85934- Name: spec.Name.Name, 85935- } 85936- var err error 85937- s.Range, err = m.NodeRange(tf, spec) 85938- if err != nil { 85939- return protocol.DocumentSymbol{}, err 85940- } 85941- s.SelectionRange, err = m.NodeRange(tf, spec.Name) 85942- if err != nil { 85943- return protocol.DocumentSymbol{}, err 85944- } 85945- s.Kind, s.Detail, s.Children = typeDetails(m, tf, spec.Type) 85946- return s, nil 85947-} 85948- 85949-func typeDetails(m *protocol.Mapper, tf *token.File, typExpr ast.Expr) (kind protocol.SymbolKind, detail string, children []protocol.DocumentSymbol) { 85950- switch typExpr := typExpr.(type) { 85951- case *ast.StructType: 85952- kind = protocol.Struct 85953- children = fieldListSymbols(m, tf, typExpr.Fields, protocol.Field) 85954- if len(children) > 0 { 85955- detail = "struct{...}" 85956- } else { 85957- detail = "struct{}" 85958- } 85959- 85960- // Find interface methods and embedded types. 85961- case *ast.InterfaceType: 85962- kind = protocol.Interface 85963- children = fieldListSymbols(m, tf, typExpr.Methods, protocol.Method) 85964- if len(children) > 0 { 85965- detail = "interface{...}" 85966- } else { 85967- detail = "interface{}" 85968- } 85969- 85970- case *ast.FuncType: 85971- kind = protocol.Function 85972- detail = types.ExprString(typExpr) 85973- 85974- default: 85975- kind = protocol.Class // catch-all, for cases where we don't know the kind syntactically 85976- detail = types.ExprString(typExpr) 85977- } 85978- return 85979-} 85980- 85981-func fieldListSymbols(m *protocol.Mapper, tf *token.File, fields *ast.FieldList, fieldKind protocol.SymbolKind) []protocol.DocumentSymbol { 85982- if fields == nil { 85983- return nil 85984- } 85985- 85986- var symbols []protocol.DocumentSymbol 85987- for _, field := range fields.List { 85988- detail, children := "", []protocol.DocumentSymbol(nil) 85989- if field.Type != nil { 85990- _, detail, children = typeDetails(m, tf, field.Type) 85991- } 85992- if len(field.Names) == 0 { // embedded interface or struct field 85993- // By default, use the formatted type details as the name of this field. 85994- // This handles potentially invalid syntax, as well as type embeddings in 85995- // interfaces. 85996- child := protocol.DocumentSymbol{ 85997- Name: detail, 85998- Kind: protocol.Field, // consider all embeddings to be fields 85999- Children: children, 86000- } 86001- 86002- // If the field is a valid embedding, promote the type name to field 86003- // name. 86004- selection := field.Type 86005- if id := embeddedIdent(field.Type); id != nil { 86006- child.Name = id.Name 86007- child.Detail = detail 86008- selection = id 86009- } 86010- 86011- if rng, err := m.NodeRange(tf, field.Type); err == nil { 86012- child.Range = rng 86013- } 86014- if rng, err := m.NodeRange(tf, selection); err == nil { 86015- child.SelectionRange = rng 86016- } 86017- 86018- symbols = append(symbols, child) 86019- } else { 86020- for _, name := range field.Names { 86021- child := protocol.DocumentSymbol{ 86022- Name: name.Name, 86023- Kind: fieldKind, 86024- Detail: detail, 86025- Children: children, 86026- } 86027- 86028- if rng, err := m.NodeRange(tf, field); err == nil { 86029- child.Range = rng 86030- } 86031- if rng, err := m.NodeRange(tf, name); err == nil { 86032- child.SelectionRange = rng 86033- } 86034- 86035- symbols = append(symbols, child) 86036- } 86037- } 86038- 86039- } 86040- return symbols 86041-} 86042- 86043-func varSymbol(m *protocol.Mapper, tf *token.File, spec *ast.ValueSpec, name *ast.Ident, isConst bool) (protocol.DocumentSymbol, error) { 86044- s := protocol.DocumentSymbol{ 86045- Name: name.Name, 86046- Kind: protocol.Variable, 86047- } 86048- if isConst { 86049- s.Kind = protocol.Constant 86050- } 86051- var err error 86052- s.Range, err = m.NodeRange(tf, spec) 86053- if err != nil { 86054- return protocol.DocumentSymbol{}, err 86055- } 86056- s.SelectionRange, err = m.NodeRange(tf, name) 86057- if err != nil { 86058- return protocol.DocumentSymbol{}, err 86059- } 86060- if spec.Type != nil { // type may be missing from the syntax 86061- _, s.Detail, s.Children = typeDetails(m, tf, spec.Type) 86062- } 86063- return s, nil 86064-} 86065diff -urN a/gopls/internal/lsp/source/type_definition.go b/gopls/internal/lsp/source/type_definition.go 86066--- a/gopls/internal/lsp/source/type_definition.go 2000-01-01 00:00:00.000000000 -0000 86067+++ b/gopls/internal/lsp/source/type_definition.go 1970-01-01 00:00:00.000000000 +0000 86068@@ -1,55 +0,0 @@ 86069-// Copyright 2023 The Go Authors. All rights reserved. 86070-// Use of this source code is governed by a BSD-style 86071-// license that can be found in the LICENSE file. 86072- 86073-package source 86074- 86075-import ( 86076- "context" 86077- "fmt" 86078- "go/token" 86079- 86080- "golang.org/x/tools/gopls/internal/lsp/protocol" 86081- "golang.org/x/tools/internal/event" 86082-) 86083- 86084-// TypeDefinition handles the textDocument/typeDefinition request for Go files. 86085-func TypeDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) ([]protocol.Location, error) { 86086- ctx, done := event.Start(ctx, "source.TypeDefinition") 86087- defer done() 86088- 86089- pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage) 86090- if err != nil { 86091- return nil, err 86092- } 86093- pos, err := pgf.PositionPos(position) 86094- if err != nil { 86095- return nil, err 86096- } 86097- 86098- // TODO(rfindley): handle type switch implicits correctly here: if the user 86099- // jumps to the type definition of x in x := y.(type), it makes sense to jump 86100- // to the type of y. 86101- _, obj, _ := referencedObject(pkg, pgf, pos) 86102- if obj == nil { 86103- return nil, nil 86104- } 86105- 86106- typObj := typeToObject(obj.Type()) 86107- if typObj == nil { 86108- return nil, fmt.Errorf("no type definition for %s", obj.Name()) 86109- } 86110- 86111- // Identifiers with the type "error" are a special case with no position. 86112- if hasErrorType(typObj) { 86113- // TODO(rfindley): we can do better here, returning a link to the builtin 86114- // file. 86115- return nil, nil 86116- } 86117- 86118- loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, typObj.Pos(), typObj.Pos()+token.Pos(len(typObj.Name()))) 86119- if err != nil { 86120- return nil, err 86121- } 86122- return []protocol.Location{loc}, nil 86123-} 86124diff -urN a/gopls/internal/lsp/source/types_format.go b/gopls/internal/lsp/source/types_format.go 86125--- a/gopls/internal/lsp/source/types_format.go 2000-01-01 00:00:00.000000000 -0000 86126+++ b/gopls/internal/lsp/source/types_format.go 1970-01-01 00:00:00.000000000 +0000 86127@@ -1,517 +0,0 @@ 86128-// Copyright 2020 The Go Authors. All rights reserved. 86129-// Use of this source code is governed by a BSD-style 86130-// license that can be found in the LICENSE file. 86131- 86132-package source 86133- 86134-import ( 86135- "bytes" 86136- "context" 86137- "fmt" 86138- "go/ast" 86139- "go/doc" 86140- "go/printer" 86141- "go/token" 86142- "go/types" 86143- "strings" 86144- 86145- "golang.org/x/tools/gopls/internal/lsp/protocol" 86146- "golang.org/x/tools/internal/bug" 86147- "golang.org/x/tools/internal/event" 86148- "golang.org/x/tools/internal/event/tag" 86149- "golang.org/x/tools/internal/typeparams" 86150-) 86151- 86152-// FormatType returns the detail and kind for a types.Type. 86153-func FormatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) { 86154- if types.IsInterface(typ) { 86155- detail = "interface{...}" 86156- kind = protocol.InterfaceCompletion 86157- } else if _, ok := typ.(*types.Struct); ok { 86158- detail = "struct{...}" 86159- kind = protocol.StructCompletion 86160- } else if typ != typ.Underlying() { 86161- detail, kind = FormatType(typ.Underlying(), qf) 86162- } else { 86163- detail = types.TypeString(typ, qf) 86164- kind = protocol.ClassCompletion 86165- } 86166- return detail, kind 86167-} 86168- 86169-type signature struct { 86170- name, doc string 86171- typeParams, params, results []string 86172- variadic bool 86173- needResultParens bool 86174-} 86175- 86176-func (s *signature) Format() string { 86177- var b strings.Builder 86178- b.WriteByte('(') 86179- for i, p := range s.params { 86180- if i > 0 { 86181- b.WriteString(", ") 86182- } 86183- b.WriteString(p) 86184- } 86185- b.WriteByte(')') 86186- 86187- // Add space between parameters and results. 86188- if len(s.results) > 0 { 86189- b.WriteByte(' ') 86190- } 86191- if s.needResultParens { 86192- b.WriteByte('(') 86193- } 86194- for i, r := range s.results { 86195- if i > 0 { 86196- b.WriteString(", ") 86197- } 86198- b.WriteString(r) 86199- } 86200- if s.needResultParens { 86201- b.WriteByte(')') 86202- } 86203- return b.String() 86204-} 86205- 86206-func (s *signature) TypeParams() []string { 86207- return s.typeParams 86208-} 86209- 86210-func (s *signature) Params() []string { 86211- return s.params 86212-} 86213- 86214-// NewBuiltinSignature returns signature for the builtin object with a given 86215-// name, if a builtin object with the name exists. 86216-func NewBuiltinSignature(ctx context.Context, s Snapshot, name string) (*signature, error) { 86217- builtin, err := s.BuiltinFile(ctx) 86218- if err != nil { 86219- return nil, err 86220- } 86221- obj := builtin.File.Scope.Lookup(name) 86222- if obj == nil { 86223- return nil, fmt.Errorf("no builtin object for %s", name) 86224- } 86225- decl, ok := obj.Decl.(*ast.FuncDecl) 86226- if !ok { 86227- return nil, fmt.Errorf("no function declaration for builtin: %s", name) 86228- } 86229- if decl.Type == nil { 86230- return nil, fmt.Errorf("no type for builtin decl %s", decl.Name) 86231- } 86232- var variadic bool 86233- if decl.Type.Params.List != nil { 86234- numParams := len(decl.Type.Params.List) 86235- lastParam := decl.Type.Params.List[numParams-1] 86236- if _, ok := lastParam.Type.(*ast.Ellipsis); ok { 86237- variadic = true 86238- } 86239- } 86240- fset := FileSetFor(builtin.Tok) 86241- params, _ := formatFieldList(ctx, fset, decl.Type.Params, variadic) 86242- results, needResultParens := formatFieldList(ctx, fset, decl.Type.Results, false) 86243- d := decl.Doc.Text() 86244- switch s.View().Options().HoverKind { 86245- case SynopsisDocumentation: 86246- d = doc.Synopsis(d) 86247- case NoDocumentation: 86248- d = "" 86249- } 86250- return &signature{ 86251- doc: d, 86252- name: name, 86253- needResultParens: needResultParens, 86254- params: params, 86255- results: results, 86256- variadic: variadic, 86257- }, nil 86258-} 86259- 86260-// replacer replaces some synthetic "type classes" used in the builtin file 86261-// with their most common constituent type. 86262-var replacer = strings.NewReplacer( 86263- `ComplexType`, `complex128`, 86264- `FloatType`, `float64`, 86265- `IntegerType`, `int`, 86266-) 86267- 86268-func formatFieldList(ctx context.Context, fset *token.FileSet, list *ast.FieldList, variadic bool) ([]string, bool) { 86269- if list == nil { 86270- return nil, false 86271- } 86272- var writeResultParens bool 86273- var result []string 86274- for i := 0; i < len(list.List); i++ { 86275- if i >= 1 { 86276- writeResultParens = true 86277- } 86278- p := list.List[i] 86279- cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4} 86280- b := &bytes.Buffer{} 86281- if err := cfg.Fprint(b, fset, p.Type); err != nil { 86282- event.Error(ctx, "unable to print type", nil, tag.Type.Of(p.Type)) 86283- continue 86284- } 86285- typ := replacer.Replace(b.String()) 86286- if len(p.Names) == 0 { 86287- result = append(result, typ) 86288- } 86289- for _, name := range p.Names { 86290- if name.Name != "" { 86291- if i == 0 { 86292- writeResultParens = true 86293- } 86294- result = append(result, fmt.Sprintf("%s %s", name.Name, typ)) 86295- } else { 86296- result = append(result, typ) 86297- } 86298- } 86299- } 86300- if variadic { 86301- result[len(result)-1] = strings.Replace(result[len(result)-1], "[]", "...", 1) 86302- } 86303- return result, writeResultParens 86304-} 86305- 86306-// FormatTypeParams turns TypeParamList into its Go representation, such as: 86307-// [T, Y]. Note that it does not print constraints as this is mainly used for 86308-// formatting type params in method receivers. 86309-func FormatTypeParams(tparams *typeparams.TypeParamList) string { 86310- if tparams == nil || tparams.Len() == 0 { 86311- return "" 86312- } 86313- var buf bytes.Buffer 86314- buf.WriteByte('[') 86315- for i := 0; i < tparams.Len(); i++ { 86316- if i > 0 { 86317- buf.WriteString(", ") 86318- } 86319- buf.WriteString(tparams.At(i).Obj().Name()) 86320- } 86321- buf.WriteByte(']') 86322- return buf.String() 86323-} 86324- 86325-// NewSignature returns formatted signature for a types.Signature struct. 86326-func NewSignature(ctx context.Context, s Snapshot, pkg Package, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier, mq MetadataQualifier) (*signature, error) { 86327- var tparams []string 86328- tpList := typeparams.ForSignature(sig) 86329- for i := 0; i < tpList.Len(); i++ { 86330- tparam := tpList.At(i) 86331- // TODO: is it possible to reuse the logic from FormatVarType here? 86332- s := tparam.Obj().Name() + " " + tparam.Constraint().String() 86333- tparams = append(tparams, s) 86334- } 86335- 86336- params := make([]string, 0, sig.Params().Len()) 86337- for i := 0; i < sig.Params().Len(); i++ { 86338- el := sig.Params().At(i) 86339- typ, err := FormatVarType(ctx, s, pkg, el, qf, mq) 86340- if err != nil { 86341- return nil, err 86342- } 86343- p := typ 86344- if el.Name() != "" { 86345- p = el.Name() + " " + typ 86346- } 86347- params = append(params, p) 86348- } 86349- 86350- var needResultParens bool 86351- results := make([]string, 0, sig.Results().Len()) 86352- for i := 0; i < sig.Results().Len(); i++ { 86353- if i >= 1 { 86354- needResultParens = true 86355- } 86356- el := sig.Results().At(i) 86357- typ, err := FormatVarType(ctx, s, pkg, el, qf, mq) 86358- if err != nil { 86359- return nil, err 86360- } 86361- if el.Name() == "" { 86362- results = append(results, typ) 86363- } else { 86364- if i == 0 { 86365- needResultParens = true 86366- } 86367- results = append(results, el.Name()+" "+typ) 86368- } 86369- } 86370- var d string 86371- if comment != nil { 86372- d = comment.Text() 86373- } 86374- switch s.View().Options().HoverKind { 86375- case SynopsisDocumentation: 86376- d = doc.Synopsis(d) 86377- case NoDocumentation: 86378- d = "" 86379- } 86380- return &signature{ 86381- doc: d, 86382- typeParams: tparams, 86383- params: params, 86384- results: results, 86385- variadic: sig.Variadic(), 86386- needResultParens: needResultParens, 86387- }, nil 86388-} 86389- 86390-// FormatVarType formats a *types.Var, accounting for type aliases. 86391-// To do this, it looks in the AST of the file in which the object is declared. 86392-// On any errors, it always falls back to types.TypeString. 86393-// 86394-// TODO(rfindley): this function could return the actual name used in syntax, 86395-// for better parameter names. 86396-func FormatVarType(ctx context.Context, snapshot Snapshot, srcpkg Package, obj *types.Var, qf types.Qualifier, mq MetadataQualifier) (string, error) { 86397- // TODO(rfindley): This looks wrong. The previous comment said: 86398- // "If the given expr refers to a type parameter, then use the 86399- // object's Type instead of the type parameter declaration. This helps 86400- // format the instantiated type as opposed to the original undeclared 86401- // generic type". 86402- // 86403- // But of course, if obj is a type param, we are formatting a generic type 86404- // and not an instantiated type. Handling for instantiated types must be done 86405- // at a higher level. 86406- // 86407- // Left this during refactoring in order to preserve pre-existing logic. 86408- if typeparams.IsTypeParam(obj.Type()) { 86409- return types.TypeString(obj.Type(), qf), nil 86410- } 86411- 86412- if obj.Pkg() == nil || !obj.Pos().IsValid() { 86413- // This is defensive, though it is extremely unlikely we'll ever have a 86414- // builtin var. 86415- return types.TypeString(obj.Type(), qf), nil 86416- } 86417- 86418- targetpgf, pos, err := parseFull(ctx, snapshot, srcpkg.FileSet(), obj.Pos()) 86419- if err != nil { 86420- return "", err // e.g. ctx cancelled 86421- } 86422- 86423- targetMeta := findFileInDeps(snapshot, srcpkg.Metadata(), targetpgf.URI) 86424- if targetMeta == nil { 86425- // If we have an object from type-checking, it should exist in a file in 86426- // the forward transitive closure. 86427- return "", bug.Errorf("failed to find file %q in deps of %q", targetpgf.URI, srcpkg.Metadata().ID) 86428- } 86429- 86430- decl, spec, field := findDeclInfo([]*ast.File{targetpgf.File}, pos) 86431- 86432- // We can't handle type parameters correctly, so we fall back on TypeString 86433- // for parameterized decls. 86434- if decl, _ := decl.(*ast.FuncDecl); decl != nil { 86435- if typeparams.ForFuncType(decl.Type).NumFields() > 0 { 86436- return types.TypeString(obj.Type(), qf), nil // in generic function 86437- } 86438- if decl.Recv != nil && len(decl.Recv.List) > 0 { 86439- if x, _, _, _ := typeparams.UnpackIndexExpr(decl.Recv.List[0].Type); x != nil { 86440- return types.TypeString(obj.Type(), qf), nil // in method of generic type 86441- } 86442- } 86443- } 86444- if spec, _ := spec.(*ast.TypeSpec); spec != nil && typeparams.ForTypeSpec(spec).NumFields() > 0 { 86445- return types.TypeString(obj.Type(), qf), nil // in generic type decl 86446- } 86447- 86448- if field == nil { 86449- // TODO(rfindley): we should never reach here from an ordinary var, so 86450- // should probably return an error here. 86451- return types.TypeString(obj.Type(), qf), nil 86452- } 86453- expr := field.Type 86454- 86455- rq := requalifier(snapshot, targetpgf.File, targetMeta, mq) 86456- 86457- // The type names in the AST may not be correctly qualified. 86458- // Determine the package name to use based on the package that originated 86459- // the query and the package in which the type is declared. 86460- // We then qualify the value by cloning the AST node and editing it. 86461- expr = qualifyTypeExpr(expr, rq) 86462- 86463- // If the request came from a different package than the one in which the 86464- // types are defined, we may need to modify the qualifiers. 86465- return FormatNodeFile(targetpgf.Tok, expr), nil 86466-} 86467- 86468-// qualifyTypeExpr clones the type expression expr after re-qualifying type 86469-// names using the given function, which accepts the current syntactic 86470-// qualifier (possibly "" for unqualified idents), and returns a new qualifier 86471-// (again, possibly "" if the identifier should be unqualified). 86472-// 86473-// The resulting expression may be inaccurate: without type-checking we don't 86474-// properly account for "." imported identifiers or builtins. 86475-// 86476-// TODO(rfindley): add many more tests for this function. 86477-func qualifyTypeExpr(expr ast.Expr, qf func(string) string) ast.Expr { 86478- switch expr := expr.(type) { 86479- case *ast.ArrayType: 86480- return &ast.ArrayType{ 86481- Lbrack: expr.Lbrack, 86482- Elt: qualifyTypeExpr(expr.Elt, qf), 86483- Len: expr.Len, 86484- } 86485- 86486- case *ast.BinaryExpr: 86487- if expr.Op != token.OR { 86488- return expr 86489- } 86490- return &ast.BinaryExpr{ 86491- X: qualifyTypeExpr(expr.X, qf), 86492- OpPos: expr.OpPos, 86493- Op: expr.Op, 86494- Y: qualifyTypeExpr(expr.Y, qf), 86495- } 86496- 86497- case *ast.ChanType: 86498- return &ast.ChanType{ 86499- Arrow: expr.Arrow, 86500- Begin: expr.Begin, 86501- Dir: expr.Dir, 86502- Value: qualifyTypeExpr(expr.Value, qf), 86503- } 86504- 86505- case *ast.Ellipsis: 86506- return &ast.Ellipsis{ 86507- Ellipsis: expr.Ellipsis, 86508- Elt: qualifyTypeExpr(expr.Elt, qf), 86509- } 86510- 86511- case *ast.FuncType: 86512- return &ast.FuncType{ 86513- Func: expr.Func, 86514- Params: qualifyFieldList(expr.Params, qf), 86515- Results: qualifyFieldList(expr.Results, qf), 86516- } 86517- 86518- case *ast.Ident: 86519- // Unqualified type (builtin, package local, or dot-imported). 86520- 86521- // Don't qualify names that look like builtins. 86522- // 86523- // Without type-checking this may be inaccurate. It could be made accurate 86524- // by doing syntactic object resolution for the entire package, but that 86525- // does not seem worthwhile and we generally want to avoid using 86526- // ast.Object, which may be inaccurate. 86527- if obj := types.Universe.Lookup(expr.Name); obj != nil { 86528- return expr 86529- } 86530- 86531- newName := qf("") 86532- if newName != "" { 86533- return &ast.SelectorExpr{ 86534- X: &ast.Ident{ 86535- NamePos: expr.Pos(), 86536- Name: newName, 86537- }, 86538- Sel: expr, 86539- } 86540- } 86541- return expr 86542- 86543- case *ast.IndexExpr: 86544- return &ast.IndexExpr{ 86545- X: qualifyTypeExpr(expr.X, qf), 86546- Lbrack: expr.Lbrack, 86547- Index: qualifyTypeExpr(expr.Index, qf), 86548- Rbrack: expr.Rbrack, 86549- } 86550- 86551- case *typeparams.IndexListExpr: 86552- indices := make([]ast.Expr, len(expr.Indices)) 86553- for i, idx := range expr.Indices { 86554- indices[i] = qualifyTypeExpr(idx, qf) 86555- } 86556- return &typeparams.IndexListExpr{ 86557- X: qualifyTypeExpr(expr.X, qf), 86558- Lbrack: expr.Lbrack, 86559- Indices: indices, 86560- Rbrack: expr.Rbrack, 86561- } 86562- 86563- case *ast.InterfaceType: 86564- return &ast.InterfaceType{ 86565- Interface: expr.Interface, 86566- Methods: qualifyFieldList(expr.Methods, qf), 86567- Incomplete: expr.Incomplete, 86568- } 86569- 86570- case *ast.MapType: 86571- return &ast.MapType{ 86572- Map: expr.Map, 86573- Key: qualifyTypeExpr(expr.Key, qf), 86574- Value: qualifyTypeExpr(expr.Value, qf), 86575- } 86576- 86577- case *ast.ParenExpr: 86578- return &ast.ParenExpr{ 86579- Lparen: expr.Lparen, 86580- Rparen: expr.Rparen, 86581- X: qualifyTypeExpr(expr.X, qf), 86582- } 86583- 86584- case *ast.SelectorExpr: 86585- if id, ok := expr.X.(*ast.Ident); ok { 86586- // qualified type 86587- newName := qf(id.Name) 86588- if newName == "" { 86589- return expr.Sel 86590- } 86591- return &ast.SelectorExpr{ 86592- X: &ast.Ident{ 86593- NamePos: id.NamePos, 86594- Name: newName, 86595- }, 86596- Sel: expr.Sel, 86597- } 86598- } 86599- return expr 86600- 86601- case *ast.StarExpr: 86602- return &ast.StarExpr{ 86603- Star: expr.Star, 86604- X: qualifyTypeExpr(expr.X, qf), 86605- } 86606- 86607- case *ast.StructType: 86608- return &ast.StructType{ 86609- Struct: expr.Struct, 86610- Fields: qualifyFieldList(expr.Fields, qf), 86611- Incomplete: expr.Incomplete, 86612- } 86613- 86614- default: 86615- return expr 86616- } 86617-} 86618- 86619-func qualifyFieldList(fl *ast.FieldList, qf func(string) string) *ast.FieldList { 86620- if fl == nil { 86621- return nil 86622- } 86623- if fl.List == nil { 86624- return &ast.FieldList{ 86625- Closing: fl.Closing, 86626- Opening: fl.Opening, 86627- } 86628- } 86629- list := make([]*ast.Field, 0, len(fl.List)) 86630- for _, f := range fl.List { 86631- list = append(list, &ast.Field{ 86632- Comment: f.Comment, 86633- Doc: f.Doc, 86634- Names: f.Names, 86635- Tag: f.Tag, 86636- Type: qualifyTypeExpr(f.Type, qf), 86637- }) 86638- } 86639- return &ast.FieldList{ 86640- Closing: fl.Closing, 86641- Opening: fl.Opening, 86642- List: list, 86643- } 86644-} 86645diff -urN a/gopls/internal/lsp/source/util.go b/gopls/internal/lsp/source/util.go 86646--- a/gopls/internal/lsp/source/util.go 2000-01-01 00:00:00.000000000 -0000 86647+++ b/gopls/internal/lsp/source/util.go 1970-01-01 00:00:00.000000000 +0000 86648@@ -1,555 +0,0 @@ 86649-// Copyright 2019 The Go Authors. All rights reserved. 86650-// Use of this source code is governed by a BSD-style 86651-// license that can be found in the LICENSE file. 86652- 86653-package source 86654- 86655-import ( 86656- "context" 86657- "go/ast" 86658- "go/printer" 86659- "go/token" 86660- "go/types" 86661- "path/filepath" 86662- "regexp" 86663- "sort" 86664- "strconv" 86665- "strings" 86666- 86667- "golang.org/x/tools/gopls/internal/lsp/protocol" 86668- "golang.org/x/tools/gopls/internal/lsp/safetoken" 86669- "golang.org/x/tools/gopls/internal/span" 86670- "golang.org/x/tools/internal/bug" 86671- "golang.org/x/tools/internal/tokeninternal" 86672- "golang.org/x/tools/internal/typeparams" 86673-) 86674- 86675-// IsGenerated gets and reads the file denoted by uri and reports 86676-// whether it contains a "generated file" comment as described at 86677-// https://golang.org/s/generatedcode. 86678-// 86679-// TODO(adonovan): opt: this function does too much. 86680-// Move snapshot.GetFile into the caller (most of which have already done it). 86681-func IsGenerated(ctx context.Context, snapshot Snapshot, uri span.URI) bool { 86682- fh, err := snapshot.GetFile(ctx, uri) 86683- if err != nil { 86684- return false 86685- } 86686- pgf, err := snapshot.ParseGo(ctx, fh, ParseHeader) 86687- if err != nil { 86688- return false 86689- } 86690- for _, commentGroup := range pgf.File.Comments { 86691- for _, comment := range commentGroup.List { 86692- if matched := generatedRx.MatchString(comment.Text); matched { 86693- // Check if comment is at the beginning of the line in source. 86694- if safetoken.Position(pgf.Tok, comment.Slash).Column == 1 { 86695- return true 86696- } 86697- } 86698- } 86699- } 86700- return false 86701-} 86702- 86703-// adjustedObjEnd returns the end position of obj, possibly modified for 86704-// package names. 86705-// 86706-// TODO(rfindley): eliminate this function, by inlining it at callsites where 86707-// it makes sense. 86708-func adjustedObjEnd(obj types.Object) token.Pos { 86709- nameLen := len(obj.Name()) 86710- if pkgName, ok := obj.(*types.PkgName); ok { 86711- // An imported Go package has a package-local, unqualified name. 86712- // When the name matches the imported package name, there is no 86713- // identifier in the import spec with the local package name. 86714- // 86715- // For example: 86716- // import "go/ast" // name "ast" matches package name 86717- // import a "go/ast" // name "a" does not match package name 86718- // 86719- // When the identifier does not appear in the source, have the range 86720- // of the object be the import path, including quotes. 86721- if pkgName.Imported().Name() == pkgName.Name() { 86722- nameLen = len(pkgName.Imported().Path()) + len(`""`) 86723- } 86724- } 86725- return obj.Pos() + token.Pos(nameLen) 86726-} 86727- 86728-// Matches cgo generated comment as well as the proposed standard: 86729-// 86730-// https://golang.org/s/generatedcode 86731-var generatedRx = regexp.MustCompile(`// .*DO NOT EDIT\.?`) 86732- 86733-// FileKindForLang returns the file kind associated with the given language ID, 86734-// or UnknownKind if the language ID is not recognized. 86735-func FileKindForLang(langID string) FileKind { 86736- switch langID { 86737- case "go": 86738- return Go 86739- case "go.mod": 86740- return Mod 86741- case "go.sum": 86742- return Sum 86743- case "tmpl", "gotmpl": 86744- return Tmpl 86745- case "go.work": 86746- return Work 86747- default: 86748- return UnknownKind 86749- } 86750-} 86751- 86752-// nodeAtPos returns the index and the node whose position is contained inside 86753-// the node list. 86754-func nodeAtPos(nodes []ast.Node, pos token.Pos) (ast.Node, int) { 86755- if nodes == nil { 86756- return nil, -1 86757- } 86758- for i, node := range nodes { 86759- if node.Pos() <= pos && pos <= node.End() { 86760- return node, i 86761- } 86762- } 86763- return nil, -1 86764-} 86765- 86766-// FormatNode returns the "pretty-print" output for an ast node. 86767-func FormatNode(fset *token.FileSet, n ast.Node) string { 86768- var buf strings.Builder 86769- if err := printer.Fprint(&buf, fset, n); err != nil { 86770- return "" 86771- } 86772- return buf.String() 86773-} 86774- 86775-// FormatNodeFile is like FormatNode, but requires only the token.File for the 86776-// syntax containing the given ast node. 86777-func FormatNodeFile(file *token.File, n ast.Node) string { 86778- fset := FileSetFor(file) 86779- return FormatNode(fset, n) 86780-} 86781- 86782-// FileSetFor returns a new FileSet containing a sequence of new Files with 86783-// the same base, size, and line as the input files, for use in APIs that 86784-// require a FileSet. 86785-// 86786-// Precondition: the input files must be non-overlapping, and sorted in order 86787-// of their Base. 86788-func FileSetFor(files ...*token.File) *token.FileSet { 86789- fset := token.NewFileSet() 86790- for _, f := range files { 86791- f2 := fset.AddFile(f.Name(), f.Base(), f.Size()) 86792- lines := tokeninternal.GetLines(f) 86793- f2.SetLines(lines) 86794- } 86795- return fset 86796-} 86797- 86798-// Deref returns a pointer's element type, traversing as many levels as needed. 86799-// Otherwise it returns typ. 86800-// 86801-// It can return a pointer type for cyclic types (see golang/go#45510). 86802-func Deref(typ types.Type) types.Type { 86803- var seen map[types.Type]struct{} 86804- for { 86805- p, ok := typ.Underlying().(*types.Pointer) 86806- if !ok { 86807- return typ 86808- } 86809- if _, ok := seen[p.Elem()]; ok { 86810- return typ 86811- } 86812- 86813- typ = p.Elem() 86814- 86815- if seen == nil { 86816- seen = make(map[types.Type]struct{}) 86817- } 86818- seen[typ] = struct{}{} 86819- } 86820-} 86821- 86822-func SortDiagnostics(d []*Diagnostic) { 86823- sort.Slice(d, func(i int, j int) bool { 86824- return CompareDiagnostic(d[i], d[j]) < 0 86825- }) 86826-} 86827- 86828-func CompareDiagnostic(a, b *Diagnostic) int { 86829- if r := protocol.CompareRange(a.Range, b.Range); r != 0 { 86830- return r 86831- } 86832- if a.Source < b.Source { 86833- return -1 86834- } 86835- if a.Source > b.Source { 86836- return +1 86837- } 86838- if a.Message < b.Message { 86839- return -1 86840- } 86841- if a.Message > b.Message { 86842- return +1 86843- } 86844- return 0 86845-} 86846- 86847-// findFileInDeps finds package metadata containing URI in the transitive 86848-// dependencies of m. When using the Go command, the answer is unique. 86849-// 86850-// TODO(rfindley): refactor to share logic with findPackageInDeps? 86851-func findFileInDeps(s MetadataSource, m *Metadata, uri span.URI) *Metadata { 86852- seen := make(map[PackageID]bool) 86853- var search func(*Metadata) *Metadata 86854- search = func(m *Metadata) *Metadata { 86855- if seen[m.ID] { 86856- return nil 86857- } 86858- seen[m.ID] = true 86859- for _, cgf := range m.CompiledGoFiles { 86860- if cgf == uri { 86861- return m 86862- } 86863- } 86864- for _, dep := range m.DepsByPkgPath { 86865- m := s.Metadata(dep) 86866- if m == nil { 86867- bug.Reportf("nil metadata for %q", dep) 86868- continue 86869- } 86870- if found := search(m); found != nil { 86871- return found 86872- } 86873- } 86874- return nil 86875- } 86876- return search(m) 86877-} 86878- 86879-// UnquoteImportPath returns the unquoted import path of s, 86880-// or "" if the path is not properly quoted. 86881-func UnquoteImportPath(s *ast.ImportSpec) ImportPath { 86882- path, err := strconv.Unquote(s.Path.Value) 86883- if err != nil { 86884- return "" 86885- } 86886- return ImportPath(path) 86887-} 86888- 86889-// NodeContains returns true if a node encloses a given position pos. 86890-func NodeContains(n ast.Node, pos token.Pos) bool { 86891- return n != nil && n.Pos() <= pos && pos <= n.End() 86892-} 86893- 86894-// CollectScopes returns all scopes in an ast path, ordered as innermost scope 86895-// first. 86896-func CollectScopes(info *types.Info, path []ast.Node, pos token.Pos) []*types.Scope { 86897- // scopes[i], where i<len(path), is the possibly nil Scope of path[i]. 86898- var scopes []*types.Scope 86899- for _, n := range path { 86900- // Include *FuncType scope if pos is inside the function body. 86901- switch node := n.(type) { 86902- case *ast.FuncDecl: 86903- if node.Body != nil && NodeContains(node.Body, pos) { 86904- n = node.Type 86905- } 86906- case *ast.FuncLit: 86907- if node.Body != nil && NodeContains(node.Body, pos) { 86908- n = node.Type 86909- } 86910- } 86911- scopes = append(scopes, info.Scopes[n]) 86912- } 86913- return scopes 86914-} 86915- 86916-// Qualifier returns a function that appropriately formats a types.PkgName 86917-// appearing in a *ast.File. 86918-func Qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifier { 86919- // Construct mapping of import paths to their defined or implicit names. 86920- imports := make(map[*types.Package]string) 86921- for _, imp := range f.Imports { 86922- var obj types.Object 86923- if imp.Name != nil { 86924- obj = info.Defs[imp.Name] 86925- } else { 86926- obj = info.Implicits[imp] 86927- } 86928- if pkgname, ok := obj.(*types.PkgName); ok { 86929- imports[pkgname.Imported()] = pkgname.Name() 86930- } 86931- } 86932- // Define qualifier to replace full package paths with names of the imports. 86933- return func(p *types.Package) string { 86934- if p == pkg { 86935- return "" 86936- } 86937- if name, ok := imports[p]; ok { 86938- if name == "." { 86939- return "" 86940- } 86941- return name 86942- } 86943- return p.Name() 86944- } 86945-} 86946- 86947-// requalifier returns a function that re-qualifies identifiers and qualified 86948-// identifiers contained in targetFile using the given metadata qualifier. 86949-func requalifier(s MetadataSource, targetFile *ast.File, targetMeta *Metadata, mq MetadataQualifier) func(string) string { 86950- qm := map[string]string{ 86951- "": mq(targetMeta.Name, "", targetMeta.PkgPath), 86952- } 86953- 86954- // Construct mapping of import paths to their defined or implicit names. 86955- for _, imp := range targetFile.Imports { 86956- name, pkgName, impPath, pkgPath := importInfo(s, imp, targetMeta) 86957- 86958- // Re-map the target name for the source file. 86959- qm[name] = mq(pkgName, impPath, pkgPath) 86960- } 86961- 86962- return func(name string) string { 86963- if newName, ok := qm[name]; ok { 86964- return newName 86965- } 86966- return name 86967- } 86968-} 86969- 86970-// A MetadataQualifier is a function that qualifies an identifier declared in a 86971-// package with the given package name, import path, and package path. 86972-// 86973-// In scenarios where metadata is missing the provided PackageName and 86974-// PackagePath may be empty, but ImportPath must always be non-empty. 86975-type MetadataQualifier func(PackageName, ImportPath, PackagePath) string 86976- 86977-// MetadataQualifierForFile returns a metadata qualifier that chooses the best 86978-// qualification of an imported package relative to the file f in package with 86979-// metadata m. 86980-func MetadataQualifierForFile(s MetadataSource, f *ast.File, m *Metadata) MetadataQualifier { 86981- // Record local names for import paths. 86982- localNames := make(map[ImportPath]string) // local names for imports in f 86983- for _, imp := range f.Imports { 86984- name, _, impPath, _ := importInfo(s, imp, m) 86985- localNames[impPath] = name 86986- } 86987- 86988- // Record a package path -> import path mapping. 86989- inverseDeps := make(map[PackageID]PackagePath) 86990- for path, id := range m.DepsByPkgPath { 86991- inverseDeps[id] = path 86992- } 86993- importsByPkgPath := make(map[PackagePath]ImportPath) // best import paths by pkgPath 86994- for impPath, id := range m.DepsByImpPath { 86995- if id == "" { 86996- continue 86997- } 86998- pkgPath := inverseDeps[id] 86999- _, hasPath := importsByPkgPath[pkgPath] 87000- _, hasImp := localNames[impPath] 87001- // In rare cases, there may be multiple import paths with the same package 87002- // path. In such scenarios, prefer an import path that already exists in 87003- // the file. 87004- if !hasPath || hasImp { 87005- importsByPkgPath[pkgPath] = impPath 87006- } 87007- } 87008- 87009- return func(pkgName PackageName, impPath ImportPath, pkgPath PackagePath) string { 87010- // If supplied, translate the package path to an import path in the source 87011- // package. 87012- if pkgPath != "" { 87013- if srcImp := importsByPkgPath[pkgPath]; srcImp != "" { 87014- impPath = srcImp 87015- } 87016- if pkgPath == m.PkgPath { 87017- return "" 87018- } 87019- } 87020- if localName, ok := localNames[impPath]; ok && impPath != "" { 87021- return string(localName) 87022- } 87023- if pkgName != "" { 87024- return string(pkgName) 87025- } 87026- idx := strings.LastIndexByte(string(impPath), '/') 87027- return string(impPath[idx+1:]) 87028- } 87029-} 87030- 87031-// importInfo collects information about the import specified by imp, 87032-// extracting its file-local name, package name, import path, and package path. 87033-// 87034-// If metadata is missing for the import, the resulting package name and 87035-// package path may be empty, and the file local name may be guessed based on 87036-// the import path. 87037-// 87038-// Note: previous versions of this helper used a PackageID->PackagePath map 87039-// extracted from m, for extracting package path even in the case where 87040-// metadata for a dep was missing. This should not be necessary, as we should 87041-// always have metadata for IDs contained in DepsByPkgPath. 87042-func importInfo(s MetadataSource, imp *ast.ImportSpec, m *Metadata) (string, PackageName, ImportPath, PackagePath) { 87043- var ( 87044- name string // local name 87045- pkgName PackageName 87046- impPath = UnquoteImportPath(imp) 87047- pkgPath PackagePath 87048- ) 87049- 87050- // If the import has a local name, use it. 87051- if imp.Name != nil { 87052- name = imp.Name.Name 87053- } 87054- 87055- // Try to find metadata for the import. If successful and there is no local 87056- // name, the package name is the local name. 87057- if depID := m.DepsByImpPath[impPath]; depID != "" { 87058- if depm := s.Metadata(depID); depm != nil { 87059- if name == "" { 87060- name = string(depm.Name) 87061- } 87062- pkgName = depm.Name 87063- pkgPath = depm.PkgPath 87064- } 87065- } 87066- 87067- // If the local name is still unknown, guess it based on the import path. 87068- if name == "" { 87069- idx := strings.LastIndexByte(string(impPath), '/') 87070- name = string(impPath[idx+1:]) 87071- } 87072- return name, pkgName, impPath, pkgPath 87073-} 87074- 87075-// isDirective reports whether c is a comment directive. 87076-// 87077-// Copied and adapted from go/src/go/ast/ast.go. 87078-func isDirective(c string) bool { 87079- if len(c) < 3 { 87080- return false 87081- } 87082- if c[1] != '/' { 87083- return false 87084- } 87085- //-style comment (no newline at the end) 87086- c = c[2:] 87087- if len(c) == 0 { 87088- // empty line 87089- return false 87090- } 87091- // "//line " is a line directive. 87092- // (The // has been removed.) 87093- if strings.HasPrefix(c, "line ") { 87094- return true 87095- } 87096- 87097- // "//[a-z0-9]+:[a-z0-9]" 87098- // (The // has been removed.) 87099- colon := strings.Index(c, ":") 87100- if colon <= 0 || colon+1 >= len(c) { 87101- return false 87102- } 87103- for i := 0; i <= colon+1; i++ { 87104- if i == colon { 87105- continue 87106- } 87107- b := c[i] 87108- if !('a' <= b && b <= 'z' || '0' <= b && b <= '9') { 87109- return false 87110- } 87111- } 87112- return true 87113-} 87114- 87115-// InDir checks whether path is in the file tree rooted at dir. 87116-// It checks only the lexical form of the file names. 87117-// It does not consider symbolic links. 87118-// 87119-// Copied from go/src/cmd/go/internal/search/search.go. 87120-func InDir(dir, path string) bool { 87121- pv := strings.ToUpper(filepath.VolumeName(path)) 87122- dv := strings.ToUpper(filepath.VolumeName(dir)) 87123- path = path[len(pv):] 87124- dir = dir[len(dv):] 87125- switch { 87126- default: 87127- return false 87128- case pv != dv: 87129- return false 87130- case len(path) == len(dir): 87131- if path == dir { 87132- return true 87133- } 87134- return false 87135- case dir == "": 87136- return path != "" 87137- case len(path) > len(dir): 87138- if dir[len(dir)-1] == filepath.Separator { 87139- if path[:len(dir)] == dir { 87140- return path[len(dir):] != "" 87141- } 87142- return false 87143- } 87144- if path[len(dir)] == filepath.Separator && path[:len(dir)] == dir { 87145- if len(path) == len(dir)+1 { 87146- return true 87147- } 87148- return path[len(dir)+1:] != "" 87149- } 87150- return false 87151- } 87152-} 87153- 87154-// IsValidImport returns whether importPkgPath is importable 87155-// by pkgPath 87156-func IsValidImport(pkgPath, importPkgPath PackagePath) bool { 87157- i := strings.LastIndex(string(importPkgPath), "/internal/") 87158- if i == -1 { 87159- return true 87160- } 87161- // TODO(rfindley): this looks wrong: IsCommandLineArguments is meant to 87162- // operate on package IDs, not package paths. 87163- if IsCommandLineArguments(PackageID(pkgPath)) { 87164- return true 87165- } 87166- // TODO(rfindley): this is wrong. mod.testx/p should not be able to 87167- // import mod.test/internal: https://go.dev/play/p/-Ca6P-E4V4q 87168- return strings.HasPrefix(string(pkgPath), string(importPkgPath[:i])) 87169-} 87170- 87171-// IsCommandLineArguments reports whether a given value denotes 87172-// "command-line-arguments" package, which is a package with an unknown ID 87173-// created by the go command. It can have a test variant, which is why callers 87174-// should not check that a value equals "command-line-arguments" directly. 87175-func IsCommandLineArguments(id PackageID) bool { 87176- return strings.Contains(string(id), "command-line-arguments") 87177-} 87178- 87179-// embeddedIdent returns the type name identifier for an embedding x, if x in a 87180-// valid embedding. Otherwise, it returns nil. 87181-// 87182-// Spec: An embedded field must be specified as a type name T or as a pointer 87183-// to a non-interface type name *T 87184-func embeddedIdent(x ast.Expr) *ast.Ident { 87185- if star, ok := x.(*ast.StarExpr); ok { 87186- x = star.X 87187- } 87188- switch ix := x.(type) { // check for instantiated receivers 87189- case *ast.IndexExpr: 87190- x = ix.X 87191- case *typeparams.IndexListExpr: 87192- x = ix.X 87193- } 87194- switch x := x.(type) { 87195- case *ast.Ident: 87196- return x 87197- case *ast.SelectorExpr: 87198- if _, ok := x.X.(*ast.Ident); ok { 87199- return x.Sel 87200- } 87201- } 87202- return nil 87203-} 87204diff -urN a/gopls/internal/lsp/source/view.go b/gopls/internal/lsp/source/view.go 87205--- a/gopls/internal/lsp/source/view.go 2000-01-01 00:00:00.000000000 -0000 87206+++ b/gopls/internal/lsp/source/view.go 1970-01-01 00:00:00.000000000 +0000 87207@@ -1,857 +0,0 @@ 87208-// Copyright 2018 The Go Authors. All rights reserved. 87209-// Use of this source code is governed by a BSD-style 87210-// license that can be found in the LICENSE file. 87211- 87212-package source 87213- 87214-import ( 87215- "bytes" 87216- "context" 87217- "crypto/sha256" 87218- "errors" 87219- "fmt" 87220- "go/ast" 87221- "go/scanner" 87222- "go/token" 87223- "go/types" 87224- "io" 87225- 87226- "golang.org/x/mod/modfile" 87227- "golang.org/x/tools/go/analysis" 87228- "golang.org/x/tools/go/packages" 87229- "golang.org/x/tools/go/types/objectpath" 87230- "golang.org/x/tools/gopls/internal/govulncheck" 87231- "golang.org/x/tools/gopls/internal/lsp/protocol" 87232- "golang.org/x/tools/gopls/internal/lsp/safetoken" 87233- "golang.org/x/tools/gopls/internal/lsp/source/methodsets" 87234- "golang.org/x/tools/gopls/internal/span" 87235- "golang.org/x/tools/internal/event/label" 87236- "golang.org/x/tools/internal/event/tag" 87237- "golang.org/x/tools/internal/gocommand" 87238- "golang.org/x/tools/internal/imports" 87239- "golang.org/x/tools/internal/packagesinternal" 87240-) 87241- 87242-// A GlobalSnapshotID uniquely identifies a snapshot within this process and 87243-// increases monotonically with snapshot creation time. 87244-// 87245-// We use a distinct integral type for global IDs to help enforce correct 87246-// usage. 87247-type GlobalSnapshotID uint64 87248- 87249-// Snapshot represents the current state for the given view. 87250-type Snapshot interface { 87251- // SequenceID is the sequence id of this snapshot within its containing 87252- // view. 87253- // 87254- // Relative to their view sequence ids are monotonically increasing, but this 87255- // does not hold globally: when new views are created their initial snapshot 87256- // has sequence ID 0. For operations that span multiple views, use global 87257- // IDs. 87258- SequenceID() uint64 87259- 87260- // GlobalID is a globally unique identifier for this snapshot. Global IDs are 87261- // monotonic: subsequent snapshots will have higher global ID, though 87262- // subsequent snapshots in a view may not have adjacent global IDs. 87263- GlobalID() GlobalSnapshotID 87264- 87265- // View returns the View associated with this snapshot. 87266- View() View 87267- 87268- // BackgroundContext returns a context used for all background processing 87269- // on behalf of this snapshot. 87270- BackgroundContext() context.Context 87271- 87272- // ValidBuildConfiguration returns true if there is some error in the 87273- // user's workspace. In particular, if they are both outside of a module 87274- // and their GOPATH. 87275- ValidBuildConfiguration() bool 87276- 87277- // FindFile returns the FileHandle for the given URI, if it is already 87278- // in the given snapshot. 87279- FindFile(uri span.URI) FileHandle 87280- 87281- // GetFile returns the FileHandle for a given URI, initializing it if it is 87282- // not already part of the snapshot. 87283- GetFile(ctx context.Context, uri span.URI) (FileHandle, error) 87284- 87285- // AwaitInitialized waits until the snapshot's view is initialized. 87286- AwaitInitialized(ctx context.Context) 87287- 87288- // IsOpen returns whether the editor currently has a file open. 87289- IsOpen(uri span.URI) bool 87290- 87291- // IgnoredFile reports if a file would be ignored by a `go list` of the whole 87292- // workspace. 87293- IgnoredFile(uri span.URI) bool 87294- 87295- // Templates returns the .tmpl files 87296- Templates() map[span.URI]FileHandle 87297- 87298- // ParseGo returns the parsed AST for the file. 87299- // If the file is not available, returns nil and an error. 87300- // Position information is added to FileSet(). 87301- ParseGo(ctx context.Context, fh FileHandle, mode ParseMode) (*ParsedGoFile, error) 87302- 87303- // Analyze runs the specified analyzers on the given package at this snapshot. 87304- Analyze(ctx context.Context, id PackageID, analyzers []*Analyzer) ([]*Diagnostic, error) 87305- 87306- // RunGoCommandPiped runs the given `go` command, writing its output 87307- // to stdout and stderr. Verb, Args, and WorkingDir must be specified. 87308- // 87309- // RunGoCommandPiped runs the command serially using gocommand.RunPiped, 87310- // enforcing that this command executes exclusively to other commands on the 87311- // server. 87312- RunGoCommandPiped(ctx context.Context, mode InvocationFlags, inv *gocommand.Invocation, stdout, stderr io.Writer) error 87313- 87314- // RunGoCommandDirect runs the given `go` command. Verb, Args, and 87315- // WorkingDir must be specified. 87316- RunGoCommandDirect(ctx context.Context, mode InvocationFlags, inv *gocommand.Invocation) (*bytes.Buffer, error) 87317- 87318- // RunGoCommands runs a series of `go` commands that updates the go.mod 87319- // and go.sum file for wd, and returns their updated contents. 87320- RunGoCommands(ctx context.Context, allowNetwork bool, wd string, run func(invoke func(...string) (*bytes.Buffer, error)) error) (bool, []byte, []byte, error) 87321- 87322- // RunProcessEnvFunc runs fn with the process env for this snapshot's view. 87323- // Note: the process env contains cached module and filesystem state. 87324- RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error 87325- 87326- // ModFiles are the go.mod files enclosed in the snapshot's view and known 87327- // to the snapshot. 87328- ModFiles() []span.URI 87329- 87330- // ParseMod is used to parse go.mod files. 87331- ParseMod(ctx context.Context, fh FileHandle) (*ParsedModule, error) 87332- 87333- // ModWhy returns the results of `go mod why` for the module specified by 87334- // the given go.mod file. 87335- ModWhy(ctx context.Context, fh FileHandle) (map[string]string, error) 87336- 87337- // ModTidy returns the results of `go mod tidy` for the module specified by 87338- // the given go.mod file. 87339- ModTidy(ctx context.Context, pm *ParsedModule) (*TidiedModule, error) 87340- 87341- // ModVuln returns import vulnerability analysis for the given go.mod URI. 87342- // Concurrent requests are combined into a single command. 87343- ModVuln(ctx context.Context, modURI span.URI) (*govulncheck.Result, error) 87344- 87345- // GoModForFile returns the URI of the go.mod file for the given URI. 87346- GoModForFile(uri span.URI) span.URI 87347- 87348- // WorkFile, if non-empty, is the go.work file for the workspace. 87349- WorkFile() span.URI 87350- 87351- // ParseWork is used to parse go.work files. 87352- ParseWork(ctx context.Context, fh FileHandle) (*ParsedWorkFile, error) 87353- 87354- // BuiltinFile returns information about the special builtin package. 87355- BuiltinFile(ctx context.Context) (*ParsedGoFile, error) 87356- 87357- // IsBuiltin reports whether uri is part of the builtin package. 87358- IsBuiltin(ctx context.Context, uri span.URI) bool 87359- 87360- // ReverseDependencies returns a new mapping whose entries are 87361- // the ID and Metadata of each package in the workspace that 87362- // directly or transitively depend on the package denoted by id, 87363- // excluding id itself. 87364- ReverseDependencies(ctx context.Context, id PackageID, transitive bool) (map[PackageID]*Metadata, error) 87365- 87366- // ActiveMetadata returns a new, unordered slice containing 87367- // metadata for all packages considered 'active' in the workspace. 87368- // 87369- // In normal memory mode, this is all workspace packages. In degraded memory 87370- // mode, this is just the reverse transitive closure of open packages. 87371- ActiveMetadata(ctx context.Context) ([]*Metadata, error) 87372- 87373- // AllMetadata returns a new unordered array of metadata for all packages in the workspace. 87374- AllMetadata(ctx context.Context) ([]*Metadata, error) 87375- 87376- // Symbols returns all symbols in the snapshot. 87377- Symbols(ctx context.Context) (map[span.URI][]Symbol, error) 87378- 87379- // Metadata returns the metadata for the specified package, 87380- // or nil if it was not found. 87381- Metadata(id PackageID) *Metadata 87382- 87383- // MetadataForFile returns a new slice containing metadata for each 87384- // package containing the Go file identified by uri, ordered by the 87385- // number of CompiledGoFiles (i.e. "narrowest" to "widest" package). 87386- // The result may include tests and intermediate test variants of 87387- // importable packages. 87388- // It returns an error if the context was cancelled. 87389- MetadataForFile(ctx context.Context, uri span.URI) ([]*Metadata, error) 87390- 87391- // TypeCheck parses and type-checks the specified packages, 87392- // and returns them in the same order as the ids. 87393- // The resulting packages' types may belong to different importers, 87394- // so types from different packages are incommensurable. 87395- TypeCheck(ctx context.Context, ids ...PackageID) ([]Package, error) 87396- 87397- // PackageDiagnostics returns diagnostics for files contained in specified 87398- // packages. 87399- // 87400- // If these diagnostics cannot be loaded from cache, the requested packages 87401- // may be type-checked. 87402- PackageDiagnostics(ctx context.Context, ids ...PackageID) (map[span.URI][]*Diagnostic, error) 87403- 87404- // References returns cross-references indexes for the specified packages. 87405- // 87406- // If these indexes cannot be loaded from cache, the requested packages may 87407- // be type-checked. 87408- References(ctx context.Context, ids ...PackageID) ([]XrefIndex, error) 87409- 87410- // MethodSets returns method-set indexes for the specified packages. 87411- // 87412- // If these indexes cannot be loaded from cache, the requested packages may 87413- // be type-checked. 87414- MethodSets(ctx context.Context, ids ...PackageID) ([]*methodsets.Index, error) 87415- 87416- // GetCriticalError returns any critical errors in the workspace. 87417- // 87418- // A nil result may mean success, or context cancellation. 87419- GetCriticalError(ctx context.Context) *CriticalError 87420-} 87421- 87422-type XrefIndex interface { 87423- Lookup(targets map[PackagePath]map[objectpath.Path]struct{}) (locs []protocol.Location) 87424-} 87425- 87426-// SnapshotLabels returns a new slice of labels that should be used for events 87427-// related to a snapshot. 87428-func SnapshotLabels(snapshot Snapshot) []label.Label { 87429- return []label.Label{tag.Snapshot.Of(snapshot.SequenceID()), tag.Directory.Of(snapshot.View().Folder())} 87430-} 87431- 87432-// PackageForFile is a convenience function that selects a package to 87433-// which this file belongs (narrowest or widest), type-checks it in 87434-// the requested mode (full or workspace), and returns it, along with 87435-// the parse tree of that file. 87436-// 87437-// Type-checking is expensive. Call snapshot.ParseGo if all you need 87438-// is a parse tree, or snapshot.MetadataForFile if you only need metadata. 87439-func PackageForFile(ctx context.Context, snapshot Snapshot, uri span.URI, pkgSel PackageSelector) (Package, *ParsedGoFile, error) { 87440- metas, err := snapshot.MetadataForFile(ctx, uri) 87441- if err != nil { 87442- return nil, nil, err 87443- } 87444- if len(metas) == 0 { 87445- return nil, nil, fmt.Errorf("no package metadata for file %s", uri) 87446- } 87447- switch pkgSel { 87448- case NarrowestPackage: 87449- metas = metas[:1] 87450- case WidestPackage: 87451- metas = metas[len(metas)-1:] 87452- } 87453- pkgs, err := snapshot.TypeCheck(ctx, metas[0].ID) 87454- if err != nil { 87455- return nil, nil, err 87456- } 87457- pkg := pkgs[0] 87458- pgf, err := pkg.File(uri) 87459- if err != nil { 87460- return nil, nil, err // "can't happen" 87461- } 87462- return pkg, pgf, err 87463-} 87464- 87465-// PackageSelector sets how a package is selected out from a set of packages 87466-// containing a given file. 87467-type PackageSelector int 87468- 87469-const ( 87470- // NarrowestPackage picks the "narrowest" package for a given file. 87471- // By "narrowest" package, we mean the package with the fewest number of 87472- // files that includes the given file. This solves the problem of test 87473- // variants, as the test will have more files than the non-test package. 87474- NarrowestPackage PackageSelector = iota 87475- 87476- // WidestPackage returns the Package containing the most files. 87477- // This is useful for something like diagnostics, where we'd prefer to 87478- // offer diagnostics for as many files as possible. 87479- WidestPackage 87480-) 87481- 87482-// InvocationFlags represents the settings of a particular go command invocation. 87483-// It is a mode, plus a set of flag bits. 87484-type InvocationFlags int 87485- 87486-const ( 87487- // Normal is appropriate for commands that might be run by a user and don't 87488- // deliberately modify go.mod files, e.g. `go test`. 87489- Normal InvocationFlags = iota 87490- // WriteTemporaryModFile is for commands that need information from a 87491- // modified version of the user's go.mod file, e.g. `go mod tidy` used to 87492- // generate diagnostics. 87493- WriteTemporaryModFile 87494- // LoadWorkspace is for packages.Load, and other operations that should 87495- // consider the whole workspace at once. 87496- LoadWorkspace 87497- 87498- // AllowNetwork is a flag bit that indicates the invocation should be 87499- // allowed to access the network. 87500- AllowNetwork InvocationFlags = 1 << 10 87501-) 87502- 87503-func (m InvocationFlags) Mode() InvocationFlags { 87504- return m & (AllowNetwork - 1) 87505-} 87506- 87507-func (m InvocationFlags) AllowNetwork() bool { 87508- return m&AllowNetwork != 0 87509-} 87510- 87511-// View represents a single workspace. 87512-// This is the level at which we maintain configuration like working directory 87513-// and build tags. 87514-type View interface { 87515- // Name returns the name this view was constructed with. 87516- Name() string 87517- 87518- // Folder returns the folder with which this view was created. 87519- Folder() span.URI 87520- 87521- // Options returns a copy of the Options for this view. 87522- Options() *Options 87523- 87524- // Snapshot returns the current snapshot for the view, and a 87525- // release function that must be called when the Snapshot is 87526- // no longer needed. 87527- // 87528- // If the view is shut down, the resulting error will be non-nil, and the 87529- // release function need not be called. 87530- Snapshot() (Snapshot, func(), error) 87531- 87532- // IsGoPrivatePath reports whether target is a private import path, as identified 87533- // by the GOPRIVATE environment variable. 87534- IsGoPrivatePath(path string) bool 87535- 87536- // ModuleUpgrades returns known module upgrades for the dependencies of 87537- // modfile. 87538- ModuleUpgrades(modfile span.URI) map[string]string 87539- 87540- // RegisterModuleUpgrades registers that upgrades exist for the given modules 87541- // required by modfile. 87542- RegisterModuleUpgrades(modfile span.URI, upgrades map[string]string) 87543- 87544- // ClearModuleUpgrades clears all upgrades for the modules in modfile. 87545- ClearModuleUpgrades(modfile span.URI) 87546- 87547- // Vulnerabilities returns known vulnerabilities for the given modfile. 87548- // TODO(suzmue): replace command.Vuln with a different type, maybe 87549- // https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck/govulnchecklib#Summary? 87550- Vulnerabilities(modfile ...span.URI) map[span.URI]*govulncheck.Result 87551- 87552- // SetVulnerabilities resets the list of vulnerabilities that exists for the given modules 87553- // required by modfile. 87554- SetVulnerabilities(modfile span.URI, vulncheckResult *govulncheck.Result) 87555- 87556- // FileKind returns the type of a file. 87557- // 87558- // We can't reliably deduce the kind from the file name alone, 87559- // as some editors can be told to interpret a buffer as 87560- // language different from the file name heuristic, e.g. that 87561- // an .html file actually contains Go "html/template" syntax, 87562- // or even that a .go file contains Python. 87563- FileKind(FileHandle) FileKind 87564- 87565- // GoVersion returns the configured Go version for this view. 87566- GoVersion() int 87567- 87568- // GoVersionString returns the go version string configured for this view. 87569- // Unlike [GoVersion], this encodes the minor version and commit hash information. 87570- GoVersionString() string 87571-} 87572- 87573-// A FileSource maps uris to FileHandles. 87574-type FileSource interface { 87575- // GetFile returns the FileHandle for a given URI. 87576- GetFile(ctx context.Context, uri span.URI) (FileHandle, error) 87577-} 87578- 87579-// A MetadataSource maps package IDs to metadata. 87580-// 87581-// TODO(rfindley): replace this with a concrete metadata graph, once it is 87582-// exposed from the snapshot. 87583-type MetadataSource interface { 87584- // Metadata returns Metadata for the given package ID, or nil if it does not 87585- // exist. 87586- Metadata(PackageID) *Metadata 87587-} 87588- 87589-// A ParsedGoFile contains the results of parsing a Go file. 87590-type ParsedGoFile struct { 87591- URI span.URI 87592- Mode ParseMode 87593- File *ast.File 87594- Tok *token.File 87595- // Source code used to build the AST. It may be different from the 87596- // actual content of the file if we have fixed the AST. 87597- Src []byte 87598- Fixed bool 87599- Mapper *protocol.Mapper // may map fixed Src, not file content 87600- ParseErr scanner.ErrorList 87601-} 87602- 87603-// -- go/token domain convenience helpers -- 87604- 87605-// PositionPos returns the token.Pos of protocol position p within the file. 87606-func (pgf *ParsedGoFile) PositionPos(p protocol.Position) (token.Pos, error) { 87607- offset, err := pgf.Mapper.PositionOffset(p) 87608- if err != nil { 87609- return token.NoPos, err 87610- } 87611- return safetoken.Pos(pgf.Tok, offset) 87612-} 87613- 87614-// PosRange returns a protocol Range for the token.Pos interval in this file. 87615-func (pgf *ParsedGoFile) PosRange(start, end token.Pos) (protocol.Range, error) { 87616- return pgf.Mapper.PosRange(pgf.Tok, start, end) 87617-} 87618- 87619-// PosMappedRange returns a MappedRange for the token.Pos interval in this file. 87620-// A MappedRange can be converted to any other form. 87621-func (pgf *ParsedGoFile) PosMappedRange(start, end token.Pos) (protocol.MappedRange, error) { 87622- return pgf.Mapper.PosMappedRange(pgf.Tok, start, end) 87623-} 87624- 87625-// PosLocation returns a protocol Location for the token.Pos interval in this file. 87626-func (pgf *ParsedGoFile) PosLocation(start, end token.Pos) (protocol.Location, error) { 87627- return pgf.Mapper.PosLocation(pgf.Tok, start, end) 87628-} 87629- 87630-// NodeRange returns a protocol Range for the ast.Node interval in this file. 87631-func (pgf *ParsedGoFile) NodeRange(node ast.Node) (protocol.Range, error) { 87632- return pgf.Mapper.NodeRange(pgf.Tok, node) 87633-} 87634- 87635-// NodeMappedRange returns a MappedRange for the ast.Node interval in this file. 87636-// A MappedRange can be converted to any other form. 87637-func (pgf *ParsedGoFile) NodeMappedRange(node ast.Node) (protocol.MappedRange, error) { 87638- return pgf.Mapper.NodeMappedRange(pgf.Tok, node) 87639-} 87640- 87641-// NodeLocation returns a protocol Location for the ast.Node interval in this file. 87642-func (pgf *ParsedGoFile) NodeLocation(node ast.Node) (protocol.Location, error) { 87643- return pgf.Mapper.PosLocation(pgf.Tok, node.Pos(), node.End()) 87644-} 87645- 87646-// RangePos parses a protocol Range back into the go/token domain. 87647-func (pgf *ParsedGoFile) RangePos(r protocol.Range) (token.Pos, token.Pos, error) { 87648- start, end, err := pgf.Mapper.RangeOffsets(r) 87649- if err != nil { 87650- return token.NoPos, token.NoPos, err 87651- } 87652- return pgf.Tok.Pos(start), pgf.Tok.Pos(end), nil 87653-} 87654- 87655-// A ParsedModule contains the results of parsing a go.mod file. 87656-type ParsedModule struct { 87657- URI span.URI 87658- File *modfile.File 87659- Mapper *protocol.Mapper 87660- ParseErrors []*Diagnostic 87661-} 87662- 87663-// A ParsedWorkFile contains the results of parsing a go.work file. 87664-type ParsedWorkFile struct { 87665- URI span.URI 87666- File *modfile.WorkFile 87667- Mapper *protocol.Mapper 87668- ParseErrors []*Diagnostic 87669-} 87670- 87671-// A TidiedModule contains the results of running `go mod tidy` on a module. 87672-type TidiedModule struct { 87673- // Diagnostics representing changes made by `go mod tidy`. 87674- Diagnostics []*Diagnostic 87675- // The bytes of the go.mod file after it was tidied. 87676- TidiedContent []byte 87677-} 87678- 87679-// Metadata represents package metadata retrieved from go/packages. 87680-type Metadata struct { 87681- ID PackageID 87682- PkgPath PackagePath 87683- Name PackageName 87684- GoFiles []span.URI 87685- CompiledGoFiles []span.URI 87686- ForTest PackagePath // package path under test, or "" 87687- TypesSizes types.Sizes 87688- Errors []packages.Error 87689- DepsByImpPath map[ImportPath]PackageID // may contain dups; empty ID => missing 87690- DepsByPkgPath map[PackagePath]PackageID // values are unique and non-empty 87691- Module *packages.Module 87692- DepsErrors []*packagesinternal.PackageError 87693- Diagnostics []*Diagnostic // processed diagnostics from 'go list' 87694- LoadDir string // directory from which go/packages was run 87695-} 87696- 87697-func (m *Metadata) String() string { return string(m.ID) } 87698- 87699-// IsIntermediateTestVariant reports whether the given package is an 87700-// intermediate test variant, e.g. "net/http [net/url.test]". 87701-// 87702-// Such test variants arise when an x_test package (in this case net/url_test) 87703-// imports a package (in this case net/http) that itself imports the the 87704-// non-x_test package (in this case net/url). 87705-// 87706-// This is done so that the forward transitive closure of net/url_test has 87707-// only one package for the "net/url" import. 87708-// The intermediate test variant exists to hold the test variant import: 87709-// 87710-// net/url_test [net/url.test] 87711-// 87712-// | "net/http" -> net/http [net/url.test] 87713-// | "net/url" -> net/url [net/url.test] 87714-// | ... 87715-// 87716-// net/http [net/url.test] 87717-// 87718-// | "net/url" -> net/url [net/url.test] 87719-// | ... 87720-// 87721-// This restriction propagates throughout the import graph of net/http: for 87722-// every package imported by net/http that imports net/url, there must be an 87723-// intermediate test variant that instead imports "net/url [net/url.test]". 87724-// 87725-// As one can see from the example of net/url and net/http, intermediate test 87726-// variants can result in many additional packages that are essentially (but 87727-// not quite) identical. For this reason, we filter these variants wherever 87728-// possible. 87729-func (m *Metadata) IsIntermediateTestVariant() bool { 87730- return m.ForTest != "" && m.ForTest != m.PkgPath && m.ForTest+"_test" != m.PkgPath 87731-} 87732- 87733-// RemoveIntermediateTestVariants removes intermediate test variants, modifying the array. 87734-func RemoveIntermediateTestVariants(metas []*Metadata) []*Metadata { 87735- res := metas[:0] 87736- for _, m := range metas { 87737- if !m.IsIntermediateTestVariant() { 87738- res = append(res, m) 87739- } 87740- } 87741- return res 87742-} 87743- 87744-var ErrViewExists = errors.New("view already exists for session") 87745- 87746-// FileModification represents a modification to a file. 87747-type FileModification struct { 87748- URI span.URI 87749- Action FileAction 87750- 87751- // OnDisk is true if a watched file is changed on disk. 87752- // If true, Version will be -1 and Text will be nil. 87753- OnDisk bool 87754- 87755- // Version will be -1 and Text will be nil when they are not supplied, 87756- // specifically on textDocument/didClose and for on-disk changes. 87757- Version int32 87758- Text []byte 87759- 87760- // LanguageID is only sent from the language client on textDocument/didOpen. 87761- LanguageID string 87762-} 87763- 87764-type FileAction int 87765- 87766-const ( 87767- UnknownFileAction = FileAction(iota) 87768- Open 87769- Change 87770- Close 87771- Save 87772- Create 87773- Delete 87774- InvalidateMetadata 87775-) 87776- 87777-func (a FileAction) String() string { 87778- switch a { 87779- case Open: 87780- return "Open" 87781- case Change: 87782- return "Change" 87783- case Close: 87784- return "Close" 87785- case Save: 87786- return "Save" 87787- case Create: 87788- return "Create" 87789- case Delete: 87790- return "Delete" 87791- case InvalidateMetadata: 87792- return "InvalidateMetadata" 87793- default: 87794- return "Unknown" 87795- } 87796-} 87797- 87798-var ErrTmpModfileUnsupported = errors.New("-modfile is unsupported for this Go version") 87799-var ErrNoModOnDisk = errors.New("go.mod file is not on disk") 87800- 87801-func IsNonFatalGoModError(err error) bool { 87802- return err == ErrTmpModfileUnsupported || err == ErrNoModOnDisk 87803-} 87804- 87805-// ParseMode controls the content of the AST produced when parsing a source file. 87806-type ParseMode int 87807- 87808-const ( 87809- // ParseHeader specifies that the main package declaration and imports are needed. 87810- // This is the mode used when attempting to examine the package graph structure. 87811- ParseHeader ParseMode = iota 87812- 87813- // ParseFull specifies the full AST is needed. 87814- // This is used for files of direct interest where the entire contents must 87815- // be considered. 87816- ParseFull 87817-) 87818- 87819-// A FileHandle is an interface to files tracked by the LSP session, which may 87820-// be either files read from disk, or open in the editor session (overlays). 87821-type FileHandle interface { 87822- // URI is the URI for this file handle. 87823- // TODO(rfindley): this is not actually well-defined. In some cases, there 87824- // may be more than one URI that resolve to the same FileHandle. Which one is 87825- // this? 87826- URI() span.URI 87827- // FileIdentity returns a FileIdentity for the file, even if there was an 87828- // error reading it. 87829- FileIdentity() FileIdentity 87830- // Saved reports whether the file has the same content on disk. 87831- // For on-disk files, this is trivially true. 87832- Saved() bool 87833- // Version returns the file version, as defined by the LSP client. 87834- // For on-disk file handles, Version returns 0. 87835- Version() int32 87836- // Read reads the contents of a file. 87837- // If the file is not available, returns a nil slice and an error. 87838- Read() ([]byte, error) 87839-} 87840- 87841-// A Hash is a cryptographic digest of the contents of a file. 87842-// (Although at 32B it is larger than a 16B string header, it is smaller 87843-// and has better locality than the string header + 64B of hex digits.) 87844-type Hash [sha256.Size]byte 87845- 87846-// HashOf returns the hash of some data. 87847-func HashOf(data []byte) Hash { 87848- return Hash(sha256.Sum256(data)) 87849-} 87850- 87851-// Hashf returns the hash of a printf-formatted string. 87852-func Hashf(format string, args ...interface{}) Hash { 87853- // Although this looks alloc-heavy, it is faster than using 87854- // Fprintf on sha256.New() because the allocations don't escape. 87855- return HashOf([]byte(fmt.Sprintf(format, args...))) 87856-} 87857- 87858-// String returns the digest as a string of hex digits. 87859-func (h Hash) String() string { 87860- return fmt.Sprintf("%64x", [sha256.Size]byte(h)) 87861-} 87862- 87863-// Less returns true if the given hash is less than the other. 87864-func (h Hash) Less(other Hash) bool { 87865- return bytes.Compare(h[:], other[:]) < 0 87866-} 87867- 87868-// XORWith updates *h to *h XOR h2. 87869-func (h *Hash) XORWith(h2 Hash) { 87870- // Small enough that we don't need crypto/subtle.XORBytes. 87871- for i := range h { 87872- h[i] ^= h2[i] 87873- } 87874-} 87875- 87876-// FileIdentity uniquely identifies a file at a version from a FileSystem. 87877-type FileIdentity struct { 87878- URI span.URI 87879- Hash Hash // digest of file contents 87880-} 87881- 87882-func (id FileIdentity) String() string { 87883- return fmt.Sprintf("%s%s", id.URI, id.Hash) 87884-} 87885- 87886-// FileKind describes the kind of the file in question. 87887-// It can be one of Go,mod, Sum, or Tmpl. 87888-type FileKind int 87889- 87890-const ( 87891- // UnknownKind is a file type we don't know about. 87892- UnknownKind = FileKind(iota) 87893- 87894- // Go is a normal go source file. 87895- Go 87896- // Mod is a go.mod file. 87897- Mod 87898- // Sum is a go.sum file. 87899- Sum 87900- // Tmpl is a template file. 87901- Tmpl 87902- // Work is a go.work file. 87903- Work 87904-) 87905- 87906-func (k FileKind) String() string { 87907- switch k { 87908- case Go: 87909- return "go" 87910- case Mod: 87911- return "go.mod" 87912- case Sum: 87913- return "go.sum" 87914- case Tmpl: 87915- return "tmpl" 87916- case Work: 87917- return "go.work" 87918- default: 87919- return fmt.Sprintf("internal error: unknown file kind %d", k) 87920- } 87921-} 87922- 87923-// Analyzer represents a go/analysis analyzer with some boolean properties 87924-// that let the user know how to use the analyzer. 87925-type Analyzer struct { 87926- Analyzer *analysis.Analyzer 87927- 87928- // Enabled reports whether the analyzer is enabled. This value can be 87929- // configured per-analysis in user settings. For staticcheck analyzers, 87930- // the value of the Staticcheck setting overrides this field. 87931- // 87932- // Most clients should use the IsEnabled method. 87933- Enabled bool 87934- 87935- // Fix is the name of the suggested fix name used to invoke the suggested 87936- // fixes for the analyzer. It is non-empty if we expect this analyzer to 87937- // provide its fix separately from its diagnostics. That is, we should apply 87938- // the analyzer's suggested fixes through a Command, not a TextEdit. 87939- Fix string 87940- 87941- // ActionKind is the kind of code action this analyzer produces. If 87942- // unspecified the type defaults to quickfix. 87943- ActionKind []protocol.CodeActionKind 87944- 87945- // Severity is the severity set for diagnostics reported by this 87946- // analyzer. If left unset it defaults to Warning. 87947- Severity protocol.DiagnosticSeverity 87948-} 87949- 87950-func (a *Analyzer) String() string { return a.Analyzer.String() } 87951- 87952-// IsEnabled reports whether this analyzer is enabled by the given options. 87953-func (a Analyzer) IsEnabled(options *Options) bool { 87954- // Staticcheck analyzers can only be enabled when staticcheck is on. 87955- if _, ok := options.StaticcheckAnalyzers[a.Analyzer.Name]; ok { 87956- if !options.Staticcheck { 87957- return false 87958- } 87959- } 87960- if enabled, ok := options.Analyses[a.Analyzer.Name]; ok { 87961- return enabled 87962- } 87963- return a.Enabled 87964-} 87965- 87966-// Declare explicit types for package paths, names, and IDs to ensure that we 87967-// never use an ID where a path belongs, and vice versa. If we confused these, 87968-// it would result in confusing errors because package IDs often look like 87969-// package paths. 87970-type ( 87971- PackageID string // go list's unique identifier for a package (e.g. "vendor/example.com/foo [vendor/example.com/bar.test]") 87972- PackagePath string // name used to prefix linker symbols (e.g. "vendor/example.com/foo") 87973- PackageName string // identifier in 'package' declaration (e.g. "foo") 87974- ImportPath string // path that appears in an import declaration (e.g. "example.com/foo") 87975-) 87976- 87977-// Package represents a Go package that has been parsed and type-checked. 87978-// 87979-// By design, there is no way to reach from a Package to the Package 87980-// representing one of its dependencies. 87981-// 87982-// Callers must not assume that two Packages share the same 87983-// token.FileSet or types.Importer and thus have commensurable 87984-// token.Pos values or types.Objects. Instead, use stable naming 87985-// schemes, such as (URI, byte offset) for positions, or (PackagePath, 87986-// objectpath.Path) for exported declarations. 87987-type Package interface { 87988- Metadata() *Metadata 87989- 87990- // Results of parsing: 87991- FileSet() *token.FileSet 87992- ParseMode() ParseMode 87993- CompiledGoFiles() []*ParsedGoFile // (borrowed) 87994- File(uri span.URI) (*ParsedGoFile, error) 87995- GetSyntax() []*ast.File // (borrowed) 87996- HasParseErrors() bool 87997- 87998- // Results of type checking: 87999- GetTypes() *types.Package 88000- GetTypesInfo() *types.Info 88001- DependencyTypes(PackagePath) *types.Package // nil for indirect dependency of no consequence 88002- HasTypeErrors() bool 88003- DiagnosticsForFile(ctx context.Context, s Snapshot, uri span.URI) ([]*Diagnostic, error) 88004-} 88005- 88006-type unit = struct{} 88007- 88008-// A CriticalError is a workspace-wide error that generally prevents gopls from 88009-// functioning correctly. In the presence of critical errors, other diagnostics 88010-// in the workspace may not make sense. 88011-type CriticalError struct { 88012- // MainError is the primary error. Must be non-nil. 88013- MainError error 88014- 88015- // Diagnostics contains any supplemental (structured) diagnostics. 88016- Diagnostics []*Diagnostic 88017-} 88018- 88019-// An Diagnostic corresponds to an LSP Diagnostic. 88020-// https://microsoft.github.io/language-server-protocol/specification#diagnostic 88021-type Diagnostic struct { 88022- URI span.URI 88023- Range protocol.Range 88024- Severity protocol.DiagnosticSeverity 88025- Code string 88026- CodeHref string 88027- 88028- // Source is a human-readable description of the source of the error. 88029- // Diagnostics generated by an analysis.Analyzer set it to Analyzer.Name. 88030- Source DiagnosticSource 88031- 88032- Message string 88033- 88034- Tags []protocol.DiagnosticTag 88035- Related []protocol.DiagnosticRelatedInformation 88036- 88037- // Fields below are used internally to generate quick fixes. They aren't 88038- // part of the LSP spec and don't leave the server. 88039- SuggestedFixes []SuggestedFix 88040-} 88041- 88042-func (d *Diagnostic) String() string { 88043- return fmt.Sprintf("%v: %s", d.Range, d.Message) 88044-} 88045- 88046-type DiagnosticSource string 88047- 88048-const ( 88049- UnknownError DiagnosticSource = "<Unknown source>" 88050- ListError DiagnosticSource = "go list" 88051- ParseError DiagnosticSource = "syntax" 88052- TypeError DiagnosticSource = "compiler" 88053- ModTidyError DiagnosticSource = "go mod tidy" 88054- OptimizationDetailsError DiagnosticSource = "optimizer details" 88055- UpgradeNotification DiagnosticSource = "upgrade available" 88056- Vulncheck DiagnosticSource = "vulncheck imports" 88057- Govulncheck DiagnosticSource = "govulncheck" 88058- TemplateError DiagnosticSource = "template" 88059- WorkFileError DiagnosticSource = "go.work file" 88060-) 88061- 88062-func AnalyzerErrorKind(name string) DiagnosticSource { 88063- return DiagnosticSource(name) 88064-} 88065diff -urN a/gopls/internal/lsp/source/workspace_symbol.go b/gopls/internal/lsp/source/workspace_symbol.go 88066--- a/gopls/internal/lsp/source/workspace_symbol.go 2000-01-01 00:00:00.000000000 -0000 88067+++ b/gopls/internal/lsp/source/workspace_symbol.go 1970-01-01 00:00:00.000000000 +0000 88068@@ -1,632 +0,0 @@ 88069-// Copyright 2020 The Go Authors. All rights reserved. 88070-// Use of this source code is governed by a BSD-style 88071-// license that can be found in the LICENSE file. 88072- 88073-package source 88074- 88075-import ( 88076- "context" 88077- "fmt" 88078- "go/types" 88079- "path" 88080- "path/filepath" 88081- "regexp" 88082- "runtime" 88083- "sort" 88084- "strings" 88085- "unicode" 88086- 88087- "golang.org/x/tools/gopls/internal/lsp/protocol" 88088- "golang.org/x/tools/gopls/internal/span" 88089- "golang.org/x/tools/internal/event" 88090- "golang.org/x/tools/internal/fuzzy" 88091-) 88092- 88093-// Symbol holds a precomputed symbol value. Note: we avoid using the 88094-// protocol.SymbolInformation struct here in order to reduce the size of each 88095-// symbol. 88096-type Symbol struct { 88097- Name string 88098- Kind protocol.SymbolKind 88099- Range protocol.Range 88100-} 88101- 88102-// maxSymbols defines the maximum number of symbol results that should ever be 88103-// sent in response to a client. 88104-const maxSymbols = 100 88105- 88106-// WorkspaceSymbols matches symbols across all views using the given query, 88107-// according to the match semantics parameterized by matcherType and style. 88108-// 88109-// The workspace symbol method is defined in the spec as follows: 88110-// 88111-// The workspace symbol request is sent from the client to the server to 88112-// list project-wide symbols matching the query string. 88113-// 88114-// It is unclear what "project-wide" means here, but given the parameters of 88115-// workspace/symbol do not include any workspace identifier, then it has to be 88116-// assumed that "project-wide" means "across all workspaces". Hence why 88117-// WorkspaceSymbols receives the views []View. 88118-// 88119-// However, it then becomes unclear what it would mean to call WorkspaceSymbols 88120-// with a different configured SymbolMatcher per View. Therefore we assume that 88121-// Session level configuration will define the SymbolMatcher to be used for the 88122-// WorkspaceSymbols method. 88123-func WorkspaceSymbols(ctx context.Context, matcher SymbolMatcher, style SymbolStyle, views []View, query string) ([]protocol.SymbolInformation, error) { 88124- ctx, done := event.Start(ctx, "source.WorkspaceSymbols") 88125- defer done() 88126- if query == "" { 88127- return nil, nil 88128- } 88129- 88130- var s symbolizer 88131- switch style { 88132- case DynamicSymbols: 88133- s = dynamicSymbolMatch 88134- case FullyQualifiedSymbols: 88135- s = fullyQualifiedSymbolMatch 88136- case PackageQualifiedSymbols: 88137- s = packageSymbolMatch 88138- default: 88139- panic(fmt.Errorf("unknown symbol style: %v", style)) 88140- } 88141- 88142- return collectSymbols(ctx, views, matcher, s, query) 88143-} 88144- 88145-// A matcherFunc returns the index and score of a symbol match. 88146-// 88147-// See the comment for symbolCollector for more information. 88148-type matcherFunc func(chunks []string) (int, float64) 88149- 88150-// A symbolizer returns the best symbol match for a name with pkg, according to 88151-// some heuristic. The symbol name is passed as the slice nameParts of logical 88152-// name pieces. For example, for myType.field the caller can pass either 88153-// []string{"myType.field"} or []string{"myType.", "field"}. 88154-// 88155-// See the comment for symbolCollector for more information. 88156-// 88157-// The space argument is an empty slice with spare capacity that may be used 88158-// to allocate the result. 88159-type symbolizer func(space []string, name string, pkg *Metadata, m matcherFunc) ([]string, float64) 88160- 88161-func fullyQualifiedSymbolMatch(space []string, name string, pkg *Metadata, matcher matcherFunc) ([]string, float64) { 88162- if _, score := dynamicSymbolMatch(space, name, pkg, matcher); score > 0 { 88163- return append(space, string(pkg.PkgPath), ".", name), score 88164- } 88165- return nil, 0 88166-} 88167- 88168-func dynamicSymbolMatch(space []string, name string, pkg *Metadata, matcher matcherFunc) ([]string, float64) { 88169- if IsCommandLineArguments(pkg.ID) { 88170- // command-line-arguments packages have a non-sensical package path, so 88171- // just use their package name. 88172- return packageSymbolMatch(space, name, pkg, matcher) 88173- } 88174- 88175- var score float64 88176- 88177- endsInPkgName := strings.HasSuffix(string(pkg.PkgPath), string(pkg.Name)) 88178- 88179- // If the package path does not end in the package name, we need to check the 88180- // package-qualified symbol as an extra pass first. 88181- if !endsInPkgName { 88182- pkgQualified := append(space, string(pkg.Name), ".", name) 88183- idx, score := matcher(pkgQualified) 88184- nameStart := len(pkg.Name) + 1 88185- if score > 0 { 88186- // If our match is contained entirely within the unqualified portion, 88187- // just return that. 88188- if idx >= nameStart { 88189- return append(space, name), score 88190- } 88191- // Lower the score for matches that include the package name. 88192- return pkgQualified, score * 0.8 88193- } 88194- } 88195- 88196- // Now try matching the fully qualified symbol. 88197- fullyQualified := append(space, string(pkg.PkgPath), ".", name) 88198- idx, score := matcher(fullyQualified) 88199- 88200- // As above, check if we matched just the unqualified symbol name. 88201- nameStart := len(pkg.PkgPath) + 1 88202- if idx >= nameStart { 88203- return append(space, name), score 88204- } 88205- 88206- // If our package path ends in the package name, we'll have skipped the 88207- // initial pass above, so check if we matched just the package-qualified 88208- // name. 88209- if endsInPkgName && idx >= 0 { 88210- pkgStart := len(pkg.PkgPath) - len(pkg.Name) 88211- if idx >= pkgStart { 88212- return append(space, string(pkg.Name), ".", name), score 88213- } 88214- } 88215- 88216- // Our match was not contained within the unqualified or package qualified 88217- // symbol. Return the fully qualified symbol but discount the score. 88218- return fullyQualified, score * 0.6 88219-} 88220- 88221-func packageSymbolMatch(space []string, name string, pkg *Metadata, matcher matcherFunc) ([]string, float64) { 88222- qualified := append(space, string(pkg.Name), ".", name) 88223- if _, s := matcher(qualified); s > 0 { 88224- return qualified, s 88225- } 88226- return nil, 0 88227-} 88228- 88229-func buildMatcher(matcher SymbolMatcher, query string) matcherFunc { 88230- switch matcher { 88231- case SymbolFuzzy: 88232- return parseQuery(query, newFuzzyMatcher) 88233- case SymbolFastFuzzy: 88234- return parseQuery(query, func(query string) matcherFunc { 88235- return fuzzy.NewSymbolMatcher(query).Match 88236- }) 88237- case SymbolCaseSensitive: 88238- return matchExact(query) 88239- case SymbolCaseInsensitive: 88240- q := strings.ToLower(query) 88241- exact := matchExact(q) 88242- wrapper := []string{""} 88243- return func(chunks []string) (int, float64) { 88244- s := strings.Join(chunks, "") 88245- wrapper[0] = strings.ToLower(s) 88246- return exact(wrapper) 88247- } 88248- } 88249- panic(fmt.Errorf("unknown symbol matcher: %v", matcher)) 88250-} 88251- 88252-func newFuzzyMatcher(query string) matcherFunc { 88253- fm := fuzzy.NewMatcher(query) 88254- return func(chunks []string) (int, float64) { 88255- score := float64(fm.ScoreChunks(chunks)) 88256- ranges := fm.MatchedRanges() 88257- if len(ranges) > 0 { 88258- return ranges[0], score 88259- } 88260- return -1, score 88261- } 88262-} 88263- 88264-// parseQuery parses a field-separated symbol query, extracting the special 88265-// characters listed below, and returns a matcherFunc corresponding to the AND 88266-// of all field queries. 88267-// 88268-// Special characters: 88269-// 88270-// ^ match exact prefix 88271-// $ match exact suffix 88272-// ' match exact 88273-// 88274-// In all three of these special queries, matches are 'smart-cased', meaning 88275-// they are case sensitive if the symbol query contains any upper-case 88276-// characters, and case insensitive otherwise. 88277-func parseQuery(q string, newMatcher func(string) matcherFunc) matcherFunc { 88278- fields := strings.Fields(q) 88279- if len(fields) == 0 { 88280- return func([]string) (int, float64) { return -1, 0 } 88281- } 88282- var funcs []matcherFunc 88283- for _, field := range fields { 88284- var f matcherFunc 88285- switch { 88286- case strings.HasPrefix(field, "^"): 88287- prefix := field[1:] 88288- f = smartCase(prefix, func(chunks []string) (int, float64) { 88289- s := strings.Join(chunks, "") 88290- if strings.HasPrefix(s, prefix) { 88291- return 0, 1 88292- } 88293- return -1, 0 88294- }) 88295- case strings.HasPrefix(field, "'"): 88296- exact := field[1:] 88297- f = smartCase(exact, matchExact(exact)) 88298- case strings.HasSuffix(field, "$"): 88299- suffix := field[0 : len(field)-1] 88300- f = smartCase(suffix, func(chunks []string) (int, float64) { 88301- s := strings.Join(chunks, "") 88302- if strings.HasSuffix(s, suffix) { 88303- return len(s) - len(suffix), 1 88304- } 88305- return -1, 0 88306- }) 88307- default: 88308- f = newMatcher(field) 88309- } 88310- funcs = append(funcs, f) 88311- } 88312- if len(funcs) == 1 { 88313- return funcs[0] 88314- } 88315- return comboMatcher(funcs).match 88316-} 88317- 88318-func matchExact(exact string) matcherFunc { 88319- return func(chunks []string) (int, float64) { 88320- s := strings.Join(chunks, "") 88321- if idx := strings.LastIndex(s, exact); idx >= 0 { 88322- return idx, 1 88323- } 88324- return -1, 0 88325- } 88326-} 88327- 88328-// smartCase returns a matcherFunc that is case-sensitive if q contains any 88329-// upper-case characters, and case-insensitive otherwise. 88330-func smartCase(q string, m matcherFunc) matcherFunc { 88331- insensitive := strings.ToLower(q) == q 88332- wrapper := []string{""} 88333- return func(chunks []string) (int, float64) { 88334- s := strings.Join(chunks, "") 88335- if insensitive { 88336- s = strings.ToLower(s) 88337- } 88338- wrapper[0] = s 88339- return m(wrapper) 88340- } 88341-} 88342- 88343-type comboMatcher []matcherFunc 88344- 88345-func (c comboMatcher) match(chunks []string) (int, float64) { 88346- score := 1.0 88347- first := 0 88348- for _, f := range c { 88349- idx, s := f(chunks) 88350- if idx < first { 88351- first = idx 88352- } 88353- score *= s 88354- } 88355- return first, score 88356-} 88357- 88358-// collectSymbols calls snapshot.Symbols to walk the syntax trees of 88359-// all files in the views' current snapshots, and returns a sorted, 88360-// scored list of symbols that best match the parameters. 88361-// 88362-// How it matches symbols is parameterized by two interfaces: 88363-// - A matcherFunc determines how well a string symbol matches a query. It 88364-// returns a non-negative score indicating the quality of the match. A score 88365-// of zero indicates no match. 88366-// - A symbolizer determines how we extract the symbol for an object. This 88367-// enables the 'symbolStyle' configuration option. 88368-func collectSymbols(ctx context.Context, views []View, matcherType SymbolMatcher, symbolizer symbolizer, query string) ([]protocol.SymbolInformation, error) { 88369- // Extract symbols from all files. 88370- var work []symbolFile 88371- var roots []string 88372- seen := make(map[span.URI]bool) 88373- // TODO(adonovan): opt: parallelize this loop? How often is len > 1? 88374- for _, v := range views { 88375- snapshot, release, err := v.Snapshot() 88376- if err != nil { 88377- continue // view is shut down; continue with others 88378- } 88379- defer release() 88380- 88381- // Use the root view URIs for determining (lexically) 88382- // whether a URI is in any open workspace. 88383- roots = append(roots, strings.TrimRight(string(v.Folder()), "/")) 88384- 88385- filters := v.Options().DirectoryFilters 88386- filterer := NewFilterer(filters) 88387- folder := filepath.ToSlash(v.Folder().Filename()) 88388- symbols, err := snapshot.Symbols(ctx) 88389- if err != nil { 88390- return nil, err 88391- } 88392- for uri, syms := range symbols { 88393- norm := filepath.ToSlash(uri.Filename()) 88394- nm := strings.TrimPrefix(norm, folder) 88395- if filterer.Disallow(nm) { 88396- continue 88397- } 88398- // Only scan each file once. 88399- if seen[uri] { 88400- continue 88401- } 88402- mds, err := snapshot.MetadataForFile(ctx, uri) 88403- if err != nil { 88404- event.Error(ctx, fmt.Sprintf("missing metadata for %q", uri), err) 88405- continue 88406- } 88407- if len(mds) == 0 { 88408- // TODO: should use the bug reporting API 88409- continue 88410- } 88411- seen[uri] = true 88412- work = append(work, symbolFile{uri, mds[0], syms}) 88413- } 88414- } 88415- 88416- // Match symbols in parallel. 88417- // Each worker has its own symbolStore, 88418- // which we merge at the end. 88419- nmatchers := runtime.GOMAXPROCS(-1) // matching is CPU bound 88420- results := make(chan *symbolStore) 88421- for i := 0; i < nmatchers; i++ { 88422- go func(i int) { 88423- matcher := buildMatcher(matcherType, query) 88424- store := new(symbolStore) 88425- // Assign files to workers in round-robin fashion. 88426- for j := i; j < len(work); j += nmatchers { 88427- matchFile(store, symbolizer, matcher, roots, work[j]) 88428- } 88429- results <- store 88430- }(i) 88431- } 88432- 88433- // Gather and merge results as they arrive. 88434- var unified symbolStore 88435- for i := 0; i < nmatchers; i++ { 88436- store := <-results 88437- for _, syms := range store.res { 88438- unified.store(syms) 88439- } 88440- } 88441- return unified.results(), nil 88442-} 88443- 88444-type Filterer struct { 88445- // Whether a filter is excluded depends on the operator (first char of the raw filter). 88446- // Slices filters and excluded then should have the same length. 88447- filters []*regexp.Regexp 88448- excluded []bool 88449-} 88450- 88451-// NewFilterer computes regular expression form of all raw filters 88452-func NewFilterer(rawFilters []string) *Filterer { 88453- var f Filterer 88454- for _, filter := range rawFilters { 88455- filter = path.Clean(filepath.ToSlash(filter)) 88456- // TODO(dungtuanle): fix: validate [+-] prefix. 88457- op, prefix := filter[0], filter[1:] 88458- // convertFilterToRegexp adds "/" at the end of prefix to handle cases where a filter is a prefix of another filter. 88459- // For example, it prevents [+foobar, -foo] from excluding "foobar". 88460- f.filters = append(f.filters, convertFilterToRegexp(filepath.ToSlash(prefix))) 88461- f.excluded = append(f.excluded, op == '-') 88462- } 88463- 88464- return &f 88465-} 88466- 88467-// Disallow return true if the path is excluded from the filterer's filters. 88468-func (f *Filterer) Disallow(path string) bool { 88469- // Ensure trailing but not leading slash. 88470- path = strings.TrimPrefix(path, "/") 88471- if !strings.HasSuffix(path, "/") { 88472- path += "/" 88473- } 88474- 88475- // TODO(adonovan): opt: iterate in reverse and break at first match. 88476- excluded := false 88477- for i, filter := range f.filters { 88478- if filter.MatchString(path) { 88479- excluded = f.excluded[i] // last match wins 88480- } 88481- } 88482- return excluded 88483-} 88484- 88485-// convertFilterToRegexp replaces glob-like operator substrings in a string file path to their equivalent regex forms. 88486-// Supporting glob-like operators: 88487-// - **: match zero or more complete path segments 88488-func convertFilterToRegexp(filter string) *regexp.Regexp { 88489- if filter == "" { 88490- return regexp.MustCompile(".*") 88491- } 88492- var ret strings.Builder 88493- ret.WriteString("^") 88494- segs := strings.Split(filter, "/") 88495- for _, seg := range segs { 88496- // Inv: seg != "" since path is clean. 88497- if seg == "**" { 88498- ret.WriteString(".*") 88499- } else { 88500- ret.WriteString(regexp.QuoteMeta(seg)) 88501- } 88502- ret.WriteString("/") 88503- } 88504- pattern := ret.String() 88505- 88506- // Remove unnecessary "^.*" prefix, which increased 88507- // BenchmarkWorkspaceSymbols time by ~20% (even though 88508- // filter CPU time increased by only by ~2.5%) when the 88509- // default filter was changed to "**/node_modules". 88510- pattern = strings.TrimPrefix(pattern, "^.*") 88511- 88512- return regexp.MustCompile(pattern) 88513-} 88514- 88515-// symbolFile holds symbol information for a single file. 88516-type symbolFile struct { 88517- uri span.URI 88518- md *Metadata 88519- syms []Symbol 88520-} 88521- 88522-// matchFile scans a symbol file and adds matching symbols to the store. 88523-func matchFile(store *symbolStore, symbolizer symbolizer, matcher matcherFunc, roots []string, i symbolFile) { 88524- space := make([]string, 0, 3) 88525- for _, sym := range i.syms { 88526- symbolParts, score := symbolizer(space, sym.Name, i.md, matcher) 88527- 88528- // Check if the score is too low before applying any downranking. 88529- if store.tooLow(score) { 88530- continue 88531- } 88532- 88533- // Factors to apply to the match score for the purpose of downranking 88534- // results. 88535- // 88536- // These numbers were crudely calibrated based on trial-and-error using a 88537- // small number of sample queries. Adjust as necessary. 88538- // 88539- // All factors are multiplicative, meaning if more than one applies they are 88540- // multiplied together. 88541- const ( 88542- // nonWorkspaceFactor is applied to symbols outside of any active 88543- // workspace. Developers are less likely to want to jump to code that they 88544- // are not actively working on. 88545- nonWorkspaceFactor = 0.5 88546- // nonWorkspaceUnexportedFactor is applied to unexported symbols outside of 88547- // any active workspace. Since one wouldn't usually jump to unexported 88548- // symbols to understand a package API, they are particularly irrelevant. 88549- nonWorkspaceUnexportedFactor = 0.5 88550- // every field or method nesting level to access the field decreases 88551- // the score by a factor of 1.0 - depth*depthFactor, up to a depth of 88552- // 3. 88553- depthFactor = 0.2 88554- ) 88555- 88556- startWord := true 88557- exported := true 88558- depth := 0.0 88559- for _, r := range sym.Name { 88560- if startWord && !unicode.IsUpper(r) { 88561- exported = false 88562- } 88563- if r == '.' { 88564- startWord = true 88565- depth++ 88566- } else { 88567- startWord = false 88568- } 88569- } 88570- 88571- inWorkspace := false 88572- for _, root := range roots { 88573- if strings.HasPrefix(string(i.uri), root) { 88574- inWorkspace = true 88575- break 88576- } 88577- } 88578- 88579- // Apply downranking based on workspace position. 88580- if !inWorkspace { 88581- score *= nonWorkspaceFactor 88582- if !exported { 88583- score *= nonWorkspaceUnexportedFactor 88584- } 88585- } 88586- 88587- // Apply downranking based on symbol depth. 88588- if depth > 3 { 88589- depth = 3 88590- } 88591- score *= 1.0 - depth*depthFactor 88592- 88593- if store.tooLow(score) { 88594- continue 88595- } 88596- 88597- si := symbolInformation{ 88598- score: score, 88599- symbol: strings.Join(symbolParts, ""), 88600- kind: sym.Kind, 88601- uri: i.uri, 88602- rng: sym.Range, 88603- container: string(i.md.PkgPath), 88604- } 88605- store.store(si) 88606- } 88607-} 88608- 88609-type symbolStore struct { 88610- res [maxSymbols]symbolInformation 88611-} 88612- 88613-// store inserts si into the sorted results, if si has a high enough score. 88614-func (sc *symbolStore) store(si symbolInformation) { 88615- if sc.tooLow(si.score) { 88616- return 88617- } 88618- insertAt := sort.Search(len(sc.res), func(i int) bool { 88619- // Sort by score, then symbol length, and finally lexically. 88620- if sc.res[i].score != si.score { 88621- return sc.res[i].score < si.score 88622- } 88623- if len(sc.res[i].symbol) != len(si.symbol) { 88624- return len(sc.res[i].symbol) > len(si.symbol) 88625- } 88626- return sc.res[i].symbol > si.symbol 88627- }) 88628- if insertAt < len(sc.res)-1 { 88629- copy(sc.res[insertAt+1:], sc.res[insertAt:len(sc.res)-1]) 88630- } 88631- sc.res[insertAt] = si 88632-} 88633- 88634-func (sc *symbolStore) tooLow(score float64) bool { 88635- return score <= sc.res[len(sc.res)-1].score 88636-} 88637- 88638-func (sc *symbolStore) results() []protocol.SymbolInformation { 88639- var res []protocol.SymbolInformation 88640- for _, si := range sc.res { 88641- if si.score <= 0 { 88642- return res 88643- } 88644- res = append(res, si.asProtocolSymbolInformation()) 88645- } 88646- return res 88647-} 88648- 88649-func typeToKind(typ types.Type) protocol.SymbolKind { 88650- switch typ := typ.Underlying().(type) { 88651- case *types.Interface: 88652- return protocol.Interface 88653- case *types.Struct: 88654- return protocol.Struct 88655- case *types.Signature: 88656- if typ.Recv() != nil { 88657- return protocol.Method 88658- } 88659- return protocol.Function 88660- case *types.Named: 88661- return typeToKind(typ.Underlying()) 88662- case *types.Basic: 88663- i := typ.Info() 88664- switch { 88665- case i&types.IsNumeric != 0: 88666- return protocol.Number 88667- case i&types.IsBoolean != 0: 88668- return protocol.Boolean 88669- case i&types.IsString != 0: 88670- return protocol.String 88671- } 88672- } 88673- return protocol.Variable 88674-} 88675- 88676-// symbolInformation is a cut-down version of protocol.SymbolInformation that 88677-// allows struct values of this type to be used as map keys. 88678-type symbolInformation struct { 88679- score float64 88680- symbol string 88681- container string 88682- kind protocol.SymbolKind 88683- uri span.URI 88684- rng protocol.Range 88685-} 88686- 88687-// asProtocolSymbolInformation converts s to a protocol.SymbolInformation value. 88688-// 88689-// TODO: work out how to handle tags if/when they are needed. 88690-func (s symbolInformation) asProtocolSymbolInformation() protocol.SymbolInformation { 88691- return protocol.SymbolInformation{ 88692- Name: s.symbol, 88693- Kind: s.kind, 88694- Location: protocol.Location{ 88695- URI: protocol.URIFromSpanURI(s.uri), 88696- Range: s.rng, 88697- }, 88698- ContainerName: s.container, 88699- } 88700-} 88701diff -urN a/gopls/internal/lsp/source/workspace_symbol_test.go b/gopls/internal/lsp/source/workspace_symbol_test.go 88702--- a/gopls/internal/lsp/source/workspace_symbol_test.go 2000-01-01 00:00:00.000000000 -0000 88703+++ b/gopls/internal/lsp/source/workspace_symbol_test.go 1970-01-01 00:00:00.000000000 +0000 88704@@ -1,136 +0,0 @@ 88705-// Copyright 2020 The Go Authors. All rights reserved. 88706-// Use of this source code is governed by a BSD-style 88707-// license that can be found in the LICENSE file. 88708- 88709-package source 88710- 88711-import ( 88712- "testing" 88713-) 88714- 88715-func TestParseQuery(t *testing.T) { 88716- tests := []struct { 88717- query, s string 88718- wantMatch bool 88719- }{ 88720- {"", "anything", false}, 88721- {"any", "anything", true}, 88722- {"any$", "anything", false}, 88723- {"ing$", "anything", true}, 88724- {"ing$", "anythinG", true}, 88725- {"inG$", "anything", false}, 88726- {"^any", "anything", true}, 88727- {"^any", "Anything", true}, 88728- {"^Any", "anything", false}, 88729- {"at", "anything", true}, 88730- // TODO: this appears to be a bug in the fuzzy matching algorithm. 'At' 88731- // should cause a case-sensitive match. 88732- // {"At", "anything", false}, 88733- {"At", "Anything", true}, 88734- {"'yth", "Anything", true}, 88735- {"'yti", "Anything", false}, 88736- {"'any 'thing", "Anything", true}, 88737- {"anythn nythg", "Anything", true}, 88738- {"ntx", "Anything", false}, 88739- {"anythn", "anything", true}, 88740- {"ing", "anything", true}, 88741- {"anythn nythgx", "anything", false}, 88742- } 88743- 88744- for _, test := range tests { 88745- matcher := parseQuery(test.query, newFuzzyMatcher) 88746- if _, score := matcher([]string{test.s}); score > 0 != test.wantMatch { 88747- t.Errorf("parseQuery(%q) match for %q: %.2g, want match: %t", test.query, test.s, score, test.wantMatch) 88748- } 88749- } 88750-} 88751- 88752-func TestFiltererDisallow(t *testing.T) { 88753- tests := []struct { 88754- filters []string 88755- included []string 88756- excluded []string 88757- }{ 88758- { 88759- []string{"+**/c.go"}, 88760- []string{"a/c.go", "a/b/c.go"}, 88761- []string{}, 88762- }, 88763- { 88764- []string{"+a/**/c.go"}, 88765- []string{"a/b/c.go", "a/b/d/c.go", "a/c.go"}, 88766- []string{}, 88767- }, 88768- { 88769- []string{"-a/c.go", "+a/**"}, 88770- []string{"a/c.go"}, 88771- []string{}, 88772- }, 88773- { 88774- []string{"+a/**/c.go", "-**/c.go"}, 88775- []string{}, 88776- []string{"a/b/c.go"}, 88777- }, 88778- { 88779- []string{"+a/**/c.go", "-a/**"}, 88780- []string{}, 88781- []string{"a/b/c.go"}, 88782- }, 88783- { 88784- []string{"+**/c.go", "-a/**/c.go"}, 88785- []string{}, 88786- []string{"a/b/c.go"}, 88787- }, 88788- { 88789- []string{"+foobar", "-foo"}, 88790- []string{"foobar", "foobar/a"}, 88791- []string{"foo", "foo/a"}, 88792- }, 88793- { 88794- []string{"+", "-"}, 88795- []string{}, 88796- []string{"foobar", "foobar/a", "foo", "foo/a"}, 88797- }, 88798- { 88799- []string{"-", "+"}, 88800- []string{"foobar", "foobar/a", "foo", "foo/a"}, 88801- []string{}, 88802- }, 88803- { 88804- []string{"-a/**/b/**/c.go"}, 88805- []string{}, 88806- []string{"a/x/y/z/b/f/g/h/c.go"}, 88807- }, 88808- // tests for unsupported glob operators 88809- { 88810- []string{"+**/c.go", "-a/*/c.go"}, 88811- []string{"a/b/c.go"}, 88812- []string{}, 88813- }, 88814- { 88815- []string{"+**/c.go", "-a/?/c.go"}, 88816- []string{"a/b/c.go"}, 88817- []string{}, 88818- }, 88819- { 88820- []string{"-b"}, // should only filter paths prefixed with the "b" directory 88821- []string{"a/b/c.go", "bb"}, 88822- []string{"b/c/d.go", "b"}, 88823- }, 88824- } 88825- 88826- for _, test := range tests { 88827- filterer := NewFilterer(test.filters) 88828- for _, inc := range test.included { 88829- if filterer.Disallow(inc) { 88830- t.Errorf("Filters %v excluded %v, wanted included", test.filters, inc) 88831- } 88832- } 88833- 88834- for _, exc := range test.excluded { 88835- if !filterer.Disallow(exc) { 88836- t.Errorf("Filters %v included %v, wanted excluded", test.filters, exc) 88837- } 88838- } 88839- } 88840-} 88841diff -urN a/gopls/internal/lsp/source/xrefs/xrefs.go b/gopls/internal/lsp/source/xrefs/xrefs.go 88842--- a/gopls/internal/lsp/source/xrefs/xrefs.go 2000-01-01 00:00:00.000000000 -0000 88843+++ b/gopls/internal/lsp/source/xrefs/xrefs.go 1970-01-01 00:00:00.000000000 +0000 88844@@ -1,216 +0,0 @@ 88845-// Copyright 2022 The Go Authors. All rights reserved. 88846-// Use of this source code is governed by a BSD-style 88847-// license that can be found in the LICENSE file. 88848- 88849-// Package xrefs defines the serializable index of cross-package 88850-// references that is computed during type checking. 88851-// 88852-// See ../references2.go for the 'references' query. 88853-package xrefs 88854- 88855-import ( 88856- "bytes" 88857- "encoding/gob" 88858- "go/ast" 88859- "go/types" 88860- "log" 88861- "sort" 88862- 88863- "golang.org/x/tools/go/types/objectpath" 88864- "golang.org/x/tools/gopls/internal/lsp/protocol" 88865- "golang.org/x/tools/gopls/internal/lsp/source" 88866- "golang.org/x/tools/internal/typesinternal" 88867-) 88868- 88869-// Index constructs a serializable index of outbound cross-references 88870-// for the specified type-checked package. 88871-func Index(files []*source.ParsedGoFile, pkg *types.Package, info *types.Info) []byte { 88872- // pkgObjects maps each referenced package Q to a mapping: 88873- // from each referenced symbol in Q to the ordered list 88874- // of references to that symbol from this package. 88875- // A nil types.Object indicates a reference 88876- // to the package as a whole: an import. 88877- pkgObjects := make(map[*types.Package]map[types.Object]*gobObject) 88878- 88879- // getObjects returns the object-to-references mapping for a package. 88880- getObjects := func(pkg *types.Package) map[types.Object]*gobObject { 88881- objects, ok := pkgObjects[pkg] 88882- if !ok { 88883- objects = make(map[types.Object]*gobObject) 88884- pkgObjects[pkg] = objects 88885- } 88886- return objects 88887- } 88888- 88889- objectpathFor := typesinternal.NewObjectpathFunc() 88890- 88891- for fileIndex, pgf := range files { 88892- 88893- nodeRange := func(n ast.Node) protocol.Range { 88894- rng, err := pgf.PosRange(n.Pos(), n.End()) 88895- if err != nil { 88896- panic(err) // can't fail 88897- } 88898- return rng 88899- } 88900- 88901- ast.Inspect(pgf.File, func(n ast.Node) bool { 88902- switch n := n.(type) { 88903- case *ast.Ident: 88904- // Report a reference for each identifier that 88905- // uses a symbol exported from another package. 88906- // (The built-in error.Error method has no package.) 88907- if n.IsExported() { 88908- if obj, ok := info.Uses[n]; ok && 88909- obj.Pkg() != nil && 88910- obj.Pkg() != pkg { 88911- 88912- objects := getObjects(obj.Pkg()) 88913- gobObj, ok := objects[obj] 88914- if !ok { 88915- path, err := objectpathFor(obj) 88916- if err != nil { 88917- // Capitalized but not exported 88918- // (e.g. local const/var/type). 88919- return true 88920- } 88921- gobObj = &gobObject{Path: path} 88922- objects[obj] = gobObj 88923- } 88924- 88925- gobObj.Refs = append(gobObj.Refs, gobRef{ 88926- FileIndex: fileIndex, 88927- Range: nodeRange(n), 88928- }) 88929- } 88930- } 88931- 88932- case *ast.ImportSpec: 88933- // Report a reference from each import path 88934- // string to the imported package. 88935- var obj types.Object 88936- if n.Name != nil { 88937- obj = info.Defs[n.Name] 88938- } else { 88939- obj = info.Implicits[n] 88940- } 88941- if obj == nil { 88942- return true // missing import 88943- } 88944- objects := getObjects(obj.(*types.PkgName).Imported()) 88945- gobObj, ok := objects[nil] 88946- if !ok { 88947- gobObj = &gobObject{Path: ""} 88948- objects[nil] = gobObj 88949- } 88950- gobObj.Refs = append(gobObj.Refs, gobRef{ 88951- FileIndex: fileIndex, 88952- Range: nodeRange(n.Path), 88953- }) 88954- } 88955- return true 88956- }) 88957- } 88958- 88959- // Flatten the maps into slices, and sort for determinism. 88960- var packages []*gobPackage 88961- for p := range pkgObjects { 88962- objects := pkgObjects[p] 88963- gp := &gobPackage{ 88964- PkgPath: source.PackagePath(p.Path()), 88965- Objects: make([]*gobObject, 0, len(objects)), 88966- } 88967- for _, gobObj := range objects { 88968- gp.Objects = append(gp.Objects, gobObj) 88969- } 88970- sort.Slice(gp.Objects, func(i, j int) bool { 88971- return gp.Objects[i].Path < gp.Objects[j].Path 88972- }) 88973- packages = append(packages, gp) 88974- } 88975- sort.Slice(packages, func(i, j int) bool { 88976- return packages[i].PkgPath < packages[j].PkgPath 88977- }) 88978- 88979- return mustEncode(packages) 88980-} 88981- 88982-// Lookup searches a serialized index produced by an indexPackage 88983-// operation on m, and returns the locations of all references from m 88984-// to any object in the target set. Each object is denoted by a pair 88985-// of (package path, object path). 88986-func Lookup(m *source.Metadata, data []byte, targets map[source.PackagePath]map[objectpath.Path]struct{}) (locs []protocol.Location) { 88987- 88988- // TODO(adonovan): opt: evaluate whether it would be faster to decode 88989- // in two passes, first with struct { PkgPath string; Objects BLOB } 88990- // to find the relevant record without decoding the Objects slice, 88991- // then decode just the desired BLOB into a slice. BLOB would be a 88992- // type whose Unmarshal method just retains (a copy of) the bytes. 88993- var packages []gobPackage 88994- mustDecode(data, &packages) 88995- 88996- for _, gp := range packages { 88997- if objectSet, ok := targets[gp.PkgPath]; ok { 88998- for _, gobObj := range gp.Objects { 88999- if _, ok := objectSet[gobObj.Path]; ok { 89000- for _, ref := range gobObj.Refs { 89001- uri := m.CompiledGoFiles[ref.FileIndex] 89002- locs = append(locs, protocol.Location{ 89003- URI: protocol.URIFromSpanURI(uri), 89004- Range: ref.Range, 89005- }) 89006- } 89007- } 89008- } 89009- } 89010- } 89011- 89012- return locs 89013-} 89014- 89015-// -- serialized representation -- 89016- 89017-// The cross-reference index records the location of all references 89018-// from one package to symbols defined in other packages 89019-// (dependencies). It does not record within-package references. 89020-// The index for package P consists of a list of gopPackage records, 89021-// each enumerating references to symbols defined a single dependency, Q. 89022- 89023-// TODO(adonovan): opt: choose a more compact encoding. Gzip reduces 89024-// the gob output to about one third its size, so clearly there's room 89025-// to improve. The gobRef.Range field is the obvious place to begin. 89026-// Even a zero-length slice gob-encodes to ~285 bytes. 89027- 89028-// A gobPackage records the set of outgoing references from the index 89029-// package to symbols defined in a dependency package. 89030-type gobPackage struct { 89031- PkgPath source.PackagePath // defining package (Q) 89032- Objects []*gobObject // set of Q objects referenced by P 89033-} 89034- 89035-// A gobObject records all references to a particular symbol. 89036-type gobObject struct { 89037- Path objectpath.Path // symbol name within package; "" => import of package itself 89038- Refs []gobRef // locations of references within P, in lexical order 89039-} 89040- 89041-type gobRef struct { 89042- FileIndex int // index of enclosing file within P's CompiledGoFiles 89043- Range protocol.Range // source range of reference 89044-} 89045- 89046-// -- duplicated from ../../cache/analysis.go -- 89047- 89048-func mustEncode(x interface{}) []byte { 89049- var buf bytes.Buffer 89050- if err := gob.NewEncoder(&buf).Encode(x); err != nil { 89051- log.Fatalf("internal error encoding %T: %v", x, err) 89052- } 89053- return buf.Bytes() 89054-} 89055- 89056-func mustDecode(data []byte, ptr interface{}) { 89057- if err := gob.NewDecoder(bytes.NewReader(data)).Decode(ptr); err != nil { 89058- log.Fatalf("internal error decoding %T: %v", ptr, err) 89059- } 89060-} 89061diff -urN a/gopls/internal/lsp/symbols.go b/gopls/internal/lsp/symbols.go 89062--- a/gopls/internal/lsp/symbols.go 2000-01-01 00:00:00.000000000 -0000 89063+++ b/gopls/internal/lsp/symbols.go 1970-01-01 00:00:00.000000000 +0000 89064@@ -1,60 +0,0 @@ 89065-// Copyright 2019 The Go Authors. All rights reserved. 89066-// Use of this source code is governed by a BSD-style 89067-// license that can be found in the LICENSE file. 89068- 89069-package lsp 89070- 89071-import ( 89072- "context" 89073- 89074- "golang.org/x/tools/gopls/internal/lsp/protocol" 89075- "golang.org/x/tools/gopls/internal/lsp/source" 89076- "golang.org/x/tools/gopls/internal/lsp/template" 89077- "golang.org/x/tools/internal/event" 89078- "golang.org/x/tools/internal/event/tag" 89079-) 89080- 89081-func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]interface{}, error) { 89082- ctx, done := event.Start(ctx, "lsp.Server.documentSymbol") 89083- defer done() 89084- 89085- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind) 89086- defer release() 89087- if !ok { 89088- return []interface{}{}, err 89089- } 89090- var docSymbols []protocol.DocumentSymbol 89091- switch snapshot.View().FileKind(fh) { 89092- case source.Tmpl: 89093- docSymbols, err = template.DocumentSymbols(snapshot, fh) 89094- case source.Go: 89095- docSymbols, err = source.DocumentSymbols(ctx, snapshot, fh) 89096- default: 89097- return []interface{}{}, nil 89098- } 89099- if err != nil { 89100- event.Error(ctx, "DocumentSymbols failed", err, tag.URI.Of(fh.URI())) 89101- return []interface{}{}, nil 89102- } 89103- // Convert the symbols to an interface array. 89104- // TODO: Remove this once the lsp deprecates SymbolInformation. 89105- symbols := make([]interface{}, len(docSymbols)) 89106- for i, s := range docSymbols { 89107- if snapshot.View().Options().HierarchicalDocumentSymbolSupport { 89108- symbols[i] = s 89109- continue 89110- } 89111- // If the client does not support hierarchical document symbols, then 89112- // we need to be backwards compatible for now and return SymbolInformation. 89113- symbols[i] = protocol.SymbolInformation{ 89114- Name: s.Name, 89115- Kind: s.Kind, 89116- Deprecated: s.Deprecated, 89117- Location: protocol.Location{ 89118- URI: params.TextDocument.URI, 89119- Range: s.Range, 89120- }, 89121- } 89122- } 89123- return symbols, nil 89124-} 89125diff -urN a/gopls/internal/lsp/template/completion.go b/gopls/internal/lsp/template/completion.go 89126--- a/gopls/internal/lsp/template/completion.go 2000-01-01 00:00:00.000000000 -0000 89127+++ b/gopls/internal/lsp/template/completion.go 1970-01-01 00:00:00.000000000 +0000 89128@@ -1,287 +0,0 @@ 89129-// Copyright 2021 The Go Authors. All rights reserved. 89130-// Use of this source code is governed by a BSD-style 89131-// license that can be found in the LICENSE file. 89132- 89133-package template 89134- 89135-import ( 89136- "bytes" 89137- "context" 89138- "fmt" 89139- "go/scanner" 89140- "go/token" 89141- "strings" 89142- 89143- "golang.org/x/tools/gopls/internal/lsp/protocol" 89144- "golang.org/x/tools/gopls/internal/lsp/source" 89145-) 89146- 89147-// information needed for completion 89148-type completer struct { 89149- p *Parsed 89150- pos protocol.Position 89151- offset int // offset of the start of the Token 89152- ctx protocol.CompletionContext 89153- syms map[string]symbol 89154-} 89155- 89156-func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, pos protocol.Position, context protocol.CompletionContext) (*protocol.CompletionList, error) { 89157- all := New(snapshot.Templates()) 89158- var start int // the beginning of the Token (completed or not) 89159- syms := make(map[string]symbol) 89160- var p *Parsed 89161- for fn, fc := range all.files { 89162- // collect symbols from all template files 89163- filterSyms(syms, fc.symbols) 89164- if fn.Filename() != fh.URI().Filename() { 89165- continue 89166- } 89167- if start = inTemplate(fc, pos); start == -1 { 89168- return nil, nil 89169- } 89170- p = fc 89171- } 89172- if p == nil { 89173- // this cannot happen unless the search missed a template file 89174- return nil, fmt.Errorf("%s not found", fh.FileIdentity().URI.Filename()) 89175- } 89176- c := completer{ 89177- p: p, 89178- pos: pos, 89179- offset: start + len(Left), 89180- ctx: context, 89181- syms: syms, 89182- } 89183- return c.complete() 89184-} 89185- 89186-func filterSyms(syms map[string]symbol, ns []symbol) { 89187- for _, xsym := range ns { 89188- switch xsym.kind { 89189- case protocol.Method, protocol.Package, protocol.Boolean, protocol.Namespace, 89190- protocol.Function: 89191- syms[xsym.name] = xsym // we don't care which symbol we get 89192- case protocol.Variable: 89193- if xsym.name != "dot" { 89194- syms[xsym.name] = xsym 89195- } 89196- case protocol.Constant: 89197- if xsym.name == "nil" { 89198- syms[xsym.name] = xsym 89199- } 89200- } 89201- } 89202-} 89203- 89204-// return the starting position of the enclosing token, or -1 if none 89205-func inTemplate(fc *Parsed, pos protocol.Position) int { 89206- // pos is the pos-th character. if the cursor is at the beginning 89207- // of the file, pos is 0. That is, we've only seen characters before pos 89208- // 1. pos might be in a Token, return tk.Start 89209- // 2. pos might be after an elided but before a Token, return elided 89210- // 3. return -1 for false 89211- offset := fc.FromPosition(pos) 89212- // this could be a binary search, as the tokens are ordered 89213- for _, tk := range fc.tokens { 89214- if tk.Start < offset && offset <= tk.End { 89215- return tk.Start 89216- } 89217- } 89218- for _, x := range fc.elided { 89219- if x > offset { 89220- // fc.elided is sorted 89221- break 89222- } 89223- // If the interval [x,offset] does not contain Left or Right 89224- // then provide completions. (do we need the test for Right?) 89225- if !bytes.Contains(fc.buf[x:offset], []byte(Left)) && !bytes.Contains(fc.buf[x:offset], []byte(Right)) { 89226- return x 89227- } 89228- } 89229- return -1 89230-} 89231- 89232-var ( 89233- keywords = []string{"if", "with", "else", "block", "range", "template", "end}}", "end"} 89234- globals = []string{"and", "call", "html", "index", "slice", "js", "len", "not", "or", 89235- "urlquery", "printf", "println", "print", "eq", "ne", "le", "lt", "ge", "gt"} 89236-) 89237- 89238-// find the completions. start is the offset of either the Token enclosing pos, or where 89239-// the incomplete token starts. 89240-// The error return is always nil. 89241-func (c *completer) complete() (*protocol.CompletionList, error) { 89242- ans := &protocol.CompletionList{IsIncomplete: true, Items: []protocol.CompletionItem{}} 89243- start := c.p.FromPosition(c.pos) 89244- sofar := c.p.buf[c.offset:start] 89245- if len(sofar) == 0 || sofar[len(sofar)-1] == ' ' || sofar[len(sofar)-1] == '\t' { 89246- return ans, nil 89247- } 89248- // sofar could be parsed by either c.analyzer() or scan(). The latter is precise 89249- // and slower, but fast enough 89250- words := scan(sofar) 89251- // 1. if pattern starts $, show variables 89252- // 2. if pattern starts ., show methods (and . by itself?) 89253- // 3. if len(words) == 1, show firstWords (but if it were a |, show functions and globals) 89254- // 4. ...? (parenthetical expressions, arguments, ...) (packages, namespaces, nil?) 89255- if len(words) == 0 { 89256- return nil, nil // if this happens, why were we called? 89257- } 89258- pattern := string(words[len(words)-1]) 89259- if pattern[0] == '$' { 89260- // should we also return a raw "$"? 89261- for _, s := range c.syms { 89262- if s.kind == protocol.Variable && weakMatch(s.name, pattern) > 0 { 89263- ans.Items = append(ans.Items, protocol.CompletionItem{ 89264- Label: s.name, 89265- Kind: protocol.VariableCompletion, 89266- Detail: "Variable", 89267- }) 89268- } 89269- } 89270- return ans, nil 89271- } 89272- if pattern[0] == '.' { 89273- for _, s := range c.syms { 89274- if s.kind == protocol.Method && weakMatch("."+s.name, pattern) > 0 { 89275- ans.Items = append(ans.Items, protocol.CompletionItem{ 89276- Label: s.name, 89277- Kind: protocol.MethodCompletion, 89278- Detail: "Method/member", 89279- }) 89280- } 89281- } 89282- return ans, nil 89283- } 89284- // could we get completion attempts in strings or numbers, and if so, do we care? 89285- // globals 89286- for _, kw := range globals { 89287- if weakMatch(kw, string(pattern)) != 0 { 89288- ans.Items = append(ans.Items, protocol.CompletionItem{ 89289- Label: kw, 89290- Kind: protocol.KeywordCompletion, 89291- Detail: "Function", 89292- }) 89293- } 89294- } 89295- // and functions 89296- for _, s := range c.syms { 89297- if s.kind == protocol.Function && weakMatch(s.name, pattern) != 0 { 89298- ans.Items = append(ans.Items, protocol.CompletionItem{ 89299- Label: s.name, 89300- Kind: protocol.FunctionCompletion, 89301- Detail: "Function", 89302- }) 89303- } 89304- } 89305- // keywords if we're at the beginning 89306- if len(words) <= 1 || len(words[len(words)-2]) == 1 && words[len(words)-2][0] == '|' { 89307- for _, kw := range keywords { 89308- if weakMatch(kw, string(pattern)) != 0 { 89309- ans.Items = append(ans.Items, protocol.CompletionItem{ 89310- Label: kw, 89311- Kind: protocol.KeywordCompletion, 89312- Detail: "keyword", 89313- }) 89314- } 89315- } 89316- } 89317- return ans, nil 89318-} 89319- 89320-// someday think about comments, strings, backslashes, etc 89321-// this would repeat some of the template parsing, but because the user is typing 89322-// there may be no parse tree here. 89323-// (go/scanner will report 2 tokens for $a, as $ is not a legal go identifier character) 89324-// (go/scanner is about 2.7 times more expensive) 89325-func (c *completer) analyze(buf []byte) [][]byte { 89326- // we want to split on whitespace and before dots 89327- var working []byte 89328- var ans [][]byte 89329- for _, ch := range buf { 89330- if ch == '.' && len(working) > 0 { 89331- ans = append(ans, working) 89332- working = []byte{'.'} 89333- continue 89334- } 89335- if ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' { 89336- if len(working) > 0 { 89337- ans = append(ans, working) 89338- working = []byte{} 89339- continue 89340- } 89341- } 89342- working = append(working, ch) 89343- } 89344- if len(working) > 0 { 89345- ans = append(ans, working) 89346- } 89347- ch := buf[len(buf)-1] 89348- if ch == ' ' || ch == '\t' { 89349- // avoid completing on whitespace 89350- ans = append(ans, []byte{ch}) 89351- } 89352- return ans 89353-} 89354- 89355-// version of c.analyze that uses go/scanner. 89356-func scan(buf []byte) []string { 89357- fset := token.NewFileSet() 89358- fp := fset.AddFile("", -1, len(buf)) 89359- var sc scanner.Scanner 89360- sc.Init(fp, buf, func(pos token.Position, msg string) {}, scanner.ScanComments) 89361- ans := make([]string, 0, 10) // preallocating gives a measurable savings 89362- for { 89363- _, tok, lit := sc.Scan() // tok is an int 89364- if tok == token.EOF { 89365- break // done 89366- } else if tok == token.SEMICOLON && lit == "\n" { 89367- continue // don't care, but probably can't happen 89368- } else if tok == token.PERIOD { 89369- ans = append(ans, ".") // lit is empty 89370- } else if tok == token.IDENT && len(ans) > 0 && ans[len(ans)-1] == "." { 89371- ans[len(ans)-1] = "." + lit 89372- } else if tok == token.IDENT && len(ans) > 0 && ans[len(ans)-1] == "$" { 89373- ans[len(ans)-1] = "$" + lit 89374- } else if lit != "" { 89375- ans = append(ans, lit) 89376- } 89377- } 89378- return ans 89379-} 89380- 89381-// pattern is what the user has typed 89382-func weakMatch(choice, pattern string) float64 { 89383- lower := strings.ToLower(choice) 89384- // for now, use only lower-case everywhere 89385- pattern = strings.ToLower(pattern) 89386- // The first char has to match 89387- if pattern[0] != lower[0] { 89388- return 0 89389- } 89390- // If they start with ., then the second char has to match 89391- from := 1 89392- if pattern[0] == '.' { 89393- if len(pattern) < 2 { 89394- return 1 // pattern just a ., so it matches 89395- } 89396- if pattern[1] != lower[1] { 89397- return 0 89398- } 89399- from = 2 89400- } 89401- // check that all the characters of pattern occur as a subsequence of choice 89402- i, j := from, from 89403- for ; i < len(lower) && j < len(pattern); j++ { 89404- if pattern[j] == lower[i] { 89405- i++ 89406- if i >= len(lower) { 89407- return 0 89408- } 89409- } 89410- } 89411- if j < len(pattern) { 89412- return 0 89413- } 89414- return 1 89415-} 89416diff -urN a/gopls/internal/lsp/template/completion_test.go b/gopls/internal/lsp/template/completion_test.go 89417--- a/gopls/internal/lsp/template/completion_test.go 2000-01-01 00:00:00.000000000 -0000 89418+++ b/gopls/internal/lsp/template/completion_test.go 1970-01-01 00:00:00.000000000 +0000 89419@@ -1,102 +0,0 @@ 89420-// Copyright 2021 The Go Authors. All rights reserved. 89421-// Use of this source code is governed by a BSD-style 89422-// license that can be found in the LICENSE file. 89423- 89424-package template 89425- 89426-import ( 89427- "log" 89428- "sort" 89429- "strings" 89430- "testing" 89431- 89432- "golang.org/x/tools/gopls/internal/lsp/protocol" 89433-) 89434- 89435-func init() { 89436- log.SetFlags(log.Lshortfile) 89437-} 89438- 89439-type tparse struct { 89440- marked string // ^ shows where to ask for completions. (The user just typed the following character.) 89441- wanted []string // expected completions 89442-} 89443- 89444-// Test completions in templates that parse enough (if completion needs symbols) 89445-// Seen characters up to the ^ 89446-func TestParsed(t *testing.T) { 89447- var tests = []tparse{ 89448- {"{{x}}{{12. xx^", nil}, // https://github.com/golang/go/issues/50430 89449- {`<table class="chroma" data-new-comment-url="{{if $.PageIsPullFiles}}{{$.Issue.HTMLURL}}/files/reviews/new_comment{{else}}{{$.CommitHTML}}/new_comment^{{end}}">`, nil}, 89450- {"{{i^f}}", []string{"index", "if"}}, 89451- {"{{if .}}{{e^ {{end}}", []string{"eq", "end}}", "else", "end"}}, 89452- {"{{foo}}{{f^", []string{"foo"}}, 89453- {"{{$^}}", []string{"$"}}, 89454- {"{{$x:=4}}{{$^", []string{"$x"}}, 89455- {"{{$x:=4}}{{$ ^ ", []string{}}, 89456- {"{{len .Modified}}{{.^Mo", []string{"Modified"}}, 89457- {"{{len .Modified}}{{.mf^", []string{"Modified"}}, 89458- {"{{$^ }}", []string{"$"}}, 89459- {"{{$a =3}}{{$^", []string{"$a"}}, 89460- // .two is not good here: fix someday 89461- {`{{.Modified}}{{.^{{if $.one.two}}xxx{{end}}`, []string{"Modified", "one", "two"}}, 89462- {`{{.Modified}}{{.o^{{if $.one.two}}xxx{{end}}`, []string{"one"}}, 89463- {"{{.Modiifed}}{{.one.t^{{if $.one.two}}xxx{{end}}", []string{"two"}}, 89464- {`{{block "foo" .}}{{i^`, []string{"index", "if"}}, 89465- {"{{in^{{Internal}}", []string{"index", "Internal", "if"}}, 89466- // simple number has no completions 89467- {"{{4^e", []string{}}, 89468- // simple string has no completions 89469- {"{{`e^", []string{}}, 89470- {"{{`No i^", []string{}}, // example of why go/scanner is used 89471- {"{{xavier}}{{12. x^", []string{"xavier"}}, 89472- } 89473- for _, tx := range tests { 89474- c := testCompleter(t, tx) 89475- var v []string 89476- if c != nil { 89477- ans, _ := c.complete() 89478- for _, a := range ans.Items { 89479- v = append(v, a.Label) 89480- } 89481- } 89482- if len(v) != len(tx.wanted) { 89483- t.Errorf("%q: got %q, wanted %q %d,%d", tx.marked, v, tx.wanted, len(v), len(tx.wanted)) 89484- continue 89485- } 89486- sort.Strings(tx.wanted) 89487- sort.Strings(v) 89488- for i := 0; i < len(v); i++ { 89489- if tx.wanted[i] != v[i] { 89490- t.Errorf("%q at %d: got %v, wanted %v", tx.marked, i, v, tx.wanted) 89491- break 89492- } 89493- } 89494- } 89495-} 89496- 89497-func testCompleter(t *testing.T, tx tparse) *completer { 89498- t.Helper() 89499- // seen chars up to ^ 89500- col := strings.Index(tx.marked, "^") 89501- buf := strings.Replace(tx.marked, "^", "", 1) 89502- p := parseBuffer([]byte(buf)) 89503- pos := protocol.Position{Line: 0, Character: uint32(col)} 89504- if p.ParseErr != nil { 89505- log.Printf("%q: %v", tx.marked, p.ParseErr) 89506- } 89507- offset := inTemplate(p, pos) 89508- if offset == -1 { 89509- return nil 89510- } 89511- syms := make(map[string]symbol) 89512- filterSyms(syms, p.symbols) 89513- c := &completer{ 89514- p: p, 89515- pos: protocol.Position{Line: 0, Character: uint32(col)}, 89516- offset: offset + len(Left), 89517- ctx: protocol.CompletionContext{TriggerKind: protocol.Invoked}, 89518- syms: syms, 89519- } 89520- return c 89521-} 89522diff -urN a/gopls/internal/lsp/template/highlight.go b/gopls/internal/lsp/template/highlight.go 89523--- a/gopls/internal/lsp/template/highlight.go 2000-01-01 00:00:00.000000000 -0000 89524+++ b/gopls/internal/lsp/template/highlight.go 1970-01-01 00:00:00.000000000 +0000 89525@@ -1,96 +0,0 @@ 89526-// Copyright 2021 The Go Authors. All rights reserved. 89527-// Use of this source code is governed by a BSD-style 89528-// license that can be found in the LICENSE file. 89529- 89530-package template 89531- 89532-import ( 89533- "context" 89534- "fmt" 89535- "regexp" 89536- 89537- "golang.org/x/tools/gopls/internal/lsp/protocol" 89538- "golang.org/x/tools/gopls/internal/lsp/source" 89539-) 89540- 89541-func Highlight(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, loc protocol.Position) ([]protocol.DocumentHighlight, error) { 89542- buf, err := fh.Read() 89543- if err != nil { 89544- return nil, err 89545- } 89546- p := parseBuffer(buf) 89547- pos := p.FromPosition(loc) 89548- var ans []protocol.DocumentHighlight 89549- if p.ParseErr == nil { 89550- for _, s := range p.symbols { 89551- if s.start <= pos && pos < s.start+s.length { 89552- return markSymbols(p, s) 89553- } 89554- } 89555- } 89556- // these tokens exist whether or not there was a parse error 89557- // (symbols require a successful parse) 89558- for _, tok := range p.tokens { 89559- if tok.Start <= pos && pos < tok.End { 89560- wordAt := findWordAt(p, pos) 89561- if len(wordAt) > 0 { 89562- return markWordInToken(p, wordAt) 89563- } 89564- } 89565- } 89566- // find the 'word' at pos, etc: someday 89567- // until then we get the default action, which doesn't respect word boundaries 89568- return ans, nil 89569-} 89570- 89571-func markSymbols(p *Parsed, sym symbol) ([]protocol.DocumentHighlight, error) { 89572- var ans []protocol.DocumentHighlight 89573- for _, s := range p.symbols { 89574- if s.name == sym.name { 89575- kind := protocol.Read 89576- if s.vardef { 89577- kind = protocol.Write 89578- } 89579- ans = append(ans, protocol.DocumentHighlight{ 89580- Range: p.Range(s.start, s.length), 89581- Kind: kind, 89582- }) 89583- } 89584- } 89585- return ans, nil 89586-} 89587- 89588-// A token is {{...}}, and this marks words in the token that equal the give word 89589-func markWordInToken(p *Parsed, wordAt string) ([]protocol.DocumentHighlight, error) { 89590- var ans []protocol.DocumentHighlight 89591- pat, err := regexp.Compile(fmt.Sprintf(`\b%s\b`, wordAt)) 89592- if err != nil { 89593- return nil, fmt.Errorf("%q: unmatchable word (%v)", wordAt, err) 89594- } 89595- for _, tok := range p.tokens { 89596- got := pat.FindAllIndex(p.buf[tok.Start:tok.End], -1) 89597- for i := 0; i < len(got); i++ { 89598- ans = append(ans, protocol.DocumentHighlight{ 89599- Range: p.Range(got[i][0], got[i][1]-got[i][0]), 89600- Kind: protocol.Text, 89601- }) 89602- } 89603- } 89604- return ans, nil 89605-} 89606- 89607-var wordRe = regexp.MustCompile(`[$]?\w+$`) 89608-var moreRe = regexp.MustCompile(`^[$]?\w+`) 89609- 89610-// findWordAt finds the word the cursor is in (meaning in or just before) 89611-func findWordAt(p *Parsed, pos int) string { 89612- if pos >= len(p.buf) { 89613- return "" // can't happen, as we are called with pos < tok.End 89614- } 89615- after := moreRe.Find(p.buf[pos:]) 89616- if len(after) == 0 { 89617- return "" // end of the word 89618- } 89619- got := wordRe.Find(p.buf[:pos+len(after)]) 89620- return string(got) 89621-} 89622diff -urN a/gopls/internal/lsp/template/implementations.go b/gopls/internal/lsp/template/implementations.go 89623--- a/gopls/internal/lsp/template/implementations.go 2000-01-01 00:00:00.000000000 -0000 89624+++ b/gopls/internal/lsp/template/implementations.go 1970-01-01 00:00:00.000000000 +0000 89625@@ -1,189 +0,0 @@ 89626-// Copyright 2021 The Go Authors. All rights reserved. 89627-// Use of this source code is governed by a BSD-style 89628-// license that can be found in the LICENSE file. 89629- 89630-package template 89631- 89632-import ( 89633- "context" 89634- "fmt" 89635- "regexp" 89636- "strconv" 89637- "time" 89638- 89639- "golang.org/x/tools/gopls/internal/lsp/protocol" 89640- "golang.org/x/tools/gopls/internal/lsp/source" 89641- "golang.org/x/tools/gopls/internal/span" 89642-) 89643- 89644-// line number (1-based) and message 89645-var errRe = regexp.MustCompile(`template.*:(\d+): (.*)`) 89646- 89647-// Diagnose returns parse errors. There is only one. 89648-// The errors are not always helpful. For instance { {end}} 89649-// will likely point to the end of the file. 89650-func Diagnose(f source.FileHandle) []*source.Diagnostic { 89651- // no need for skipTemplate check, as Diagnose is called on the 89652- // snapshot's template files 89653- buf, err := f.Read() 89654- if err != nil { 89655- // Is a Diagnostic with no Range useful? event.Error also? 89656- msg := fmt.Sprintf("failed to read %s (%v)", f.URI().Filename(), err) 89657- d := source.Diagnostic{Message: msg, Severity: protocol.SeverityError, URI: f.URI(), 89658- Source: source.TemplateError} 89659- return []*source.Diagnostic{&d} 89660- } 89661- p := parseBuffer(buf) 89662- if p.ParseErr == nil { 89663- return nil 89664- } 89665- unknownError := func(msg string) []*source.Diagnostic { 89666- s := fmt.Sprintf("malformed template error %q: %s", p.ParseErr.Error(), msg) 89667- d := source.Diagnostic{ 89668- Message: s, Severity: protocol.SeverityError, Range: p.Range(p.nls[0], 1), 89669- URI: f.URI(), Source: source.TemplateError} 89670- return []*source.Diagnostic{&d} 89671- } 89672- // errors look like `template: :40: unexpected "}" in operand` 89673- // so the string needs to be parsed 89674- matches := errRe.FindStringSubmatch(p.ParseErr.Error()) 89675- if len(matches) != 3 { 89676- msg := fmt.Sprintf("expected 3 matches, got %d (%v)", len(matches), matches) 89677- return unknownError(msg) 89678- } 89679- lineno, err := strconv.Atoi(matches[1]) 89680- if err != nil { 89681- msg := fmt.Sprintf("couldn't convert %q to int, %v", matches[1], err) 89682- return unknownError(msg) 89683- } 89684- msg := matches[2] 89685- d := source.Diagnostic{Message: msg, Severity: protocol.SeverityError, 89686- Source: source.TemplateError} 89687- start := p.nls[lineno-1] 89688- if lineno < len(p.nls) { 89689- size := p.nls[lineno] - start 89690- d.Range = p.Range(start, size) 89691- } else { 89692- d.Range = p.Range(start, 1) 89693- } 89694- return []*source.Diagnostic{&d} 89695-} 89696- 89697-// Definition finds the definitions of the symbol at loc. It 89698-// does not understand scoping (if any) in templates. This code is 89699-// for definitions, type definitions, and implementations. 89700-// Results only for variables and templates. 89701-func Definition(snapshot source.Snapshot, fh source.FileHandle, loc protocol.Position) ([]protocol.Location, error) { 89702- x, _, err := symAtPosition(fh, loc) 89703- if err != nil { 89704- return nil, err 89705- } 89706- sym := x.name 89707- ans := []protocol.Location{} 89708- // PJW: this is probably a pattern to abstract 89709- a := New(snapshot.Templates()) 89710- for k, p := range a.files { 89711- for _, s := range p.symbols { 89712- if !s.vardef || s.name != sym { 89713- continue 89714- } 89715- ans = append(ans, protocol.Location{URI: protocol.DocumentURI(k), Range: p.Range(s.start, s.length)}) 89716- } 89717- } 89718- return ans, nil 89719-} 89720- 89721-func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.Hover, error) { 89722- sym, p, err := symAtPosition(fh, position) 89723- if sym == nil || err != nil { 89724- return nil, err 89725- } 89726- ans := protocol.Hover{Range: p.Range(sym.start, sym.length), Contents: protocol.MarkupContent{Kind: protocol.Markdown}} 89727- switch sym.kind { 89728- case protocol.Function: 89729- ans.Contents.Value = fmt.Sprintf("function: %s", sym.name) 89730- case protocol.Variable: 89731- ans.Contents.Value = fmt.Sprintf("variable: %s", sym.name) 89732- case protocol.Constant: 89733- ans.Contents.Value = fmt.Sprintf("constant %s", sym.name) 89734- case protocol.Method: // field or method 89735- ans.Contents.Value = fmt.Sprintf("%s: field or method", sym.name) 89736- case protocol.Package: // template use, template def (PJW: do we want two?) 89737- ans.Contents.Value = fmt.Sprintf("template %s\n(add definition)", sym.name) 89738- case protocol.Namespace: 89739- ans.Contents.Value = fmt.Sprintf("template %s defined", sym.name) 89740- case protocol.Number: 89741- ans.Contents.Value = "number" 89742- case protocol.String: 89743- ans.Contents.Value = "string" 89744- case protocol.Boolean: 89745- ans.Contents.Value = "boolean" 89746- default: 89747- ans.Contents.Value = fmt.Sprintf("oops, sym=%#v", sym) 89748- } 89749- return &ans, nil 89750-} 89751- 89752-func References(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, params *protocol.ReferenceParams) ([]protocol.Location, error) { 89753- sym, _, err := symAtPosition(fh, params.Position) 89754- if sym == nil || err != nil || sym.name == "" { 89755- return nil, err 89756- } 89757- ans := []protocol.Location{} 89758- 89759- a := New(snapshot.Templates()) 89760- for k, p := range a.files { 89761- for _, s := range p.symbols { 89762- if s.name != sym.name { 89763- continue 89764- } 89765- if s.vardef && !params.Context.IncludeDeclaration { 89766- continue 89767- } 89768- ans = append(ans, protocol.Location{URI: protocol.DocumentURI(k), Range: p.Range(s.start, s.length)}) 89769- } 89770- } 89771- // do these need to be sorted? (a.files is a map) 89772- return ans, nil 89773-} 89774- 89775-func SemanticTokens(ctx context.Context, snapshot source.Snapshot, spn span.URI, add func(line, start, len uint32), d func() []uint32) (*protocol.SemanticTokens, error) { 89776- fh, err := snapshot.GetFile(ctx, spn) 89777- if err != nil { 89778- return nil, err 89779- } 89780- buf, err := fh.Read() 89781- if err != nil { 89782- return nil, err 89783- } 89784- p := parseBuffer(buf) 89785- 89786- for _, t := range p.Tokens() { 89787- if t.Multiline { 89788- la, ca := p.LineCol(t.Start) 89789- lb, cb := p.LineCol(t.End) 89790- add(la, ca, p.RuneCount(la, ca, 0)) 89791- for l := la + 1; l < lb; l++ { 89792- add(l, 0, p.RuneCount(l, 0, 0)) 89793- } 89794- add(lb, 0, p.RuneCount(lb, 0, cb)) 89795- continue 89796- } 89797- sz, err := p.TokenSize(t) 89798- if err != nil { 89799- return nil, err 89800- } 89801- line, col := p.LineCol(t.Start) 89802- add(line, col, uint32(sz)) 89803- } 89804- data := d() 89805- ans := &protocol.SemanticTokens{ 89806- Data: data, 89807- // for small cache, some day. for now, the LSP client ignores this 89808- // (that is, when the LSP client starts returning these, we can cache) 89809- ResultID: fmt.Sprintf("%v", time.Now()), 89810- } 89811- return ans, nil 89812-} 89813- 89814-// still need to do rename, etc 89815diff -urN a/gopls/internal/lsp/template/parse.go b/gopls/internal/lsp/template/parse.go 89816--- a/gopls/internal/lsp/template/parse.go 2000-01-01 00:00:00.000000000 -0000 89817+++ b/gopls/internal/lsp/template/parse.go 1970-01-01 00:00:00.000000000 +0000 89818@@ -1,508 +0,0 @@ 89819-// Copyright 2021 The Go Authors. All rights reserved. 89820-// Use of this source code is governed by a BSD-style 89821-// license that can be found in the LICENSE file. 89822- 89823-// Package template contains code for dealing with templates 89824-package template 89825- 89826-// template files are small enough that the code reprocesses them each time 89827-// this may be a bad choice for projects with lots of template files. 89828- 89829-// This file contains the parsing code, some debugging printing, and 89830-// implementations for Diagnose, Definition, Hover, References 89831- 89832-import ( 89833- "bytes" 89834- "context" 89835- "fmt" 89836- "io" 89837- "log" 89838- "regexp" 89839- "runtime" 89840- "sort" 89841- "text/template" 89842- "text/template/parse" 89843- "unicode/utf8" 89844- 89845- "golang.org/x/tools/gopls/internal/lsp/protocol" 89846- "golang.org/x/tools/gopls/internal/lsp/source" 89847- "golang.org/x/tools/gopls/internal/span" 89848- "golang.org/x/tools/internal/event" 89849-) 89850- 89851-var ( 89852- Left = []byte("{{") 89853- Right = []byte("}}") 89854-) 89855- 89856-type Parsed struct { 89857- buf []byte //contents 89858- lines [][]byte // needed?, other than for debugging? 89859- elided []int // offsets where Left was replaced by blanks 89860- 89861- // tokens are matched Left-Right pairs, computed before trying to parse 89862- tokens []Token 89863- 89864- // result of parsing 89865- named []*template.Template // the template and embedded templates 89866- ParseErr error 89867- symbols []symbol 89868- stack []parse.Node // used while computing symbols 89869- 89870- // for mapping from offsets in buf to LSP coordinates 89871- // See FromPosition() and LineCol() 89872- nls []int // offset of newlines before each line (nls[0]==-1) 89873- lastnl int // last line seen 89874- check int // used to decide whether to use lastnl or search through nls 89875- nonASCII bool // are there any non-ascii runes in buf? 89876-} 89877- 89878-// Token is a single {{...}}. More precisely, Left...Right 89879-type Token struct { 89880- Start, End int // offset from start of template 89881- Multiline bool 89882-} 89883- 89884-// All contains the Parse of all the template files 89885-type All struct { 89886- files map[span.URI]*Parsed 89887-} 89888- 89889-// New returns the Parses of the snapshot's tmpl files 89890-// (maybe cache these, but then avoiding import cycles needs code rearrangements) 89891-func New(tmpls map[span.URI]source.FileHandle) *All { 89892- all := make(map[span.URI]*Parsed) 89893- for k, v := range tmpls { 89894- buf, err := v.Read() 89895- if err != nil { // PJW: decide what to do with these errors 89896- log.Printf("failed to read %s (%v)", v.URI().Filename(), err) 89897- continue 89898- } 89899- all[k] = parseBuffer(buf) 89900- } 89901- return &All{files: all} 89902-} 89903- 89904-func parseBuffer(buf []byte) *Parsed { 89905- ans := &Parsed{ 89906- buf: buf, 89907- check: -1, 89908- nls: []int{-1}, 89909- } 89910- if len(buf) == 0 { 89911- return ans 89912- } 89913- // how to compute allAscii... 89914- for _, b := range buf { 89915- if b >= utf8.RuneSelf { 89916- ans.nonASCII = true 89917- break 89918- } 89919- } 89920- if buf[len(buf)-1] != '\n' { 89921- ans.buf = append(buf, '\n') 89922- } 89923- for i, p := range ans.buf { 89924- if p == '\n' { 89925- ans.nls = append(ans.nls, i) 89926- } 89927- } 89928- ans.setTokens() // ans.buf may be a new []byte 89929- ans.lines = bytes.Split(ans.buf, []byte{'\n'}) 89930- t, err := template.New("").Parse(string(ans.buf)) 89931- if err != nil { 89932- funcs := make(template.FuncMap) 89933- for t == nil && ans.ParseErr == nil { 89934- // in 1.17 it may be possible to avoid getting this error 89935- // template: :2: function "foo" not defined 89936- matches := parseErrR.FindStringSubmatch(err.Error()) 89937- if len(matches) == 2 { 89938- // suppress the error by giving it a function with the right name 89939- funcs[matches[1]] = func() interface{} { return nil } 89940- t, err = template.New("").Funcs(funcs).Parse(string(ans.buf)) 89941- continue 89942- } 89943- ans.ParseErr = err // unfixed error 89944- return ans 89945- } 89946- } 89947- ans.named = t.Templates() 89948- // set the symbols 89949- for _, t := range ans.named { 89950- ans.stack = append(ans.stack, t.Root) 89951- ans.findSymbols() 89952- if t.Name() != "" { 89953- // defining a template. The pos is just after {{define...}} (or {{block...}}?) 89954- at, sz := ans.FindLiteralBefore(int(t.Root.Pos)) 89955- s := symbol{start: at, length: sz, name: t.Name(), kind: protocol.Namespace, vardef: true} 89956- ans.symbols = append(ans.symbols, s) 89957- } 89958- } 89959- 89960- sort.Slice(ans.symbols, func(i, j int) bool { 89961- left, right := ans.symbols[i], ans.symbols[j] 89962- if left.start != right.start { 89963- return left.start < right.start 89964- } 89965- if left.vardef != right.vardef { 89966- return left.vardef 89967- } 89968- return left.kind < right.kind 89969- }) 89970- return ans 89971-} 89972- 89973-// FindLiteralBefore locates the first preceding string literal 89974-// returning its position and length in buf 89975-// or returns -1 if there is none. 89976-// Assume double-quoted string rather than backquoted string for now. 89977-func (p *Parsed) FindLiteralBefore(pos int) (int, int) { 89978- left, right := -1, -1 89979- for i := pos - 1; i >= 0; i-- { 89980- if p.buf[i] != '"' { 89981- continue 89982- } 89983- if right == -1 { 89984- right = i 89985- continue 89986- } 89987- left = i 89988- break 89989- } 89990- if left == -1 { 89991- return -1, 0 89992- } 89993- return left + 1, right - left - 1 89994-} 89995- 89996-var ( 89997- parseErrR = regexp.MustCompile(`template:.*function "([^"]+)" not defined`) 89998-) 89999- 90000-func (p *Parsed) setTokens() { 90001- const ( 90002- // InRaw and InString only occur inside an action (SeenLeft) 90003- Start = iota 90004- InRaw 90005- InString 90006- SeenLeft 90007- ) 90008- state := Start 90009- var left, oldState int 90010- for n := 0; n < len(p.buf); n++ { 90011- c := p.buf[n] 90012- switch state { 90013- case InRaw: 90014- if c == '`' { 90015- state = oldState 90016- } 90017- case InString: 90018- if c == '"' && !isEscaped(p.buf[:n]) { 90019- state = oldState 90020- } 90021- case SeenLeft: 90022- if c == '`' { 90023- oldState = state // it's SeenLeft, but a little clearer this way 90024- state = InRaw 90025- continue 90026- } 90027- if c == '"' { 90028- oldState = state 90029- state = InString 90030- continue 90031- } 90032- if bytes.HasPrefix(p.buf[n:], Right) { 90033- right := n + len(Right) 90034- tok := Token{Start: left, 90035- End: right, 90036- Multiline: bytes.Contains(p.buf[left:right], []byte{'\n'}), 90037- } 90038- p.tokens = append(p.tokens, tok) 90039- state = Start 90040- } 90041- // If we see (unquoted) Left then the original left is probably the user 90042- // typing. Suppress the original left 90043- if bytes.HasPrefix(p.buf[n:], Left) { 90044- p.elideAt(left) 90045- left = n 90046- n += len(Left) - 1 // skip the rest 90047- } 90048- case Start: 90049- if bytes.HasPrefix(p.buf[n:], Left) { 90050- left = n 90051- state = SeenLeft 90052- n += len(Left) - 1 // skip the rest (avoids {{{ bug) 90053- } 90054- } 90055- } 90056- // this error occurs after typing {{ at the end of the file 90057- if state != Start { 90058- // Unclosed Left. remove the Left at left 90059- p.elideAt(left) 90060- } 90061-} 90062- 90063-func (p *Parsed) elideAt(left int) { 90064- if p.elided == nil { 90065- // p.buf is the same buffer that v.Read() returns, so copy it. 90066- // (otherwise the next time it's parsed, elided information is lost) 90067- b := make([]byte, len(p.buf)) 90068- copy(b, p.buf) 90069- p.buf = b 90070- } 90071- for i := 0; i < len(Left); i++ { 90072- p.buf[left+i] = ' ' 90073- } 90074- p.elided = append(p.elided, left) 90075-} 90076- 90077-// isEscaped reports whether the byte after buf is escaped 90078-func isEscaped(buf []byte) bool { 90079- backSlashes := 0 90080- for j := len(buf) - 1; j >= 0 && buf[j] == '\\'; j-- { 90081- backSlashes++ 90082- } 90083- return backSlashes%2 == 1 90084-} 90085- 90086-func (p *Parsed) Tokens() []Token { 90087- return p.tokens 90088-} 90089- 90090-// TODO(adonovan): the next 100 lines could perhaps replaced by use of protocol.Mapper. 90091- 90092-func (p *Parsed) utf16len(buf []byte) int { 90093- cnt := 0 90094- if !p.nonASCII { 90095- return len(buf) 90096- } 90097- // we need a utf16len(rune), but we don't have it 90098- for _, r := range string(buf) { 90099- cnt++ 90100- if r >= 1<<16 { 90101- cnt++ 90102- } 90103- } 90104- return cnt 90105-} 90106- 90107-func (p *Parsed) TokenSize(t Token) (int, error) { 90108- if t.Multiline { 90109- return -1, fmt.Errorf("TokenSize called with Multiline token %#v", t) 90110- } 90111- ans := p.utf16len(p.buf[t.Start:t.End]) 90112- return ans, nil 90113-} 90114- 90115-// RuneCount counts runes in line l, from col s to e 90116-// (e==0 for end of line. called only for multiline tokens) 90117-func (p *Parsed) RuneCount(l, s, e uint32) uint32 { 90118- start := p.nls[l] + 1 + int(s) 90119- end := p.nls[l] + 1 + int(e) 90120- if e == 0 || end > p.nls[l+1] { 90121- end = p.nls[l+1] 90122- } 90123- return uint32(utf8.RuneCount(p.buf[start:end])) 90124-} 90125- 90126-// LineCol converts from a 0-based byte offset to 0-based line, col. col in runes 90127-func (p *Parsed) LineCol(x int) (uint32, uint32) { 90128- if x < p.check { 90129- p.lastnl = 0 90130- } 90131- p.check = x 90132- for i := p.lastnl; i < len(p.nls); i++ { 90133- if p.nls[i] <= x { 90134- continue 90135- } 90136- p.lastnl = i 90137- var count int 90138- if i > 0 && x == p.nls[i-1] { // \n 90139- count = 0 90140- } else { 90141- count = p.utf16len(p.buf[p.nls[i-1]+1 : x]) 90142- } 90143- return uint32(i - 1), uint32(count) 90144- } 90145- if x == len(p.buf)-1 { // trailing \n 90146- return uint32(len(p.nls) - 1), 0 90147- } 90148- // shouldn't happen 90149- for i := 1; i < 4; i++ { 90150- _, f, l, ok := runtime.Caller(i) 90151- if !ok { 90152- break 90153- } 90154- log.Printf("%d: %s:%d", i, f, l) 90155- } 90156- 90157- msg := fmt.Errorf("LineCol off the end, %d of %d, nls=%v, %q", x, len(p.buf), p.nls, p.buf[x:]) 90158- event.Error(context.Background(), "internal error", msg) 90159- return 0, 0 90160-} 90161- 90162-// Position produces a protocol.Position from an offset in the template 90163-func (p *Parsed) Position(pos int) protocol.Position { 90164- line, col := p.LineCol(pos) 90165- return protocol.Position{Line: line, Character: col} 90166-} 90167- 90168-func (p *Parsed) Range(x, length int) protocol.Range { 90169- line, col := p.LineCol(x) 90170- ans := protocol.Range{ 90171- Start: protocol.Position{Line: line, Character: col}, 90172- End: protocol.Position{Line: line, Character: col + uint32(length)}, 90173- } 90174- return ans 90175-} 90176- 90177-// FromPosition translates a protocol.Position into an offset into the template 90178-func (p *Parsed) FromPosition(x protocol.Position) int { 90179- l, c := int(x.Line), int(x.Character) 90180- if l >= len(p.nls) || p.nls[l]+1 >= len(p.buf) { 90181- // paranoia to avoid panic. return the largest offset 90182- return len(p.buf) 90183- } 90184- line := p.buf[p.nls[l]+1:] 90185- cnt := 0 90186- for w := range string(line) { 90187- if cnt >= c { 90188- return w + p.nls[l] + 1 90189- } 90190- cnt++ 90191- } 90192- // do we get here? NO 90193- pos := int(x.Character) + p.nls[int(x.Line)] + 1 90194- event.Error(context.Background(), "internal error", fmt.Errorf("surprise %#v", x)) 90195- return pos 90196-} 90197- 90198-func symAtPosition(fh source.FileHandle, loc protocol.Position) (*symbol, *Parsed, error) { 90199- buf, err := fh.Read() 90200- if err != nil { 90201- return nil, nil, err 90202- } 90203- p := parseBuffer(buf) 90204- pos := p.FromPosition(loc) 90205- syms := p.SymsAtPos(pos) 90206- if len(syms) == 0 { 90207- return nil, p, fmt.Errorf("no symbol found") 90208- } 90209- if len(syms) > 1 { 90210- log.Printf("Hover: %d syms, not 1 %v", len(syms), syms) 90211- } 90212- sym := syms[0] 90213- return &sym, p, nil 90214-} 90215- 90216-func (p *Parsed) SymsAtPos(pos int) []symbol { 90217- ans := []symbol{} 90218- for _, s := range p.symbols { 90219- if s.start <= pos && pos < s.start+s.length { 90220- ans = append(ans, s) 90221- } 90222- } 90223- return ans 90224-} 90225- 90226-type wrNode struct { 90227- p *Parsed 90228- w io.Writer 90229-} 90230- 90231-// WriteNode is for debugging 90232-func (p *Parsed) WriteNode(w io.Writer, n parse.Node) { 90233- wr := wrNode{p: p, w: w} 90234- wr.writeNode(n, "") 90235-} 90236- 90237-func (wr wrNode) writeNode(n parse.Node, indent string) { 90238- if n == nil { 90239- return 90240- } 90241- at := func(pos parse.Pos) string { 90242- line, col := wr.p.LineCol(int(pos)) 90243- return fmt.Sprintf("(%d)%v:%v", pos, line, col) 90244- } 90245- switch x := n.(type) { 90246- case *parse.ActionNode: 90247- fmt.Fprintf(wr.w, "%sActionNode at %s\n", indent, at(x.Pos)) 90248- wr.writeNode(x.Pipe, indent+". ") 90249- case *parse.BoolNode: 90250- fmt.Fprintf(wr.w, "%sBoolNode at %s, %v\n", indent, at(x.Pos), x.True) 90251- case *parse.BranchNode: 90252- fmt.Fprintf(wr.w, "%sBranchNode at %s\n", indent, at(x.Pos)) 90253- wr.writeNode(x.Pipe, indent+"Pipe. ") 90254- wr.writeNode(x.List, indent+"List. ") 90255- wr.writeNode(x.ElseList, indent+"Else. ") 90256- case *parse.ChainNode: 90257- fmt.Fprintf(wr.w, "%sChainNode at %s, %v\n", indent, at(x.Pos), x.Field) 90258- case *parse.CommandNode: 90259- fmt.Fprintf(wr.w, "%sCommandNode at %s, %d children\n", indent, at(x.Pos), len(x.Args)) 90260- for _, a := range x.Args { 90261- wr.writeNode(a, indent+". ") 90262- } 90263- //case *parse.CommentNode: // 1.16 90264- case *parse.DotNode: 90265- fmt.Fprintf(wr.w, "%sDotNode at %s\n", indent, at(x.Pos)) 90266- case *parse.FieldNode: 90267- fmt.Fprintf(wr.w, "%sFieldNode at %s, %v\n", indent, at(x.Pos), x.Ident) 90268- case *parse.IdentifierNode: 90269- fmt.Fprintf(wr.w, "%sIdentifierNode at %s, %v\n", indent, at(x.Pos), x.Ident) 90270- case *parse.IfNode: 90271- fmt.Fprintf(wr.w, "%sIfNode at %s\n", indent, at(x.Pos)) 90272- wr.writeNode(&x.BranchNode, indent+". ") 90273- case *parse.ListNode: 90274- if x == nil { 90275- return // nil BranchNode.ElseList 90276- } 90277- fmt.Fprintf(wr.w, "%sListNode at %s, %d children\n", indent, at(x.Pos), len(x.Nodes)) 90278- for _, n := range x.Nodes { 90279- wr.writeNode(n, indent+". ") 90280- } 90281- case *parse.NilNode: 90282- fmt.Fprintf(wr.w, "%sNilNode at %s\n", indent, at(x.Pos)) 90283- case *parse.NumberNode: 90284- fmt.Fprintf(wr.w, "%sNumberNode at %s, %s\n", indent, at(x.Pos), x.Text) 90285- case *parse.PipeNode: 90286- if x == nil { 90287- return // {{template "xxx"}} 90288- } 90289- fmt.Fprintf(wr.w, "%sPipeNode at %s, %d vars, %d cmds, IsAssign:%v\n", 90290- indent, at(x.Pos), len(x.Decl), len(x.Cmds), x.IsAssign) 90291- for _, d := range x.Decl { 90292- wr.writeNode(d, indent+"Decl. ") 90293- } 90294- for _, c := range x.Cmds { 90295- wr.writeNode(c, indent+"Cmd. ") 90296- } 90297- case *parse.RangeNode: 90298- fmt.Fprintf(wr.w, "%sRangeNode at %s\n", indent, at(x.Pos)) 90299- wr.writeNode(&x.BranchNode, indent+". ") 90300- case *parse.StringNode: 90301- fmt.Fprintf(wr.w, "%sStringNode at %s, %s\n", indent, at(x.Pos), x.Quoted) 90302- case *parse.TemplateNode: 90303- fmt.Fprintf(wr.w, "%sTemplateNode at %s, %s\n", indent, at(x.Pos), x.Name) 90304- wr.writeNode(x.Pipe, indent+". ") 90305- case *parse.TextNode: 90306- fmt.Fprintf(wr.w, "%sTextNode at %s, len %d\n", indent, at(x.Pos), len(x.Text)) 90307- case *parse.VariableNode: 90308- fmt.Fprintf(wr.w, "%sVariableNode at %s, %v\n", indent, at(x.Pos), x.Ident) 90309- case *parse.WithNode: 90310- fmt.Fprintf(wr.w, "%sWithNode at %s\n", indent, at(x.Pos)) 90311- wr.writeNode(&x.BranchNode, indent+". ") 90312- } 90313-} 90314- 90315-var kindNames = []string{"", "File", "Module", "Namespace", "Package", "Class", "Method", "Property", 90316- "Field", "Constructor", "Enum", "Interface", "Function", "Variable", "Constant", "String", 90317- "Number", "Boolean", "Array", "Object", "Key", "Null", "EnumMember", "Struct", "Event", 90318- "Operator", "TypeParameter"} 90319- 90320-func kindStr(k protocol.SymbolKind) string { 90321- n := int(k) 90322- if n < 1 || n >= len(kindNames) { 90323- return fmt.Sprintf("?SymbolKind %d?", n) 90324- } 90325- return kindNames[n] 90326-} 90327diff -urN a/gopls/internal/lsp/template/parse_test.go b/gopls/internal/lsp/template/parse_test.go 90328--- a/gopls/internal/lsp/template/parse_test.go 2000-01-01 00:00:00.000000000 -0000 90329+++ b/gopls/internal/lsp/template/parse_test.go 1970-01-01 00:00:00.000000000 +0000 90330@@ -1,238 +0,0 @@ 90331-// Copyright 2021 The Go Authors. All rights reserved. 90332-// Use of this source code is governed by a BSD-style 90333-// license that can be found in the LICENSE file. 90334- 90335-package template 90336- 90337-import ( 90338- "strings" 90339- "testing" 90340-) 90341- 90342-type datum struct { 90343- buf string 90344- cnt int 90345- syms []string // the symbols in the parse of buf 90346-} 90347- 90348-var tmpl = []datum{{` 90349-{{if (foo .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} 90350-{{$A.X 12}} 90351-{{foo (.X.Y) 23 ($A.Zü)}} 90352-{{end}}`, 1, []string{"{7,3,foo,Function,false}", "{12,1,X,Method,false}", 90353- "{14,1,Y,Method,false}", "{21,2,$A,Variable,true}", "{26,2,,String,false}", 90354- "{35,1,Z,Method,false}", "{38,2,$A,Variable,false}", 90355- "{53,2,$A,Variable,false}", "{56,1,X,Method,false}", "{57,2,,Number,false}", 90356- "{64,3,foo,Function,false}", "{70,1,X,Method,false}", 90357- "{72,1,Y,Method,false}", "{75,2,,Number,false}", "{80,2,$A,Variable,false}", 90358- "{83,2,Zü,Method,false}", "{94,3,,Constant,false}"}}, 90359- 90360- {`{{define "zzz"}}{{.}}{{end}} 90361-{{template "zzz"}}`, 2, []string{"{10,3,zzz,Namespace,true}", "{18,1,dot,Variable,false}", 90362- "{41,3,zzz,Package,false}"}}, 90363- 90364- {`{{block "aaa" foo}}b{{end}}`, 2, []string{"{9,3,aaa,Namespace,true}", 90365- "{9,3,aaa,Package,false}", "{14,3,foo,Function,false}", "{19,1,,Constant,false}"}}, 90366- {"", 0, nil}, 90367-} 90368- 90369-func TestSymbols(t *testing.T) { 90370- for i, x := range tmpl { 90371- got := parseBuffer([]byte(x.buf)) 90372- if got.ParseErr != nil { 90373- t.Errorf("error:%v", got.ParseErr) 90374- continue 90375- } 90376- if len(got.named) != x.cnt { 90377- t.Errorf("%d: got %d, expected %d", i, len(got.named), x.cnt) 90378- } 90379- for n, s := range got.symbols { 90380- if s.String() != x.syms[n] { 90381- t.Errorf("%d: got %s, expected %s", i, s.String(), x.syms[n]) 90382- } 90383- } 90384- } 90385-} 90386- 90387-func TestWordAt(t *testing.T) { 90388- want := []string{"", "", "$A", "$A", "", "", "", "", "", "", 90389- "", "", "", "if", "if", "", "$A", "$A", "", "", 90390- "B", "", "", "end", "end", "end", "", "", ""} 90391- p := parseBuffer([]byte("{{$A := .}}{{if $A}}B{{end}}")) 90392- for i := 0; i < len(p.buf); i++ { 90393- got := findWordAt(p, i) 90394- if got != want[i] { 90395- t.Errorf("for %d, got %q, wanted %q", i, got, want[i]) 90396- } 90397- } 90398-} 90399- 90400-func TestNLS(t *testing.T) { 90401- buf := `{{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} 90402- {{$A.X 12}} 90403- {{foo (.X.Y) 23 ($A.Z)}} 90404- {{end}} 90405- ` 90406- p := parseBuffer([]byte(buf)) 90407- if p.ParseErr != nil { 90408- t.Fatal(p.ParseErr) 90409- } 90410- // line 0 doesn't have a \n in front of it 90411- for i := 1; i < len(p.nls)-1; i++ { 90412- if buf[p.nls[i]] != '\n' { 90413- t.Errorf("line %d got %c", i, buf[p.nls[i]]) 90414- } 90415- } 90416- // fake line at end of file 90417- if p.nls[len(p.nls)-1] != len(buf) { 90418- t.Errorf("got %d expected %d", p.nls[len(p.nls)-1], len(buf)) 90419- } 90420-} 90421- 90422-func TestLineCol(t *testing.T) { 90423- buf := `{{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} 90424- {{$A.X 12}} 90425- {{foo (.X.Y) 23 ($A.Z)}} 90426- {{end}}` 90427- if false { 90428- t.Error(buf) 90429- } 90430- for n, cx := range tmpl { 90431- buf := cx.buf 90432- p := parseBuffer([]byte(buf)) 90433- if p.ParseErr != nil { 90434- t.Fatal(p.ParseErr) 90435- } 90436- type loc struct { 90437- offset int 90438- l, c uint32 90439- } 90440- saved := []loc{} 90441- // forwards 90442- var lastl, lastc uint32 90443- for offset := range buf { 90444- l, c := p.LineCol(offset) 90445- saved = append(saved, loc{offset, l, c}) 90446- if l > lastl { 90447- lastl = l 90448- if c != 0 { 90449- t.Errorf("line %d, got %d instead of 0", l, c) 90450- } 90451- } 90452- if c > lastc { 90453- lastc = c 90454- } 90455- } 90456- lines := strings.Split(buf, "\n") 90457- mxlen := -1 90458- for _, l := range lines { 90459- if len(l) > mxlen { 90460- mxlen = len(l) 90461- } 90462- } 90463- if int(lastl) != len(lines)-1 && int(lastc) != mxlen { 90464- // lastl is 0 if there is only 1 line(?) 90465- t.Errorf("expected %d, %d, got %d, %d for case %d", len(lines)-1, mxlen, lastl, lastc, n) 90466- } 90467- // backwards 90468- for j := len(saved) - 1; j >= 0; j-- { 90469- s := saved[j] 90470- xl, xc := p.LineCol(s.offset) 90471- if xl != s.l || xc != s.c { 90472- t.Errorf("at offset %d(%d), got (%d,%d), expected (%d,%d)", s.offset, j, xl, xc, s.l, s.c) 90473- } 90474- } 90475- } 90476-} 90477- 90478-func TestLineColNL(t *testing.T) { 90479- buf := "\n\n\n\n\n" 90480- p := parseBuffer([]byte(buf)) 90481- if p.ParseErr != nil { 90482- t.Fatal(p.ParseErr) 90483- } 90484- for i := 0; i < len(buf); i++ { 90485- l, c := p.LineCol(i) 90486- if c != 0 || int(l) != i+1 { 90487- t.Errorf("got (%d,%d), expected (%d,0)", l, c, i) 90488- } 90489- } 90490-} 90491- 90492-func TestPos(t *testing.T) { 90493- buf := ` 90494- {{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} 90495- {{$A.X 12}} 90496- {{foo (.X.Y) 23 ($A.Z)}} 90497- {{end}}` 90498- p := parseBuffer([]byte(buf)) 90499- if p.ParseErr != nil { 90500- t.Fatal(p.ParseErr) 90501- } 90502- for pos, r := range buf { 90503- if r == '\n' { 90504- continue 90505- } 90506- x := p.Position(pos) 90507- n := p.FromPosition(x) 90508- if n != pos { 90509- // once it's wrong, it will be wrong forever 90510- t.Fatalf("at pos %d (rune %c) got %d {%#v]", pos, r, n, x) 90511- } 90512- 90513- } 90514-} 90515-func TestLen(t *testing.T) { 90516- data := []struct { 90517- cnt int 90518- v string 90519- }{{1, "a"}, {1, "膈"}, {4, ""}, {7, "34567"}} 90520- p := &Parsed{nonASCII: true} 90521- for _, d := range data { 90522- got := p.utf16len([]byte(d.v)) 90523- if got != d.cnt { 90524- t.Errorf("%v, got %d wanted %d", d, got, d.cnt) 90525- } 90526- } 90527-} 90528- 90529-func TestUtf16(t *testing.T) { 90530- buf := ` 90531- {{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} 90532- {{$A.X 12}} 90533- {{foo (.X.Y) 23 ($A.Z)}} 90534- {{end}}` 90535- p := parseBuffer([]byte(buf)) 90536- if p.nonASCII == false { 90537- t.Error("expected nonASCII to be true") 90538- } 90539-} 90540- 90541-type ttest struct { 90542- tmpl string 90543- tokCnt int 90544- elidedCnt int8 90545-} 90546- 90547-func TestQuotes(t *testing.T) { 90548- tsts := []ttest{ 90549- {"{{- /*comment*/ -}}", 1, 0}, 90550- {"{{/*`\ncomment\n`*/}}", 1, 0}, 90551- //{"{{foo\nbar}}\n", 1, 0}, // this action spanning lines parses in 1.16 90552- {"{{\"{{foo}}{{\"}}", 1, 0}, 90553- {"{{\n{{- when}}", 1, 1}, // corrected 90554- {"{{{{if .}}xx{{\n{{end}}", 2, 2}, // corrected 90555- } 90556- for _, s := range tsts { 90557- p := parseBuffer([]byte(s.tmpl)) 90558- if len(p.tokens) != s.tokCnt { 90559- t.Errorf("%q: got %d tokens, expected %d", s, len(p.tokens), s.tokCnt) 90560- } 90561- if p.ParseErr != nil { 90562- t.Errorf("%q: %v", string(p.buf), p.ParseErr) 90563- } 90564- if len(p.elided) != int(s.elidedCnt) { 90565- t.Errorf("%q: elided %d, expected %d", s, len(p.elided), s.elidedCnt) 90566- } 90567- } 90568-} 90569diff -urN a/gopls/internal/lsp/template/symbols.go b/gopls/internal/lsp/template/symbols.go 90570--- a/gopls/internal/lsp/template/symbols.go 2000-01-01 00:00:00.000000000 -0000 90571+++ b/gopls/internal/lsp/template/symbols.go 1970-01-01 00:00:00.000000000 +0000 90572@@ -1,230 +0,0 @@ 90573-// Copyright 2021 The Go Authors. All rights reserved. 90574-// Use of this source code is governed by a BSD-style 90575-// license that can be found in the LICENSE file. 90576- 90577-package template 90578- 90579-import ( 90580- "bytes" 90581- "context" 90582- "fmt" 90583- "text/template/parse" 90584- "unicode/utf8" 90585- 90586- "golang.org/x/tools/internal/event" 90587- "golang.org/x/tools/gopls/internal/lsp/protocol" 90588- "golang.org/x/tools/gopls/internal/lsp/source" 90589-) 90590- 90591-// in local coordinates, to be translated to protocol.DocumentSymbol 90592-type symbol struct { 90593- start int // for sorting 90594- length int // in runes (unicode code points) 90595- name string 90596- kind protocol.SymbolKind 90597- vardef bool // is this a variable definition? 90598- // do we care about selection range, or children? 90599- // no children yet, and selection range is the same as range 90600-} 90601- 90602-func (s symbol) String() string { 90603- return fmt.Sprintf("{%d,%d,%s,%s,%v}", s.start, s.length, s.name, s.kind, s.vardef) 90604-} 90605- 90606-// for FieldNode or VariableNode (or ChainNode?) 90607-func (p *Parsed) fields(flds []string, x parse.Node) []symbol { 90608- ans := []symbol{} 90609- // guessing that there are no embedded blanks allowed. The doc is unclear 90610- lookfor := "" 90611- switch x.(type) { 90612- case *parse.FieldNode: 90613- for _, f := range flds { 90614- lookfor += "." + f // quadratic, but probably ok 90615- } 90616- case *parse.VariableNode: 90617- lookfor = flds[0] 90618- for i := 1; i < len(flds); i++ { 90619- lookfor += "." + flds[i] 90620- } 90621- case *parse.ChainNode: // PJW, what are these? 90622- for _, f := range flds { 90623- lookfor += "." + f // quadratic, but probably ok 90624- } 90625- default: 90626- // If these happen they will happen even if gopls is restarted 90627- // and the users does the same thing, so it is better not to panic. 90628- // context.Background() is used because we don't have access 90629- // to any other context. [we could, but it would be complicated] 90630- event.Log(context.Background(), fmt.Sprintf("%T unexpected in fields()", x)) 90631- return nil 90632- } 90633- if len(lookfor) == 0 { 90634- event.Log(context.Background(), fmt.Sprintf("no strings in fields() %#v", x)) 90635- return nil 90636- } 90637- startsAt := int(x.Position()) 90638- ix := bytes.Index(p.buf[startsAt:], []byte(lookfor)) // HasPrefix? PJW? 90639- if ix < 0 || ix > len(lookfor) { // lookfor expected to be at start (or so) 90640- // probably golang.go/#43388, so back up 90641- startsAt -= len(flds[0]) + 1 90642- ix = bytes.Index(p.buf[startsAt:], []byte(lookfor)) // ix might be 1? PJW 90643- if ix < 0 { 90644- return ans 90645- } 90646- } 90647- at := ix + startsAt 90648- for _, f := range flds { 90649- at += 1 // . 90650- kind := protocol.Method 90651- if f[0] == '$' { 90652- kind = protocol.Variable 90653- } 90654- sym := symbol{name: f, kind: kind, start: at, length: utf8.RuneCount([]byte(f))} 90655- if kind == protocol.Variable && len(p.stack) > 1 { 90656- if pipe, ok := p.stack[len(p.stack)-2].(*parse.PipeNode); ok { 90657- for _, y := range pipe.Decl { 90658- if x == y { 90659- sym.vardef = true 90660- } 90661- } 90662- } 90663- } 90664- ans = append(ans, sym) 90665- at += len(f) 90666- } 90667- return ans 90668-} 90669- 90670-func (p *Parsed) findSymbols() { 90671- if len(p.stack) == 0 { 90672- return 90673- } 90674- n := p.stack[len(p.stack)-1] 90675- pop := func() { 90676- p.stack = p.stack[:len(p.stack)-1] 90677- } 90678- if n == nil { // allowing nil simplifies the code 90679- pop() 90680- return 90681- } 90682- nxt := func(nd parse.Node) { 90683- p.stack = append(p.stack, nd) 90684- p.findSymbols() 90685- } 90686- switch x := n.(type) { 90687- case *parse.ActionNode: 90688- nxt(x.Pipe) 90689- case *parse.BoolNode: 90690- // need to compute the length from the value 90691- msg := fmt.Sprintf("%v", x.True) 90692- p.symbols = append(p.symbols, symbol{start: int(x.Pos), length: len(msg), kind: protocol.Boolean}) 90693- case *parse.BranchNode: 90694- nxt(x.Pipe) 90695- nxt(x.List) 90696- nxt(x.ElseList) 90697- case *parse.ChainNode: 90698- p.symbols = append(p.symbols, p.fields(x.Field, x)...) 90699- nxt(x.Node) 90700- case *parse.CommandNode: 90701- for _, a := range x.Args { 90702- nxt(a) 90703- } 90704- //case *parse.CommentNode: // go 1.16 90705- // log.Printf("implement %d", x.Type()) 90706- case *parse.DotNode: 90707- sym := symbol{name: "dot", kind: protocol.Variable, start: int(x.Pos), length: 1} 90708- p.symbols = append(p.symbols, sym) 90709- case *parse.FieldNode: 90710- p.symbols = append(p.symbols, p.fields(x.Ident, x)...) 90711- case *parse.IdentifierNode: 90712- sym := symbol{name: x.Ident, kind: protocol.Function, start: int(x.Pos), 90713- length: utf8.RuneCount([]byte(x.Ident))} 90714- p.symbols = append(p.symbols, sym) 90715- case *parse.IfNode: 90716- nxt(&x.BranchNode) 90717- case *parse.ListNode: 90718- if x != nil { // wretched typed nils. Node should have an IfNil 90719- for _, nd := range x.Nodes { 90720- nxt(nd) 90721- } 90722- } 90723- case *parse.NilNode: 90724- sym := symbol{name: "nil", kind: protocol.Constant, start: int(x.Pos), length: 3} 90725- p.symbols = append(p.symbols, sym) 90726- case *parse.NumberNode: 90727- // no name; ascii 90728- p.symbols = append(p.symbols, symbol{start: int(x.Pos), length: len(x.Text), kind: protocol.Number}) 90729- case *parse.PipeNode: 90730- if x == nil { // {{template "foo"}} 90731- return 90732- } 90733- for _, d := range x.Decl { 90734- nxt(d) 90735- } 90736- for _, c := range x.Cmds { 90737- nxt(c) 90738- } 90739- case *parse.RangeNode: 90740- nxt(&x.BranchNode) 90741- case *parse.StringNode: 90742- // no name 90743- sz := utf8.RuneCount([]byte(x.Text)) 90744- p.symbols = append(p.symbols, symbol{start: int(x.Pos), length: sz, kind: protocol.String}) 90745- case *parse.TemplateNode: // invoking a template 90746- // x.Pos points to the quote before the name 90747- p.symbols = append(p.symbols, symbol{name: x.Name, kind: protocol.Package, start: int(x.Pos) + 1, 90748- length: utf8.RuneCount([]byte(x.Name))}) 90749- nxt(x.Pipe) 90750- case *parse.TextNode: 90751- if len(x.Text) == 1 && x.Text[0] == '\n' { 90752- break 90753- } 90754- // nothing to report, but build one for hover 90755- sz := utf8.RuneCount([]byte(x.Text)) 90756- p.symbols = append(p.symbols, symbol{start: int(x.Pos), length: sz, kind: protocol.Constant}) 90757- case *parse.VariableNode: 90758- p.symbols = append(p.symbols, p.fields(x.Ident, x)...) 90759- case *parse.WithNode: 90760- nxt(&x.BranchNode) 90761- 90762- } 90763- pop() 90764-} 90765- 90766-// DocumentSymbols returns a hierarchy of the symbols defined in a template file. 90767-// (The hierarchy is flat. SymbolInformation might be better.) 90768-func DocumentSymbols(snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentSymbol, error) { 90769- buf, err := fh.Read() 90770- if err != nil { 90771- return nil, err 90772- } 90773- p := parseBuffer(buf) 90774- if p.ParseErr != nil { 90775- return nil, p.ParseErr 90776- } 90777- var ans []protocol.DocumentSymbol 90778- for _, s := range p.symbols { 90779- if s.kind == protocol.Constant { 90780- continue 90781- } 90782- d := kindStr(s.kind) 90783- if d == "Namespace" { 90784- d = "Template" 90785- } 90786- if s.vardef { 90787- d += "(def)" 90788- } else { 90789- d += "(use)" 90790- } 90791- r := p.Range(s.start, s.length) 90792- y := protocol.DocumentSymbol{ 90793- Name: s.name, 90794- Detail: d, 90795- Kind: s.kind, 90796- Range: r, 90797- SelectionRange: r, // or should this be the entire {{...}}? 90798- } 90799- ans = append(ans, y) 90800- } 90801- return ans, nil 90802-} 90803diff -urN a/gopls/internal/lsp/testdata/addimport/addimport.go.golden b/gopls/internal/lsp/testdata/addimport/addimport.go.golden 90804--- a/gopls/internal/lsp/testdata/addimport/addimport.go.golden 2000-01-01 00:00:00.000000000 -0000 90805+++ b/gopls/internal/lsp/testdata/addimport/addimport.go.golden 1970-01-01 00:00:00.000000000 +0000 90806@@ -1,7 +0,0 @@ 90807--- addimport -- 90808-package addimport //@addimport("", "bytes") 90809- 90810-import "bytes" 90811- 90812-func main() {} 90813- 90814diff -urN a/gopls/internal/lsp/testdata/addimport/addimport.go.in b/gopls/internal/lsp/testdata/addimport/addimport.go.in 90815--- a/gopls/internal/lsp/testdata/addimport/addimport.go.in 2000-01-01 00:00:00.000000000 -0000 90816+++ b/gopls/internal/lsp/testdata/addimport/addimport.go.in 1970-01-01 00:00:00.000000000 +0000 90817@@ -1,3 +0,0 @@ 90818-package addimport //@addimport("", "bytes") 90819- 90820-func main() {} 90821diff -urN a/gopls/internal/lsp/testdata/address/address.go b/gopls/internal/lsp/testdata/address/address.go 90822--- a/gopls/internal/lsp/testdata/address/address.go 2000-01-01 00:00:00.000000000 -0000 90823+++ b/gopls/internal/lsp/testdata/address/address.go 1970-01-01 00:00:00.000000000 +0000 90824@@ -1,78 +0,0 @@ 90825-package address 90826- 90827-func wantsPtr(*int) {} 90828-func wantsVariadicPtr(...*int) {} 90829- 90830-func wantsVariadic(...int) {} 90831- 90832-type foo struct{ c int } //@item(addrFieldC, "c", "int", "field") 90833- 90834-func _() { 90835- var ( 90836- a string //@item(addrA, "a", "string", "var") 90837- b int //@item(addrB, "b", "int", "var") 90838- ) 90839- 90840- wantsPtr() //@rank(")", addrB, addrA),snippet(")", addrB, "&b", "&b") 90841- wantsPtr(&b) //@snippet(")", addrB, "b", "b") 90842- 90843- wantsVariadicPtr() //@rank(")", addrB, addrA),snippet(")", addrB, "&b", "&b") 90844- 90845- var s foo 90846- s.c //@item(addrDeepC, "s.c", "int", "field") 90847- wantsPtr() //@snippet(")", addrDeepC, "&s.c", "&s.c") 90848- wantsPtr(s) //@snippet(")", addrDeepC, "&s.c", "&s.c") 90849- wantsPtr(&s) //@snippet(")", addrDeepC, "s.c", "s.c") 90850- 90851- // don't add "&" in item (it gets added as an additional edit) 90852- wantsPtr(&s.c) //@snippet(")", addrFieldC, "c", "c") 90853- 90854- // check dereferencing as well 90855- var c *int //@item(addrCPtr, "c", "*int", "var") 90856- var _ int = _ //@rank("_ //", addrCPtr, addrA),snippet("_ //", addrCPtr, "*c", "*c") 90857- 90858- wantsVariadic() //@rank(")", addrCPtr, addrA),snippet(")", addrCPtr, "*c", "*c") 90859- 90860- var d **int //@item(addrDPtr, "d", "**int", "var") 90861- var _ int = _ //@rank("_ //", addrDPtr, addrA),snippet("_ //", addrDPtr, "**d", "**d") 90862- 90863- type namedPtr *int 90864- var np namedPtr //@item(addrNamedPtr, "np", "namedPtr", "var") 90865- 90866- var _ int = _ //@rank("_ //", addrNamedPtr, addrA) 90867- 90868- // don't get tripped up by recursive pointer type 90869- type dontMessUp *dontMessUp 90870- var dmu *dontMessUp //@item(addrDMU, "dmu", "*dontMessUp", "var") 90871- 90872- var _ int = dmu //@complete(" //", addrDMU) 90873-} 90874- 90875-func (f foo) ptr() *foo { return &f } 90876- 90877-func _() { 90878- getFoo := func() foo { return foo{} } 90879- 90880- // not addressable 90881- getFoo().c //@item(addrGetFooC, "getFoo().c", "int", "field") 90882- 90883- // addressable 90884- getFoo().ptr().c //@item(addrGetFooPtrC, "getFoo().ptr().c", "int", "field") 90885- 90886- wantsPtr() //@rank(addrGetFooPtrC, addrGetFooC),snippet(")", addrGetFooPtrC, "&getFoo().ptr().c", "&getFoo().ptr().c") 90887- wantsPtr(&g) //@rank(addrGetFooPtrC, addrGetFooC),snippet(")", addrGetFooPtrC, "getFoo().ptr().c", "getFoo().ptr().c") 90888-} 90889- 90890-type nested struct { 90891- f foo 90892-} 90893- 90894-func _() { 90895- getNested := func() nested { return nested{} } 90896- 90897- getNested().f.c //@item(addrNestedC, "getNested().f.c", "int", "field") 90898- getNested().f.ptr().c //@item(addrNestedPtrC, "getNested().f.ptr().c", "int", "field") 90899- 90900- // addrNestedC is not addressable, so rank lower 90901- wantsPtr(getNestedfc) //@fuzzy(")", addrNestedPtrC, addrNestedC) 90902-} 90903diff -urN a/gopls/internal/lsp/testdata/analyzer/bad_test.go b/gopls/internal/lsp/testdata/analyzer/bad_test.go 90904--- a/gopls/internal/lsp/testdata/analyzer/bad_test.go 2000-01-01 00:00:00.000000000 -0000 90905+++ b/gopls/internal/lsp/testdata/analyzer/bad_test.go 1970-01-01 00:00:00.000000000 +0000 90906@@ -1,24 +0,0 @@ 90907-package analyzer 90908- 90909-import ( 90910- "fmt" 90911- "sync" 90912- "testing" 90913- "time" 90914-) 90915- 90916-func Testbad(t *testing.T) { //@diag("", "tests", "Testbad has malformed name: first letter after 'Test' must not be lowercase", "warning") 90917- var x sync.Mutex 90918- _ = x //@diag("x", "copylocks", "assignment copies lock value to _: sync.Mutex", "warning") 90919- 90920- printfWrapper("%s") //@diag(re`printfWrapper\(.*\)`, "printf", "golang.org/lsptests/analyzer.printfWrapper format %s reads arg #1, but call has 0 args", "warning") 90921-} 90922- 90923-func printfWrapper(format string, args ...interface{}) { 90924- fmt.Printf(format, args...) 90925-} 90926- 90927-func _() { 90928- now := time.Now() 90929- fmt.Println(now.Format("2006-02-01")) //@diag("2006-02-01", "timeformat", "2006-02-01 should be 2006-01-02", "warning") 90930-} 90931diff -urN a/gopls/internal/lsp/testdata/anon/anon.go.in b/gopls/internal/lsp/testdata/anon/anon.go.in 90932--- a/gopls/internal/lsp/testdata/anon/anon.go.in 2000-01-01 00:00:00.000000000 -0000 90933+++ b/gopls/internal/lsp/testdata/anon/anon.go.in 1970-01-01 00:00:00.000000000 +0000 90934@@ -1,23 +0,0 @@ 90935-package anon 90936- 90937-func _() { 90938- for _, _ := range []struct { 90939- i, j int //@item(anonI, "i", "int", "field"),item(anonJ, "j", "int", "field") 90940- }{ 90941- { 90942- i: 1, 90943- //@complete("", anonJ) 90944- }, 90945- { 90946- //@complete("", anonI, anonJ) 90947- }, 90948- } { 90949- continue 90950- } 90951- 90952- s := struct{ f int }{ } //@item(anonF, "f", "int", "field"),item(structS, "s", "struct{...}", "var"),complete(" }", anonF) 90953- 90954- _ = map[struct{ x int }]int{ //@item(anonX, "x", "int", "field") 90955- struct{ x int }{ }: 1, //@complete(" }", anonX, structS) 90956- } 90957-} 90958diff -urN a/gopls/internal/lsp/testdata/append/append2.go.in b/gopls/internal/lsp/testdata/append/append2.go.in 90959--- a/gopls/internal/lsp/testdata/append/append2.go.in 2000-01-01 00:00:00.000000000 -0000 90960+++ b/gopls/internal/lsp/testdata/append/append2.go.in 1970-01-01 00:00:00.000000000 +0000 90961@@ -1,5 +0,0 @@ 90962-package append 90963- 90964-func _() { 90965- _ = append(a, struct) //@complete(")") 90966-} 90967\ No newline at end of file 90968diff -urN a/gopls/internal/lsp/testdata/append/append.go b/gopls/internal/lsp/testdata/append/append.go 90969--- a/gopls/internal/lsp/testdata/append/append.go 2000-01-01 00:00:00.000000000 -0000 90970+++ b/gopls/internal/lsp/testdata/append/append.go 1970-01-01 00:00:00.000000000 +0000 90971@@ -1,38 +0,0 @@ 90972-package append 90973- 90974-func foo([]string) {} 90975-func bar(...string) {} 90976- 90977-func _() { 90978- var ( 90979- aInt []int //@item(appendInt, "aInt", "[]int", "var") 90980- aStrings []string //@item(appendStrings, "aStrings", "[]string", "var") 90981- aString string //@item(appendString, "aString", "string", "var") 90982- ) 90983- 90984- append(aStrings, a) //@rank(")", appendString, appendInt) 90985- var _ interface{} = append(aStrings, a) //@rank(")", appendString, appendInt) 90986- var _ []string = append(oops, a) //@rank(")", appendString, appendInt) 90987- 90988- foo(append()) //@rank("))", appendStrings, appendInt),rank("))", appendStrings, appendString) 90989- foo(append([]string{}, a)) //@rank("))", appendStrings, appendInt),rank("))", appendString, appendInt),snippet("))", appendStrings, "aStrings...", "aStrings...") 90990- foo(append([]string{}, "", a)) //@rank("))", appendString, appendInt),rank("))", appendString, appendStrings) 90991- 90992- // Don't add "..." to append() argument. 90993- bar(append()) //@snippet("))", appendStrings, "aStrings", "aStrings") 90994- 90995- type baz struct{} 90996- baz{} //@item(appendBazLiteral, "baz{}", "", "var") 90997- var bazzes []baz //@item(appendBazzes, "bazzes", "[]baz", "var") 90998- var bazzy baz //@item(appendBazzy, "bazzy", "baz", "var") 90999- bazzes = append(bazzes, ba) //@rank(")", appendBazzy, appendBazLiteral, appendBazzes) 91000- 91001- var b struct{ b []baz } 91002- b.b //@item(appendNestedBaz, "b.b", "[]baz", "field") 91003- b.b = append(b.b, b) //@rank(")", appendBazzy, appendBazLiteral, appendNestedBaz) 91004- 91005- var aStringsPtr *[]string //@item(appendStringsPtr, "aStringsPtr", "*[]string", "var") 91006- foo(append([]string{}, a)) //@snippet("))", appendStringsPtr, "*aStringsPtr...", "*aStringsPtr...") 91007- 91008- foo(append([]string{}, *a)) //@snippet("))", appendStringsPtr, "aStringsPtr...", "aStringsPtr...") 91009-} 91010diff -urN a/gopls/internal/lsp/testdata/arraytype/array_type.go.in b/gopls/internal/lsp/testdata/arraytype/array_type.go.in 91011--- a/gopls/internal/lsp/testdata/arraytype/array_type.go.in 2000-01-01 00:00:00.000000000 -0000 91012+++ b/gopls/internal/lsp/testdata/arraytype/array_type.go.in 1970-01-01 00:00:00.000000000 +0000 91013@@ -1,50 +0,0 @@ 91014-package arraytype 91015- 91016-import ( 91017- "golang.org/lsptests/foo" 91018-) 91019- 91020-func _() { 91021- var ( 91022- val string //@item(atVal, "val", "string", "var") 91023- ) 91024- 91025- // disabled - see issue #54822 91026- [] // complete(" //", PackageFoo) 91027- 91028- []val //@complete(" //") 91029- 91030- []foo.StructFoo //@complete(" //", StructFoo) 91031- 91032- []foo.StructFoo(nil) //@complete("(", StructFoo) 91033- 91034- []*foo.StructFoo //@complete(" //", StructFoo) 91035- 91036- [...]foo.StructFoo //@complete(" //", StructFoo) 91037- 91038- [2][][4]foo.StructFoo //@complete(" //", StructFoo) 91039- 91040- []struct { f []foo.StructFoo } //@complete(" }", StructFoo) 91041-} 91042- 91043-func _() { 91044- type myInt int //@item(atMyInt, "myInt", "int", "type") 91045- 91046- var mark []myInt //@item(atMark, "mark", "[]myInt", "var") 91047- 91048- var s []myInt //@item(atS, "s", "[]myInt", "var") 91049- s = []m //@complete(" //", atMyInt) 91050- // disabled - see issue #54822 91051- s = [] // complete(" //", atMyInt, PackageFoo) 91052- 91053- var a [1]myInt 91054- a = [1]m //@complete(" //", atMyInt) 91055- 91056- var ds [][]myInt 91057- ds = [][]m //@complete(" //", atMyInt) 91058-} 91059- 91060-func _() { 91061- var b [0]byte //@item(atByte, "b", "[0]byte", "var") 91062- var _ []byte = b //@snippet(" //", atByte, "b[:]", "b[:]") 91063-} 91064diff -urN a/gopls/internal/lsp/testdata/assign/assign.go.in b/gopls/internal/lsp/testdata/assign/assign.go.in 91065--- a/gopls/internal/lsp/testdata/assign/assign.go.in 2000-01-01 00:00:00.000000000 -0000 91066+++ b/gopls/internal/lsp/testdata/assign/assign.go.in 1970-01-01 00:00:00.000000000 +0000 91067@@ -1,26 +0,0 @@ 91068-package assign 91069- 91070-import "golang.org/lsptests/assign/internal/secret" 91071- 91072-func _() { 91073- secret.Hello() 91074- var ( 91075- myInt int //@item(assignInt, "myInt", "int", "var") 91076- myStr string //@item(assignStr, "myStr", "string", "var") 91077- ) 91078- 91079- var _ string = my //@rank(" //", assignStr, assignInt) 91080- var _ string = //@rank(" //", assignStr, assignInt) 91081-} 91082- 91083-func _() { 91084- var a string = a //@complete(" //") 91085-} 91086- 91087-func _() { 91088- fooBar := fooBa //@complete(" //"),item(assignFooBar, "fooBar", "", "var") 91089- abc, fooBar := 123, fooBa //@complete(" //", assignFooBar) 91090- { 91091- fooBar := fooBa //@complete(" //", assignFooBar) 91092- } 91093-} 91094diff -urN a/gopls/internal/lsp/testdata/assign/internal/secret/secret.go b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go 91095--- a/gopls/internal/lsp/testdata/assign/internal/secret/secret.go 2000-01-01 00:00:00.000000000 -0000 91096+++ b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go 1970-01-01 00:00:00.000000000 +0000 91097@@ -1,3 +0,0 @@ 91098-package secret 91099- 91100-func Hello() {} 91101\ No newline at end of file 91102diff -urN a/gopls/internal/lsp/testdata/bad/bad0.go b/gopls/internal/lsp/testdata/bad/bad0.go 91103--- a/gopls/internal/lsp/testdata/bad/bad0.go 2000-01-01 00:00:00.000000000 -0000 91104+++ b/gopls/internal/lsp/testdata/bad/bad0.go 1970-01-01 00:00:00.000000000 +0000 91105@@ -1,24 +0,0 @@ 91106-//go:build go1.11 91107-// +build go1.11 91108- 91109-package bad 91110- 91111-import _ "golang.org/lsptests/assign/internal/secret" //@diag("\"golang.org/lsptests/assign/internal/secret\"", "compiler", "could not import golang.org/lsptests/assign/internal/secret \\(invalid use of internal package \"golang.org/lsptests/assign/internal/secret\"\\)", "error") 91112- 91113-func stuff() { //@item(stuff, "stuff", "func()", "func") 91114- x := "heeeeyyyy" 91115- random2(x) //@diag("x", "compiler", "cannot use x \\(variable of type string\\) as int value in argument to random2", "error") 91116- random2(1) //@complete("dom", random, random2, random3) 91117- y := 3 //@diag("y", "compiler", "y declared (and|but) not used", "error") 91118-} 91119- 91120-type bob struct { //@item(bob, "bob", "struct{...}", "struct") 91121- x int 91122-} 91123- 91124-func _() { 91125- var q int 91126- _ = &bob{ 91127- f: q, //@diag("f: q", "compiler", "unknown field f in struct literal", "error") 91128- } 91129-} 91130diff -urN a/gopls/internal/lsp/testdata/bad/bad1.go b/gopls/internal/lsp/testdata/bad/bad1.go 91131--- a/gopls/internal/lsp/testdata/bad/bad1.go 2000-01-01 00:00:00.000000000 -0000 91132+++ b/gopls/internal/lsp/testdata/bad/bad1.go 1970-01-01 00:00:00.000000000 +0000 91133@@ -1,34 +0,0 @@ 91134-//go:build go1.11 91135-// +build go1.11 91136- 91137-package bad 91138- 91139-// See #36637 91140-type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFunc", "type") 91141- 91142-var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "compiler", "(undeclared name|undefined): unknown", "error") 91143- 91144-func random() int { //@item(random, "random", "func() int", "func") 91145- //@complete("", global_a, bob, random, random2, random3, stateFunc, stuff) 91146- return 0 91147-} 91148- 91149-func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func"),item(bad_y_param, "y", "int", "var") 91150- x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared (and|but) not used", "error") 91151- var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared (and|but) not used", "error"),diag("blah", "compiler", "(undeclared name|undefined): blah", "error") 91152- var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared (and|but) not used", "error"),diag("blob", "compiler", "(undeclared name|undefined): blob", "error") 91153- //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff) 91154- 91155- return y 91156-} 91157- 91158-func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var") 91159- //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) 91160- 91161- var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared (and|but) not used", "error"),diag("favType1", "compiler", "(undeclared name|undefined): favType1", "error") 91162- var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared (and|but) not used", "error"),diag("keyType", "compiler", "(undeclared name|undefined): keyType", "error") 91163- var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared (and|but) not used", "error"),diag("favType2", "compiler", "(undeclared name|undefined): favType2", "error") 91164- var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared (and|but) not used", "error"),diag("badResult", "compiler", "(undeclared name|undefined): badResult", "error") 91165- var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared (and|but) not used", "error"),diag("badParam", "compiler", "(undeclared name|undefined): badParam", "error") 91166- //@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) 91167-} 91168diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in 91169--- a/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in 2000-01-01 00:00:00.000000000 -0000 91170+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in 1970-01-01 00:00:00.000000000 +0000 91171@@ -1,9 +0,0 @@ 91172-package badstmt 91173- 91174-import ( 91175- "golang.org/lsptests/foo" 91176-) 91177- 91178-func _() { 91179- defer func() { foo. } //@rank(" }", Foo) 91180-} 91181diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in 91182--- a/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in 2000-01-01 00:00:00.000000000 -0000 91183+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in 1970-01-01 00:00:00.000000000 +0000 91184@@ -1,9 +0,0 @@ 91185-package badstmt 91186- 91187-import ( 91188- "golang.org/lsptests/foo" 91189-) 91190- 91191-func _() { 91192- go foo. //@rank(" //", Foo, IntFoo),snippet(" //", Foo, "Foo()", "Foo()") 91193-} 91194diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in 91195--- a/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in 2000-01-01 00:00:00.000000000 -0000 91196+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in 1970-01-01 00:00:00.000000000 +0000 91197@@ -1,11 +0,0 @@ 91198-package badstmt 91199- 91200-import ( 91201- "golang.org/lsptests/foo" 91202-) 91203- 91204-func _() { 91205- go func() { 91206- defer foo. //@rank(" //", Foo, IntFoo) 91207- } 91208-} 91209diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in 91210--- a/gopls/internal/lsp/testdata/badstmt/badstmt.go.in 2000-01-01 00:00:00.000000000 -0000 91211+++ b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in 1970-01-01 00:00:00.000000000 +0000 91212@@ -1,29 +0,0 @@ 91213-package badstmt 91214- 91215-import ( 91216- "golang.org/lsptests/foo" 91217-) 91218- 91219-// The nonewvars expectation asserts that the go/analysis framework ran. 91220-// See comments in noparse. 91221- 91222-func _(x int) { 91223- defer foo.F //@complete(" //", Foo),diag(" //", "syntax", "function must be invoked in defer statement|expression in defer must be function call", "error") 91224- defer foo.F //@complete(" //", Foo) 91225- x := 123 //@diag(":=", "nonewvars", "no new variables", "warning") 91226-} 91227- 91228-func _() { 91229- switch true { 91230- case true: 91231- go foo.F //@complete(" //", Foo) 91232- } 91233-} 91234- 91235-func _() { 91236- defer func() { 91237- foo.F //@complete(" //", Foo),snippet(" //", Foo, "Foo()", "Foo()") 91238- 91239- foo. //@rank(" //", Foo) 91240- } 91241-} 91242diff -urN a/gopls/internal/lsp/testdata/bar/bar.go.in b/gopls/internal/lsp/testdata/bar/bar.go.in 91243--- a/gopls/internal/lsp/testdata/bar/bar.go.in 2000-01-01 00:00:00.000000000 -0000 91244+++ b/gopls/internal/lsp/testdata/bar/bar.go.in 1970-01-01 00:00:00.000000000 +0000 91245@@ -1,47 +0,0 @@ 91246-// +build go1.11 91247- 91248-package bar 91249- 91250-import ( 91251- "golang.org/lsptests/foo" //@item(foo, "foo", "\"golang.org/lsptests/foo\"", "package") 91252-) 91253- 91254-func helper(i foo.IntFoo) {} //@item(helper, "helper", "func(i foo.IntFoo)", "func") 91255- 91256-func _() { 91257- help //@complete("l", helper) 91258- _ = foo.StructFoo{} //@complete("S", IntFoo, StructFoo) 91259-} 91260- 91261-// Bar is a function. 91262-func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.") 91263- foo.Foo() //@complete("F", Foo, IntFoo, StructFoo) 91264- var _ foo.IntFoo //@complete("I", IntFoo, StructFoo) 91265- foo.() //@complete("(", Foo, IntFoo, StructFoo) 91266-} 91267- 91268-func _() { 91269- var Valentine int //@item(Valentine, "Valentine", "int", "var") 91270- 91271- _ = foo.StructFoo{ 91272- Valu //@complete(" //", Value) 91273- } 91274- _ = foo.StructFoo{ 91275- Va //@complete("a", Value, Valentine) 91276- } 91277- _ = foo.StructFoo{ 91278- Value: 5, //@complete("a", Value) 91279- } 91280- _ = foo.StructFoo{ 91281- //@complete("", Value, Valentine, foo, helper, Bar) 91282- } 91283- _ = foo.StructFoo{ 91284- Value: Valen //@complete("le", Valentine) 91285- } 91286- _ = foo.StructFoo{ 91287- Value: //@complete(" //", Valentine, foo, helper, Bar) 91288- } 91289- _ = foo.StructFoo{ 91290- Value: //@complete(" ", Valentine, foo, helper, Bar) 91291- } 91292-} 91293diff -urN a/gopls/internal/lsp/testdata/basiclit/basiclit.go b/gopls/internal/lsp/testdata/basiclit/basiclit.go 91294--- a/gopls/internal/lsp/testdata/basiclit/basiclit.go 2000-01-01 00:00:00.000000000 -0000 91295+++ b/gopls/internal/lsp/testdata/basiclit/basiclit.go 1970-01-01 00:00:00.000000000 +0000 91296@@ -1,13 +0,0 @@ 91297-package basiclit 91298- 91299-func _() { 91300- var a int // something for lexical completions 91301- 91302- _ = "hello." //@complete(".") 91303- 91304- _ = 1 //@complete(" //") 91305- 91306- _ = 1. //@complete(".") 91307- 91308- _ = 'a' //@complete("' ") 91309-} 91310diff -urN a/gopls/internal/lsp/testdata/baz/baz.go.in b/gopls/internal/lsp/testdata/baz/baz.go.in 91311--- a/gopls/internal/lsp/testdata/baz/baz.go.in 2000-01-01 00:00:00.000000000 -0000 91312+++ b/gopls/internal/lsp/testdata/baz/baz.go.in 1970-01-01 00:00:00.000000000 +0000 91313@@ -1,33 +0,0 @@ 91314-// +build go1.11 91315- 91316-package baz 91317- 91318-import ( 91319- "golang.org/lsptests/bar" 91320- 91321- f "golang.org/lsptests/foo" 91322-) 91323- 91324-var FooStruct f.StructFoo 91325- 91326-func Baz() { 91327- defer bar.Bar() //@complete("B", Bar) 91328- // TODO(rstambler): Test completion here. 91329- defer bar.B 91330- var x f.IntFoo //@complete("n", IntFoo),typdef("x", IntFoo) 91331- bar.Bar() //@complete("B", Bar) 91332-} 91333- 91334-func _() { 91335- bob := f.StructFoo{Value: 5} 91336- if x := bob. //@complete(" //", Value) 91337- switch true == false { 91338- case true: 91339- if x := bob. //@complete(" //", Value) 91340- case false: 91341- } 91342- if x := bob.Va //@complete("a", Value) 91343- switch true == true { 91344- default: 91345- } 91346-} 91347diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_args.go b/gopls/internal/lsp/testdata/builtins/builtin_args.go 91348--- a/gopls/internal/lsp/testdata/builtins/builtin_args.go 2000-01-01 00:00:00.000000000 -0000 91349+++ b/gopls/internal/lsp/testdata/builtins/builtin_args.go 1970-01-01 00:00:00.000000000 +0000 91350@@ -1,62 +0,0 @@ 91351-package builtins 91352- 91353-func _() { 91354- var ( 91355- aSlice []int //@item(builtinSlice, "aSlice", "[]int", "var") 91356- aMap map[string]int //@item(builtinMap, "aMap", "map[string]int", "var") 91357- aString string //@item(builtinString, "aString", "string", "var") 91358- aArray [0]int //@item(builtinArray, "aArray", "[0]int", "var") 91359- aArrayPtr *[0]int //@item(builtinArrayPtr, "aArrayPtr", "*[0]int", "var") 91360- aChan chan int //@item(builtinChan, "aChan", "chan int", "var") 91361- aPtr *int //@item(builtinPtr, "aPtr", "*int", "var") 91362- aInt int //@item(builtinInt, "aInt", "int", "var") 91363- ) 91364- 91365- type ( 91366- aSliceType []int //@item(builtinSliceType, "aSliceType", "[]int", "type") 91367- aChanType chan int //@item(builtinChanType, "aChanType", "chan int", "type") 91368- aMapType map[string]int //@item(builtinMapType, "aMapType", "map[string]int", "type") 91369- ) 91370- 91371- close() //@rank(")", builtinChan, builtinSlice) 91372- 91373- append() //@rank(")", builtinSlice, builtinChan) 91374- 91375- var _ []byte = append([]byte(nil), ""...) //@rank(") //") 91376- 91377- copy() //@rank(")", builtinSlice, builtinChan) 91378- copy(aSlice, aS) //@rank(")", builtinSlice, builtinString) 91379- copy(aS, aSlice) //@rank(",", builtinSlice, builtinString) 91380- 91381- delete() //@rank(")", builtinMap, builtinChan) 91382- delete(aMap, aS) //@rank(")", builtinString, builtinSlice) 91383- 91384- aMapFunc := func() map[int]int { //@item(builtinMapFunc, "aMapFunc", "func() map[int]int", "var") 91385- return nil 91386- } 91387- delete() //@rank(")", builtinMapFunc, builtinSlice) 91388- 91389- len() //@rank(")", builtinSlice, builtinInt),rank(")", builtinMap, builtinInt),rank(")", builtinString, builtinInt),rank(")", builtinArray, builtinInt),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt) 91390- 91391- cap() //@rank(")", builtinSlice, builtinMap),rank(")", builtinArray, builtinString),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt) 91392- 91393- make() //@rank(")", builtinMapType, int),rank(")", builtinChanType, int),rank(")", builtinSliceType, int),rank(")", builtinMapType, int) 91394- make(aSliceType, a) //@rank(")", builtinInt, builtinSlice) 91395- 91396- type myInt int 91397- var mi myInt //@item(builtinMyInt, "mi", "myInt", "var") 91398- make(aSliceType, m) //@snippet(")", builtinMyInt, "mi", "mi") 91399- 91400- var _ []int = make() //@rank(")", builtinSliceType, builtinMapType) 91401- 91402- type myStruct struct{} //@item(builtinStructType, "myStruct", "struct{...}", "struct") 91403- var _ *myStruct = new() //@rank(")", builtinStructType, int) 91404- 91405- for k := range a { //@rank(" {", builtinSlice, builtinInt),rank(" {", builtinString, builtinInt),rank(" {", builtinChan, builtinInt),rank(" {", builtinArray, builtinInt),rank(" {", builtinArrayPtr, builtinInt),rank(" {", builtinMap, builtinInt), 91406- } 91407- 91408- for k, v := range a { //@rank(" {", builtinSlice, builtinChan) 91409- } 91410- 91411- <-a //@rank(" //", builtinChan, builtinInt) 91412-} 91413diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_go117.go b/gopls/internal/lsp/testdata/builtins/builtin_go117.go 91414--- a/gopls/internal/lsp/testdata/builtins/builtin_go117.go 2000-01-01 00:00:00.000000000 -0000 91415+++ b/gopls/internal/lsp/testdata/builtins/builtin_go117.go 1970-01-01 00:00:00.000000000 +0000 91416@@ -1,8 +0,0 @@ 91417-//go:build !go1.18 91418-// +build !go1.18 91419- 91420-package builtins 91421- 91422-func _() { 91423- //@complete("", append, bool, byte, cap, close, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil) 91424-} 91425diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_go118.go b/gopls/internal/lsp/testdata/builtins/builtin_go118.go 91426--- a/gopls/internal/lsp/testdata/builtins/builtin_go118.go 2000-01-01 00:00:00.000000000 -0000 91427+++ b/gopls/internal/lsp/testdata/builtins/builtin_go118.go 1970-01-01 00:00:00.000000000 +0000 91428@@ -1,8 +0,0 @@ 91429-//go:build go1.18 && !go1.21 91430-// +build go1.18,!go1.21 91431- 91432-package builtins 91433- 91434-func _() { 91435- //@complete("", any, append, bool, byte, cap, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil) 91436-} 91437diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_go121.go b/gopls/internal/lsp/testdata/builtins/builtin_go121.go 91438--- a/gopls/internal/lsp/testdata/builtins/builtin_go121.go 2000-01-01 00:00:00.000000000 -0000 91439+++ b/gopls/internal/lsp/testdata/builtins/builtin_go121.go 1970-01-01 00:00:00.000000000 +0000 91440@@ -1,8 +0,0 @@ 91441-//go:build go1.21 91442-// +build go1.21 91443- 91444-package builtins 91445- 91446-func _() { 91447- //@complete("", any, append, bool, byte, cap, clear, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil) 91448-} 91449diff -urN a/gopls/internal/lsp/testdata/builtins/builtins.go b/gopls/internal/lsp/testdata/builtins/builtins.go 91450--- a/gopls/internal/lsp/testdata/builtins/builtins.go 2000-01-01 00:00:00.000000000 -0000 91451+++ b/gopls/internal/lsp/testdata/builtins/builtins.go 1970-01-01 00:00:00.000000000 +0000 91452@@ -1,47 +0,0 @@ 91453-package builtins 91454- 91455-// Definitions of builtin completion items. 91456- 91457-/* any */ //@item(any, "any", "", "interface") 91458-/* Create markers for builtin types. Only for use by this test. 91459-/* append(slice []Type, elems ...Type) []Type */ //@item(append, "append", "func(slice []Type, elems ...Type) []Type", "func") 91460-/* bool */ //@item(bool, "bool", "", "type") 91461-/* byte */ //@item(byte, "byte", "", "type") 91462-/* cap(v Type) int */ //@item(cap, "cap", "func(v Type) int", "func") 91463-/* clear[T interface{ ~[]Type | ~map[Type]Type1 }](t T) */ //@item(clear, "clear", "func(t T)", "func") 91464-/* close(c chan<- Type) */ //@item(close, "close", "func(c chan<- Type)", "func") 91465-/* comparable */ //@item(comparable, "comparable", "", "interface") 91466-/* complex(r float64, i float64) */ //@item(complex, "complex", "func(r float64, i float64) complex128", "func") 91467-/* complex128 */ //@item(complex128, "complex128", "", "type") 91468-/* complex64 */ //@item(complex64, "complex64", "", "type") 91469-/* copy(dst []Type, src []Type) int */ //@item(copy, "copy", "func(dst []Type, src []Type) int", "func") 91470-/* delete(m map[Type]Type1, key Type) */ //@item(delete, "delete", "func(m map[Type]Type1, key Type)", "func") 91471-/* error */ //@item(error, "error", "", "interface") 91472-/* false */ //@item(_false, "false", "", "const") 91473-/* float32 */ //@item(float32, "float32", "", "type") 91474-/* float64 */ //@item(float64, "float64", "", "type") 91475-/* imag(c complex128) float64 */ //@item(imag, "imag", "func(c complex128) float64", "func") 91476-/* int */ //@item(int, "int", "", "type") 91477-/* int16 */ //@item(int16, "int16", "", "type") 91478-/* int32 */ //@item(int32, "int32", "", "type") 91479-/* int64 */ //@item(int64, "int64", "", "type") 91480-/* int8 */ //@item(int8, "int8", "", "type") 91481-/* iota */ //@item(iota, "iota", "", "const") 91482-/* len(v Type) int */ //@item(len, "len", "func(v Type) int", "func") 91483-/* make(t Type, size ...int) Type */ //@item(make, "make", "func(t Type, size ...int) Type", "func") 91484-/* new(Type) *Type */ //@item(new, "new", "func(Type) *Type", "func") 91485-/* nil */ //@item(_nil, "nil", "", "var") 91486-/* panic(v interface{}) */ //@item(panic, "panic", "func(v interface{})", "func") 91487-/* print(args ...Type) */ //@item(print, "print", "func(args ...Type)", "func") 91488-/* println(args ...Type) */ //@item(println, "println", "func(args ...Type)", "func") 91489-/* real(c complex128) float64 */ //@item(real, "real", "func(c complex128) float64", "func") 91490-/* recover() interface{} */ //@item(recover, "recover", "func() interface{}", "func") 91491-/* rune */ //@item(rune, "rune", "", "type") 91492-/* string */ //@item(string, "string", "", "type") 91493-/* true */ //@item(_true, "true", "", "const") 91494-/* uint */ //@item(uint, "uint", "", "type") 91495-/* uint16 */ //@item(uint16, "uint16", "", "type") 91496-/* uint32 */ //@item(uint32, "uint32", "", "type") 91497-/* uint64 */ //@item(uint64, "uint64", "", "type") 91498-/* uint8 */ //@item(uint8, "uint8", "", "type") 91499-/* uintptr */ //@item(uintptr, "uintptr", "", "type") 91500diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_types.go b/gopls/internal/lsp/testdata/builtins/builtin_types.go 91501--- a/gopls/internal/lsp/testdata/builtins/builtin_types.go 2000-01-01 00:00:00.000000000 -0000 91502+++ b/gopls/internal/lsp/testdata/builtins/builtin_types.go 1970-01-01 00:00:00.000000000 +0000 91503@@ -1,11 +0,0 @@ 91504-package builtins 91505- 91506-func _() { 91507- var _ []bool //@item(builtinBoolSliceType, "[]bool", "[]bool", "type") 91508- 91509- var _ []bool = make() //@rank(")", builtinBoolSliceType, int) 91510- 91511- var _ []bool = make([], 0) //@rank(",", bool, int) 91512- 91513- var _ [][]bool = make([][], 0) //@rank(",", bool, int) 91514-} 91515diff -urN a/gopls/internal/lsp/testdata/builtins/constants.go b/gopls/internal/lsp/testdata/builtins/constants.go 91516--- a/gopls/internal/lsp/testdata/builtins/constants.go 2000-01-01 00:00:00.000000000 -0000 91517+++ b/gopls/internal/lsp/testdata/builtins/constants.go 1970-01-01 00:00:00.000000000 +0000 91518@@ -1,19 +0,0 @@ 91519-package builtins 91520- 91521-func _() { 91522- const ( 91523- foo = iota //@complete(" //", iota) 91524- ) 91525- 91526- iota //@complete(" //") 91527- 91528- var iota int //@item(iotaVar, "iota", "int", "var") 91529- 91530- iota //@complete(" //", iotaVar) 91531-} 91532- 91533-func _() { 91534- var twoRedUpEnd bool //@item(TRUEVar, "twoRedUpEnd", "bool", "var") 91535- 91536- var _ bool = true //@rank(" //", _true, TRUEVar) 91537-} 91538diff -urN a/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go 91539--- a/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go 2000-01-01 00:00:00.000000000 -0000 91540+++ b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go 1970-01-01 00:00:00.000000000 +0000 91541@@ -1,70 +0,0 @@ 91542-// Copyright 2020 The Go Authors. All rights reserved. 91543-// Use of this source code is governed by a BSD-style 91544-// license that can be found in the LICENSE file. 91545- 91546-package callhierarchy 91547- 91548-import "golang.org/lsptests/callhierarchy/outgoing" 91549- 91550-func a() { //@mark(hierarchyA, "a") 91551- D() 91552-} 91553- 91554-func b() { //@mark(hierarchyB, "b") 91555- D() 91556-} 91557- 91558-// C is an exported function 91559-func C() { //@mark(hierarchyC, "C") 91560- D() 91561- D() 91562-} 91563- 91564-// To test hierarchy across function literals 91565-var x = func() { //@mark(hierarchyLiteral, "func"),mark(hierarchyLiteralOut, "x") 91566- D() 91567-} 91568- 91569-// D is exported to test incoming/outgoing calls across packages 91570-func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB, hierarchyFoo, hierarchyH, hierarchyI, hierarchyJ, hierarchyK) 91571- e() 91572- x() 91573- F() 91574- outgoing.B() 91575- foo := func() {} //@mark(hierarchyFoo, "foo"),incomingcalls(hierarchyFoo, hierarchyD),outgoingcalls(hierarchyFoo) 91576- foo() 91577- 91578- func() { 91579- g() 91580- }() 91581- 91582- var i Interface = impl{} 91583- i.H() 91584- i.I() 91585- 91586- s := Struct{} 91587- s.J() 91588- s.K() 91589-} 91590- 91591-func e() {} //@mark(hierarchyE, "e") 91592- 91593-// F is an exported function 91594-func F() {} //@mark(hierarchyF, "F") 91595- 91596-func g() {} //@mark(hierarchyG, "g") 91597- 91598-type Interface interface { 91599- H() //@mark(hierarchyH, "H") 91600- I() //@mark(hierarchyI, "I") 91601-} 91602- 91603-type impl struct{} 91604- 91605-func (i impl) H() {} 91606-func (i impl) I() {} 91607- 91608-type Struct struct { 91609- J func() //@mark(hierarchyJ, "J") 91610- K func() //@mark(hierarchyK, "K") 91611-} 91612diff -urN a/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go 91613--- a/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go 2000-01-01 00:00:00.000000000 -0000 91614+++ b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go 1970-01-01 00:00:00.000000000 +0000 91615@@ -1,12 +0,0 @@ 91616-// Copyright 2020 The Go Authors. All rights reserved. 91617-// Use of this source code is governed by a BSD-style 91618-// license that can be found in the LICENSE file. 91619- 91620-package incoming 91621- 91622-import "golang.org/lsptests/callhierarchy" 91623- 91624-// A is exported to test incoming calls across packages 91625-func A() { //@mark(incomingA, "A") 91626- callhierarchy.D() 91627-} 91628diff -urN a/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go 91629--- a/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go 2000-01-01 00:00:00.000000000 -0000 91630+++ b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go 1970-01-01 00:00:00.000000000 +0000 91631@@ -1,9 +0,0 @@ 91632-// Copyright 2020 The Go Authors. All rights reserved. 91633-// Use of this source code is governed by a BSD-style 91634-// license that can be found in the LICENSE file. 91635- 91636-package outgoing 91637- 91638-// B is exported to test outgoing calls across packages 91639-func B() { //@mark(outgoingB, "B") 91640-} 91641diff -urN a/gopls/internal/lsp/testdata/casesensitive/casesensitive.go b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go 91642--- a/gopls/internal/lsp/testdata/casesensitive/casesensitive.go 2000-01-01 00:00:00.000000000 -0000 91643+++ b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go 1970-01-01 00:00:00.000000000 +0000 91644@@ -1,16 +0,0 @@ 91645-// Copyright 2019 The Go Authors. All rights reserved. 91646-// Use of this source code is governed by a BSD-style 91647-// license that can be found in the LICENSE file. 91648- 91649-package casesensitive 91650- 91651-func _() { 91652- var lower int //@item(lower, "lower", "int", "var") 91653- var Upper int //@item(upper, "Upper", "int", "var") 91654- 91655- l //@casesensitive(" //", lower) 91656- U //@casesensitive(" //", upper) 91657- 91658- L //@casesensitive(" //") 91659- u //@casesensitive(" //") 91660-} 91661diff -urN a/gopls/internal/lsp/testdata/cast/cast.go.in b/gopls/internal/lsp/testdata/cast/cast.go.in 91662--- a/gopls/internal/lsp/testdata/cast/cast.go.in 2000-01-01 00:00:00.000000000 -0000 91663+++ b/gopls/internal/lsp/testdata/cast/cast.go.in 1970-01-01 00:00:00.000000000 +0000 91664@@ -1,11 +0,0 @@ 91665-package cast 91666- 91667-func _() { 91668- foo := struct{x int}{x: 1} //@item(x_field, "x", "int", "field") 91669- _ = float64(foo.x) //@complete("x", x_field) 91670-} 91671- 91672-func _() { 91673- foo := struct{x int}{x: 1} 91674- _ = float64(foo. //@complete(" /", x_field) 91675-} 91676\ No newline at end of file 91677diff -urN a/gopls/internal/lsp/testdata/cgo/declarecgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo.go 91678--- a/gopls/internal/lsp/testdata/cgo/declarecgo.go 2000-01-01 00:00:00.000000000 -0000 91679+++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go 1970-01-01 00:00:00.000000000 +0000 91680@@ -1,27 +0,0 @@ 91681-package cgo 91682- 91683-/* 91684-#include <stdio.h> 91685-#include <stdlib.h> 91686- 91687-void myprint(char* s) { 91688- printf("%s\n", s); 91689-} 91690-*/ 91691-import "C" 91692- 91693-import ( 91694- "fmt" 91695- "unsafe" 91696-) 91697- 91698-func Example() { //@mark(funccgoexample, "Example"),item(funccgoexample, "Example", "func()", "func") 91699- fmt.Println() 91700- cs := C.CString("Hello from stdio\n") 91701- C.myprint(cs) 91702- C.free(unsafe.Pointer(cs)) 91703-} 91704- 91705-func _() { 91706- Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample) 91707-} 91708diff -urN a/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden 91709--- a/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden 2000-01-01 00:00:00.000000000 -0000 91710+++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden 1970-01-01 00:00:00.000000000 +0000 91711@@ -1,30 +0,0 @@ 91712--- funccgoexample-definition -- 91713-cgo/declarecgo.go:18:6-13: defined here as ```go 91714-func Example() 91715-``` 91716- 91717-[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) 91718--- funccgoexample-definition-json -- 91719-{ 91720- "span": { 91721- "uri": "file://cgo/declarecgo.go", 91722- "start": { 91723- "line": 18, 91724- "column": 6, 91725- "offset": 151 91726- }, 91727- "end": { 91728- "line": 18, 91729- "column": 13, 91730- "offset": 158 91731- } 91732- }, 91733- "description": "```go\nfunc Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)" 91734-} 91735- 91736--- funccgoexample-hoverdef -- 91737-```go 91738-func Example() 91739-``` 91740- 91741-[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) 91742diff -urN a/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go 91743--- a/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go 2000-01-01 00:00:00.000000000 -0000 91744+++ b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go 1970-01-01 00:00:00.000000000 +0000 91745@@ -1,6 +0,0 @@ 91746-//+build !cgo 91747- 91748-package cgo 91749- 91750-// Set a dummy marker to keep the test framework happy. The tests should be skipped. 91751-var _ = "Example" //@mark(funccgoexample, "Example"),godef("ample", funccgoexample),complete("ample", funccgoexample) 91752diff -urN a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden 91753--- a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden 2000-01-01 00:00:00.000000000 -0000 91754+++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden 1970-01-01 00:00:00.000000000 +0000 91755@@ -1,30 +0,0 @@ 91756--- funccgoexample-definition -- 91757-cgo/declarecgo.go:18:6-13: defined here as ```go 91758-func cgo.Example() 91759-``` 91760- 91761-[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) 91762--- funccgoexample-definition-json -- 91763-{ 91764- "span": { 91765- "uri": "file://cgo/declarecgo.go", 91766- "start": { 91767- "line": 18, 91768- "column": 6, 91769- "offset": 151 91770- }, 91771- "end": { 91772- "line": 18, 91773- "column": 13, 91774- "offset": 158 91775- } 91776- }, 91777- "description": "```go\nfunc cgo.Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)" 91778-} 91779- 91780--- funccgoexample-hoverdef -- 91781-```go 91782-func cgo.Example() 91783-``` 91784- 91785-[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) 91786diff -urN a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in 91787--- a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in 2000-01-01 00:00:00.000000000 -0000 91788+++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in 1970-01-01 00:00:00.000000000 +0000 91789@@ -1,9 +0,0 @@ 91790-package cgoimport 91791- 91792-import ( 91793- "golang.org/lsptests/cgo" 91794-) 91795- 91796-func _() { 91797- cgo.Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample) 91798-} 91799diff -urN a/gopls/internal/lsp/testdata/channel/channel.go b/gopls/internal/lsp/testdata/channel/channel.go 91800--- a/gopls/internal/lsp/testdata/channel/channel.go 2000-01-01 00:00:00.000000000 -0000 91801+++ b/gopls/internal/lsp/testdata/channel/channel.go 1970-01-01 00:00:00.000000000 +0000 91802@@ -1,25 +0,0 @@ 91803-package channel 91804- 91805-func _() { 91806- var ( 91807- aa = "123" //@item(channelAA, "aa", "string", "var") 91808- ab = 123 //@item(channelAB, "ab", "int", "var") 91809- ) 91810- 91811- { 91812- type myChan chan int 91813- var mc myChan 91814- mc <- a //@complete(" //", channelAB, channelAA) 91815- } 91816- 91817- { 91818- var ac chan int //@item(channelAC, "ac", "chan int", "var") 91819- a <- a //@complete(" <-", channelAC, channelAA, channelAB) 91820- } 91821- 91822- { 91823- var foo chan int //@item(channelFoo, "foo", "chan int", "var") 91824- wantsInt := func(int) {} //@item(channelWantsInt, "wantsInt", "func(int)", "var") 91825- wantsInt(<-) //@rank(")", channelFoo, channelAB) 91826- } 91827-} 91828diff -urN a/gopls/internal/lsp/testdata/codelens/codelens_test.go b/gopls/internal/lsp/testdata/codelens/codelens_test.go 91829--- a/gopls/internal/lsp/testdata/codelens/codelens_test.go 2000-01-01 00:00:00.000000000 -0000 91830+++ b/gopls/internal/lsp/testdata/codelens/codelens_test.go 1970-01-01 00:00:00.000000000 +0000 91831@@ -1,16 +0,0 @@ 91832-package codelens //@codelens("package codelens", "run file benchmarks", "test") 91833- 91834-import "testing" 91835- 91836-func TestMain(m *testing.M) {} // no code lens for TestMain 91837- 91838-func TestFuncWithCodeLens(t *testing.T) { //@codelens("func", "run test", "test") 91839-} 91840- 91841-func thisShouldNotHaveACodeLens(t *testing.T) { 91842-} 91843- 91844-func BenchmarkFuncWithCodeLens(b *testing.B) { //@codelens("func", "run benchmark", "test") 91845-} 91846- 91847-func helper() {} // expect no code lens 91848diff -urN a/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in 91849--- a/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in 2000-01-01 00:00:00.000000000 -0000 91850+++ b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in 1970-01-01 00:00:00.000000000 +0000 91851@@ -1,70 +0,0 @@ 91852-package comment_completion 91853- 91854-var p bool 91855- 91856-//@complete(re"$") 91857- 91858-func _() { 91859- var a int 91860- 91861- switch a { 91862- case 1: 91863- //@complete(re"$") 91864- _ = a 91865- } 91866- 91867- var b chan int 91868- select { 91869- case <-b: 91870- //@complete(re"$") 91871- _ = b 91872- } 91873- 91874- var ( 91875- //@complete(re"$") 91876- _ = a 91877- ) 91878-} 91879- 91880-// //@complete(" ", variableC) 91881-var C string //@item(variableC, "C", "string", "var") //@complete(" ", variableC) 91882- 91883-// //@complete(" ", constant) 91884-const Constant = "example" //@item(constant, "Constant", "string", "const") //@complete(" ", constant) 91885- 91886-// //@complete(" ", structType, fieldB, fieldA) 91887-type StructType struct { //@item(structType, "StructType", "struct{...}", "struct") //@complete(" ", structType, fieldA, fieldB) 91888- // //@complete(" ", fieldA, structType, fieldB) 91889- A string //@item(fieldA, "A", "string", "field") //@complete(" ", fieldA, structType, fieldB) 91890- b int //@item(fieldB, "b", "int", "field") //@complete(" ", fieldB, structType, fieldA) 91891-} 91892- 91893-// //@complete(" ", method, structRecv, paramX, resultY, fieldB, fieldA) 91894-func (structType *StructType) Method(X int) (Y int) { //@item(structRecv, "structType", "*StructType", "var"),item(method, "Method", "func(X int) (Y int)", "method"),item(paramX, "X", "int", "var"),item(resultY, "Y", "int", "var") 91895- // //@complete(" ", method, structRecv, paramX, resultY, fieldB, fieldA) 91896- return 91897-} 91898- 91899-// //@complete(" ", newType) 91900-type NewType string //@item(newType, "NewType", "string", "type") //@complete(" ", newType) 91901- 91902-// //@complete(" ", testInterface, testA, testB) 91903-type TestInterface interface { //@item(testInterface, "TestInterface", "interface{...}", "interface") 91904- // //@complete(" ", testA, testInterface, testB) 91905- TestA(L string) (M int) //@item(testA, "TestA", "func(L string) (M int)", "method"),item(paramL, "L", "var", "string"),item(resM, "M", "var", "int") //@complete(" ", testA, testInterface, testB) 91906- TestB(N int) bool //@item(testB, "TestB", "func(N int) bool", "method"),item(paramN, "N", "var", "int") //@complete(" ", testB, testInterface, testA) 91907-} 91908- 91909-// //@complete(" ", function) 91910-func Function() int { //@item(function, "Function", "func() int", "func") //@complete(" ", function) 91911- // //@complete(" ", function) 91912- return 0 91913-} 91914- 91915-// This tests multiline block comments and completion with prefix 91916-// Lorem Ipsum Multili//@complete("Multi", multiline) 91917-// Lorem ipsum dolor sit ametom 91918-func Multiline() int { //@item(multiline, "Multiline", "func() int", "func") 91919- // //@complete(" ", multiline) 91920- return 0 91921-} 91922diff -urN a/gopls/internal/lsp/testdata/complit/complit.go.in b/gopls/internal/lsp/testdata/complit/complit.go.in 91923--- a/gopls/internal/lsp/testdata/complit/complit.go.in 2000-01-01 00:00:00.000000000 -0000 91924+++ b/gopls/internal/lsp/testdata/complit/complit.go.in 1970-01-01 00:00:00.000000000 +0000 91925@@ -1,90 +0,0 @@ 91926-package complit 91927- 91928-// general completions 91929- 91930-type position struct { //@item(structPosition, "position", "struct{...}", "struct") 91931- X, Y int //@item(fieldX, "X", "int", "field"),item(fieldY, "Y", "int", "field") 91932-} 91933- 91934-func _() { 91935- _ = position{ 91936- //@complete("", fieldX, fieldY, structPosition) 91937- } 91938- _ = position{ 91939- X: 1, 91940- //@complete("", fieldY) 91941- } 91942- _ = position{ 91943- //@complete("", fieldX) 91944- Y: 1, 91945- } 91946- _ = []*position{ 91947- { 91948- //@complete("", fieldX, fieldY, structPosition) 91949- }, 91950- } 91951-} 91952- 91953-func _() { 91954- var ( 91955- aa string //@item(aaVar, "aa", "string", "var") 91956- ab int //@item(abVar, "ab", "int", "var") 91957- ) 91958- 91959- _ = map[int]int{ 91960- a: a, //@complete(":", abVar, aaVar),complete(",", abVar, aaVar) 91961- } 91962- 91963- _ = map[int]int{ 91964- //@complete("", abVar, aaVar, structPosition) 91965- } 91966- 91967- _ = []string{a: ""} //@complete(":", abVar, aaVar) 91968- _ = [1]string{a: ""} //@complete(":", abVar, aaVar) 91969- 91970- _ = position{X: a} //@complete("}", abVar, aaVar) 91971- _ = position{a} //@complete("}", abVar, aaVar) 91972- _ = position{a, } //@complete("}", abVar, aaVar, structPosition) 91973- 91974- _ = []int{a} //@complete("}", abVar, aaVar) 91975- _ = [1]int{a} //@complete("}", abVar, aaVar) 91976- 91977- type myStruct struct { 91978- AA int //@item(fieldAA, "AA", "int", "field") 91979- AB string //@item(fieldAB, "AB", "string", "field") 91980- } 91981- 91982- _ = myStruct{ 91983- AB: a, //@complete(",", aaVar, abVar) 91984- } 91985- 91986- var s myStruct 91987- 91988- _ = map[int]string{1: "" + s.A} //@complete("}", fieldAB, fieldAA) 91989- _ = map[int]string{1: (func(i int) string { return "" })(s.A)} //@complete(")}", fieldAA, fieldAB) 91990- _ = map[int]string{1: func() string { s.A }} //@complete(" }", fieldAA, fieldAB) 91991- 91992- _ = position{s.A} //@complete("}", fieldAA, fieldAB) 91993- 91994- var X int //@item(varX, "X", "int", "var") 91995- _ = position{X} //@complete("}", fieldX, varX) 91996-} 91997- 91998-func _() { 91999- type foo struct{} //@item(complitFoo, "foo", "struct{...}", "struct") 92000- 92001- var _ *foo = &fo{} //@snippet("{", complitFoo, "foo", "foo") 92002- var _ *foo = fo{} //@snippet("{", complitFoo, "&foo", "&foo") 92003- 92004- struct { a, b *foo }{ 92005- a: &fo{}, //@rank("{", complitFoo) 92006- b: fo{}, //@snippet("{", complitFoo, "&foo", "&foo") 92007- } 92008-} 92009- 92010-func _() { 92011- _ := position{ 92012- X: 1, //@complete("X", fieldX),complete(" 1", structPosition) 92013- Y: , //@complete(":", fieldY),complete(" ,", structPosition) 92014- } 92015-} 92016diff -urN a/gopls/internal/lsp/testdata/constant/constant.go b/gopls/internal/lsp/testdata/constant/constant.go 92017--- a/gopls/internal/lsp/testdata/constant/constant.go 2000-01-01 00:00:00.000000000 -0000 92018+++ b/gopls/internal/lsp/testdata/constant/constant.go 1970-01-01 00:00:00.000000000 +0000 92019@@ -1,14 +0,0 @@ 92020-package constant 92021- 92022-const x = 1 //@item(constX, "x", "int", "const") 92023- 92024-const ( 92025- a int = iota << 2 //@item(constA, "a", "int", "const") 92026- b //@item(constB, "b", "int", "const") 92027- c //@item(constC, "c", "int", "const") 92028-) 92029- 92030-func _() { 92031- const y = "hi" //@item(constY, "y", "string", "const") 92032- //@complete("", constY, constA, constB, constC, constX) 92033-} 92034diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go 92035--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go 2000-01-01 00:00:00.000000000 -0000 92036+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go 1970-01-01 00:00:00.000000000 +0000 92037@@ -1,9 +0,0 @@ 92038-package danglingstmt 92039- 92040-func _() { 92041- for bar //@rank(" //", danglingBar) 92042-} 92043- 92044-func bar() bool { //@item(danglingBar, "bar", "func() bool", "func") 92045- return true 92046-} 92047diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go 92048--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go 2000-01-01 00:00:00.000000000 -0000 92049+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go 1970-01-01 00:00:00.000000000 +0000 92050@@ -1,9 +0,0 @@ 92051-package danglingstmt 92052- 92053-func _() { 92054- for i := bar3(); i > bar //@rank(" //", danglingBar3) 92055-} 92056- 92057-func bar3() int { //@item(danglingBar3, "bar3", "func() int", "func") 92058- return 0 92059-} 92060diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go 92061--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go 2000-01-01 00:00:00.000000000 -0000 92062+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go 1970-01-01 00:00:00.000000000 +0000 92063@@ -1,9 +0,0 @@ 92064-package danglingstmt 92065- 92066-func _() { 92067- for i := bar4(); i > bar4(); i += bar //@rank(" //", danglingBar4) 92068-} 92069- 92070-func bar4() int { //@item(danglingBar4, "bar4", "func() int", "func") 92071- return 0 92072-} 92073diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go 92074--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go 2000-01-01 00:00:00.000000000 -0000 92075+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go 1970-01-01 00:00:00.000000000 +0000 92076@@ -1,9 +0,0 @@ 92077-package danglingstmt 92078- 92079-func _() { 92080- for i := bar //@rank(" //", danglingBar2) 92081-} 92082- 92083-func bar2() int { //@item(danglingBar2, "bar2", "func() int", "func") 92084- return 0 92085-} 92086diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go 92087--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go 2000-01-01 00:00:00.000000000 -0000 92088+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go 1970-01-01 00:00:00.000000000 +0000 92089@@ -1,8 +0,0 @@ 92090-package danglingstmt 92091- 92092-func bar5() bool { //@item(danglingBar5, "bar5", "func() bool", "func") 92093- return true 92094-} 92095- 92096-func _() { 92097- if b //@rank(" //", danglingBar5) 92098diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go 92099--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go 2000-01-01 00:00:00.000000000 -0000 92100+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go 1970-01-01 00:00:00.000000000 +0000 92101@@ -1,9 +0,0 @@ 92102-package danglingstmt 92103- 92104-func _() { 92105- if foo //@rank(" //", danglingFoo) 92106-} 92107- 92108-func foo() bool { //@item(danglingFoo, "foo", "func() bool", "func") 92109- return true 92110-} 92111diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go 92112--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go 2000-01-01 00:00:00.000000000 -0000 92113+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go 1970-01-01 00:00:00.000000000 +0000 92114@@ -1,9 +0,0 @@ 92115-package danglingstmt 92116- 92117-func _() { 92118- if i := 123; foo //@rank(" //", danglingFoo3) 92119-} 92120- 92121-func foo3() bool { //@item(danglingFoo3, "foo3", "func() bool", "func") 92122- return true 92123-} 92124diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go 92125--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go 2000-01-01 00:00:00.000000000 -0000 92126+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go 1970-01-01 00:00:00.000000000 +0000 92127@@ -1,9 +0,0 @@ 92128-package danglingstmt 92129- 92130-func _() { 92131- if i := foo //@rank(" //", danglingFoo2) 92132-} 92133- 92134-func foo2() bool { //@item(danglingFoo2, "foo2", "func() bool", "func") 92135- return true 92136-} 92137diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go 92138--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go 2000-01-01 00:00:00.000000000 -0000 92139+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go 1970-01-01 00:00:00.000000000 +0000 92140@@ -1,10 +0,0 @@ 92141-package danglingstmt 92142- 92143-func walrus() bool { //@item(danglingWalrus, "walrus", "func() bool", "func") 92144- return true 92145-} 92146- 92147-func _() { 92148- if true && 92149- walrus //@complete(" //", danglingWalrus) 92150-} 92151diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go 92152--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go 2000-01-01 00:00:00.000000000 -0000 92153+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go 1970-01-01 00:00:00.000000000 +0000 92154@@ -1,7 +0,0 @@ 92155-package danglingstmt 92156- 92157-func _() { 92158- x. //@rank(" //", danglingI) 92159-} 92160- 92161-var x struct { i int } //@item(danglingI, "i", "int", "field") 92162diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go 92163--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go 2000-01-01 00:00:00.000000000 -0000 92164+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go 1970-01-01 00:00:00.000000000 +0000 92165@@ -1,8 +0,0 @@ 92166-package danglingstmt 92167- 92168-import "golang.org/lsptests/foo" 92169- 92170-func _() { 92171- foo. //@rank(" //", Foo) 92172- var _ = []string{foo.} //@rank("}", Foo) 92173-} 92174diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go 92175--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go 2000-01-01 00:00:00.000000000 -0000 92176+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go 1970-01-01 00:00:00.000000000 +0000 92177@@ -1,9 +0,0 @@ 92178-package danglingstmt 92179- 92180-func _() { 92181- switch i := baz //@rank(" //", danglingBaz) 92182-} 92183- 92184-func baz() int { //@item(danglingBaz, "baz", "func() int", "func") 92185- return 0 92186-} 92187diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go 92188--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go 2000-01-01 00:00:00.000000000 -0000 92189+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go 1970-01-01 00:00:00.000000000 +0000 92190@@ -1,9 +0,0 @@ 92191-package danglingstmt 92192- 92193-func _() { 92194- switch i := 0; baz //@rank(" //", danglingBaz2) 92195-} 92196- 92197-func baz2() int { //@item(danglingBaz2, "baz2", "func() int", "func") 92198- return 0 92199-} 92200diff -urN a/gopls/internal/lsp/testdata/deep/deep.go b/gopls/internal/lsp/testdata/deep/deep.go 92201--- a/gopls/internal/lsp/testdata/deep/deep.go 2000-01-01 00:00:00.000000000 -0000 92202+++ b/gopls/internal/lsp/testdata/deep/deep.go 1970-01-01 00:00:00.000000000 +0000 92203@@ -1,142 +0,0 @@ 92204-package deep 92205- 92206-import "context" 92207- 92208-type deepA struct { 92209- b deepB //@item(deepBField, "b", "deepB", "field") 92210-} 92211- 92212-type deepB struct { 92213-} 92214- 92215-func wantsDeepB(deepB) {} 92216- 92217-func _() { 92218- var a deepA //@item(deepAVar, "a", "deepA", "var") 92219- a.b //@item(deepABField, "a.b", "deepB", "field") 92220- wantsDeepB(a) //@deep(")", deepABField, deepAVar) 92221- 92222- deepA{a} //@snippet("}", deepABField, "a.b", "a.b") 92223-} 92224- 92225-func wantsContext(context.Context) {} 92226- 92227-func _() { 92228- context.Background() //@item(ctxBackground, "context.Background", "func() context.Context", "func", "Background returns a non-nil, empty Context.") 92229- context.TODO() //@item(ctxTODO, "context.TODO", "func() context.Context", "func", "TODO returns a non-nil, empty Context.") 92230- 92231- wantsContext(c) //@rank(")", ctxBackground),rank(")", ctxTODO) 92232-} 92233- 92234-func _() { 92235- var cork struct{ err error } 92236- cork.err //@item(deepCorkErr, "cork.err", "error", "field") 92237- context //@item(deepContextPkg, "context", "\"context\"", "package") 92238- var _ error = co //@rank(" //", deepCorkErr, deepContextPkg) 92239-} 92240- 92241-func _() { 92242- // deepCircle is circular. 92243- type deepCircle struct { 92244- *deepCircle 92245- } 92246- var circle deepCircle //@item(deepCircle, "circle", "deepCircle", "var") 92247- circle.deepCircle //@item(deepCircleField, "circle.deepCircle", "*deepCircle", "field") 92248- var _ deepCircle = circ //@deep(" //", deepCircle, deepCircleField),snippet(" //", deepCircleField, "*circle.deepCircle", "*circle.deepCircle") 92249-} 92250- 92251-func _() { 92252- type deepEmbedC struct { 92253- } 92254- type deepEmbedB struct { 92255- deepEmbedC 92256- } 92257- type deepEmbedA struct { 92258- deepEmbedB 92259- } 92260- 92261- wantsC := func(deepEmbedC) {} 92262- 92263- var a deepEmbedA //@item(deepEmbedA, "a", "deepEmbedA", "var") 92264- a.deepEmbedB //@item(deepEmbedB, "a.deepEmbedB", "deepEmbedB", "field") 92265- a.deepEmbedC //@item(deepEmbedC, "a.deepEmbedC", "deepEmbedC", "field") 92266- wantsC(a) //@deep(")", deepEmbedC, deepEmbedA, deepEmbedB) 92267-} 92268- 92269-func _() { 92270- type nested struct { 92271- a int 92272- n *nested //@item(deepNestedField, "n", "*nested", "field") 92273- } 92274- 92275- nested{ 92276- a: 123, //@deep(" //", deepNestedField) 92277- } 92278-} 92279- 92280-func _() { 92281- var a struct { 92282- b struct { 92283- c int 92284- } 92285- d int 92286- } 92287- 92288- a.d //@item(deepAD, "a.d", "int", "field") 92289- a.b.c //@item(deepABC, "a.b.c", "int", "field") 92290- a.b //@item(deepAB, "a.b", "struct{...}", "field") 92291- a //@item(deepA, "a", "struct{...}", "var") 92292- 92293- // "a.d" should be ranked above the deeper "a.b.c" 92294- var i int 92295- i = a //@deep(" //", deepAD, deepABC, deepA, deepAB) 92296-} 92297- 92298-type foo struct { 92299- b bar 92300-} 92301- 92302-func (f foo) bar() bar { 92303- return f.b 92304-} 92305- 92306-func (f foo) barPtr() *bar { 92307- return &f.b 92308-} 92309- 92310-type bar struct{} 92311- 92312-func (b bar) valueReceiver() int { 92313- return 0 92314-} 92315- 92316-func (b *bar) ptrReceiver() int { 92317- return 0 92318-} 92319- 92320-func _() { 92321- var ( 92322- i int 92323- f foo 92324- ) 92325- 92326- f.bar().valueReceiver //@item(deepBarValue, "f.bar().valueReceiver", "func() int", "method") 92327- f.barPtr().ptrReceiver //@item(deepBarPtrPtr, "f.barPtr().ptrReceiver", "func() int", "method") 92328- f.barPtr().valueReceiver //@item(deepBarPtrValue, "f.barPtr().valueReceiver", "func() int", "method") 92329- 92330- i = fbar //@fuzzy(" //", deepBarValue, deepBarPtrPtr, deepBarPtrValue) 92331-} 92332- 92333-func (b baz) Thing() struct{ val int } { 92334- return b.thing 92335-} 92336- 92337-type baz struct { 92338- thing struct{ val int } 92339-} 92340- 92341-func (b baz) _() { 92342- b.Thing().val //@item(deepBazMethVal, "b.Thing().val", "int", "field") 92343- b.thing.val //@item(deepBazFieldVal, "b.thing.val", "int", "field") 92344- var _ int = bval //@rank(" //", deepBazFieldVal, deepBazMethVal) 92345-} 92346diff -urN a/gopls/internal/lsp/testdata/errors/errors.go b/gopls/internal/lsp/testdata/errors/errors.go 92347--- a/gopls/internal/lsp/testdata/errors/errors.go 2000-01-01 00:00:00.000000000 -0000 92348+++ b/gopls/internal/lsp/testdata/errors/errors.go 1970-01-01 00:00:00.000000000 +0000 92349@@ -1,10 +0,0 @@ 92350-package errors 92351- 92352-import ( 92353- "golang.org/lsptests/types" 92354-) 92355- 92356-func _() { 92357- bob.Bob() //@complete(".") 92358- types.b //@complete(" //", Bob_interface) 92359-} 92360diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go 92361--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go 2000-01-01 00:00:00.000000000 -0000 92362+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go 1970-01-01 00:00:00.000000000 +0000 92363@@ -1,11 +0,0 @@ 92364-package extract 92365- 92366-func _() { 92367- a := 1 92368- a = 5 //@mark(exSt0, "a") 92369- a = a + 2 //@mark(exEn0, "2") 92370- //@extractfunc(exSt0, exEn0) 92371- b := a * 2 //@mark(exB, " b") 92372- _ = 3 + 4 //@mark(exEnd, "4") 92373- //@extractfunc(exB, exEnd) 92374-} 92375diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden 92376--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden 2000-01-01 00:00:00.000000000 -0000 92377+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden 1970-01-01 00:00:00.000000000 +0000 92378@@ -1,37 +0,0 @@ 92379--- functionextraction_extract_args_returns_5_2 -- 92380-package extract 92381- 92382-func _() { 92383- a := 1 92384- //@mark(exSt0, "a") 92385- a = newFunction(a) //@mark(exEn0, "2") 92386- //@extractfunc(exSt0, exEn0) 92387- b := a * 2 //@mark(exB, " b") 92388- _ = 3 + 4 //@mark(exEnd, "4") 92389- //@extractfunc(exB, exEnd) 92390-} 92391- 92392-func newFunction(a int) int { 92393- a = 5 92394- a = a + 2 92395- return a 92396-} 92397- 92398--- functionextraction_extract_args_returns_8_1 -- 92399-package extract 92400- 92401-func _() { 92402- a := 1 92403- a = 5 //@mark(exSt0, "a") 92404- a = a + 2 //@mark(exEn0, "2") 92405- //@extractfunc(exSt0, exEn0) 92406- //@mark(exB, " b") 92407- newFunction(a) //@mark(exEnd, "4") 92408- //@extractfunc(exB, exEnd) 92409-} 92410- 92411-func newFunction(a int) { 92412- b := a * 2 92413- _ = 3 + 4 92414-} 92415- 92416diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go 92417--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go 2000-01-01 00:00:00.000000000 -0000 92418+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go 1970-01-01 00:00:00.000000000 +0000 92419@@ -1,12 +0,0 @@ 92420-package extract 92421- 92422-func _() { 92423- a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a") 92424- // Comment on its own line //@mark(exSt19, "Comment") 92425- _ = 3 + 4 //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") 92426- // Comment right after 3 + 4 92427- 92428- // Comment after with space //@mark(exEn20, "Comment") 92429- 92430- //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) 92431-} 92432diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden 92433--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden 2000-01-01 00:00:00.000000000 -0000 92434+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden 1970-01-01 00:00:00.000000000 +0000 92435@@ -1,57 +0,0 @@ 92436--- functionextraction_extract_basic_comment_4_2 -- 92437-package extract 92438- 92439-func _() { 92440- /* comment in the middle of a line */ 92441- //@mark(exSt18, "a") 92442- // Comment on its own line //@mark(exSt19, "Comment") 92443- newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") 92444- // Comment right after 3 + 4 92445- 92446- // Comment after with space //@mark(exEn20, "Comment") 92447- 92448- //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) 92449-} 92450- 92451-func newFunction() { 92452- a := 1 92453- 92454- _ = 3 + 4 92455-} 92456- 92457--- functionextraction_extract_basic_comment_5_5 -- 92458-package extract 92459- 92460-func _() { 92461- a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a") 92462- // Comment on its own line //@mark(exSt19, "Comment") 92463- newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") 92464- // Comment right after 3 + 4 92465- 92466- // Comment after with space //@mark(exEn20, "Comment") 92467- 92468- //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) 92469-} 92470- 92471-func newFunction() { 92472- _ = 3 + 4 92473-} 92474- 92475--- functionextraction_extract_basic_comment_6_2 -- 92476-package extract 92477- 92478-func _() { 92479- a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a") 92480- // Comment on its own line //@mark(exSt19, "Comment") 92481- newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") 92482- // Comment right after 3 + 4 92483- 92484- // Comment after with space //@mark(exEn20, "Comment") 92485- 92486- //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) 92487-} 92488- 92489-func newFunction() { 92490- _ = 3 + 4 92491-} 92492- 92493diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go 92494--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go 2000-01-01 00:00:00.000000000 -0000 92495+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go 1970-01-01 00:00:00.000000000 +0000 92496@@ -1,8 +0,0 @@ 92497-package extract 92498- 92499-func _() { //@mark(exSt25, "{") 92500- a := 1 //@mark(exSt1, "a") 92501- _ = 3 + 4 //@mark(exEn1, "4") 92502- //@extractfunc(exSt1, exEn1) 92503- //@extractfunc(exSt25, exEn25) 92504-} //@mark(exEn25, "}") 92505diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden 92506--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden 2000-01-01 00:00:00.000000000 -0000 92507+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden 1970-01-01 00:00:00.000000000 +0000 92508@@ -1,30 +0,0 @@ 92509--- functionextraction_extract_basic_3_10 -- 92510-package extract 92511- 92512-func _() { //@mark(exSt25, "{") 92513- //@mark(exSt1, "a") 92514- newFunction() //@mark(exEn1, "4") 92515- //@extractfunc(exSt1, exEn1) 92516- //@extractfunc(exSt25, exEn25) 92517-} 92518- 92519-func newFunction() { 92520- a := 1 92521- _ = 3 + 4 92522-} //@mark(exEn25, "}") 92523- 92524--- functionextraction_extract_basic_4_2 -- 92525-package extract 92526- 92527-func _() { //@mark(exSt25, "{") 92528- //@mark(exSt1, "a") 92529- newFunction() //@mark(exEn1, "4") 92530- //@extractfunc(exSt1, exEn1) 92531- //@extractfunc(exSt25, exEn25) 92532-} 92533- 92534-func newFunction() { 92535- a := 1 92536- _ = 3 + 4 92537-} //@mark(exEn25, "}") 92538- 92539diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go 92540--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go 2000-01-01 00:00:00.000000000 -0000 92541+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go 1970-01-01 00:00:00.000000000 +0000 92542@@ -1,13 +0,0 @@ 92543-package extract 92544- 92545-import "fmt" 92546- 92547-func main() { 92548- x := []rune{} //@mark(exSt9, "x") 92549- s := "HELLO" 92550- for _, c := range s { 92551- x = append(x, c) 92552- } //@mark(exEn9, "}") 92553- //@extractfunc(exSt9, exEn9) 92554- fmt.Printf("%x\n", x) 92555-} 92556diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden 92557--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden 2000-01-01 00:00:00.000000000 -0000 92558+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden 1970-01-01 00:00:00.000000000 +0000 92559@@ -1,21 +0,0 @@ 92560--- functionextraction_extract_issue_44813_6_2 -- 92561-package extract 92562- 92563-import "fmt" 92564- 92565-func main() { 92566- //@mark(exSt9, "x") 92567- x := newFunction() //@mark(exEn9, "}") 92568- //@extractfunc(exSt9, exEn9) 92569- fmt.Printf("%x\n", x) 92570-} 92571- 92572-func newFunction() []rune { 92573- x := []rune{} 92574- s := "HELLO" 92575- for _, c := range s { 92576- x = append(x, c) 92577- } 92578- return x 92579-} 92580- 92581diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go 92582--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go 2000-01-01 00:00:00.000000000 -0000 92583+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go 1970-01-01 00:00:00.000000000 +0000 92584@@ -1,11 +0,0 @@ 92585-package extract 92586- 92587-import "strconv" 92588- 92589-func _() { 92590- i, err := strconv.Atoi("1") 92591- u, err := strconv.Atoi("2") //@extractfunc("u", ")") 92592- if i == u || err == nil { 92593- return 92594- } 92595-} 92596diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden 92597--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden 2000-01-01 00:00:00.000000000 -0000 92598+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden 1970-01-01 00:00:00.000000000 +0000 92599@@ -1,18 +0,0 @@ 92600--- functionextraction_extract_redefine_7_2 -- 92601-package extract 92602- 92603-import "strconv" 92604- 92605-func _() { 92606- i, err := strconv.Atoi("1") 92607- u, err := newFunction() //@extractfunc("u", ")") 92608- if i == u || err == nil { 92609- return 92610- } 92611-} 92612- 92613-func newFunction() (int, error) { 92614- u, err := strconv.Atoi("2") 92615- return u, err 92616-} 92617- 92618diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go 92619--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go 2000-01-01 00:00:00.000000000 -0000 92620+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go 1970-01-01 00:00:00.000000000 +0000 92621@@ -1,10 +0,0 @@ 92622-package extract 92623- 92624-func _() bool { 92625- x := 1 92626- if x == 0 { //@mark(exSt2, "if") 92627- return true 92628- } //@mark(exEn2, "}") 92629- return false 92630- //@extractfunc(exSt2, exEn2) 92631-} 92632diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden 92633--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden 2000-01-01 00:00:00.000000000 -0000 92634+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden 1970-01-01 00:00:00.000000000 +0000 92635@@ -1,21 +0,0 @@ 92636--- functionextraction_extract_return_basic_5_2 -- 92637-package extract 92638- 92639-func _() bool { 92640- x := 1 92641- //@mark(exSt2, "if") 92642- shouldReturn, returnValue := newFunction(x) 92643- if shouldReturn { 92644- return returnValue 92645- } //@mark(exEn2, "}") 92646- return false 92647- //@extractfunc(exSt2, exEn2) 92648-} 92649- 92650-func newFunction(x int) (bool, bool) { 92651- if x == 0 { 92652- return true, true 92653- } 92654- return false, false 92655-} 92656- 92657diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go 92658--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go 2000-01-01 00:00:00.000000000 -0000 92659+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go 1970-01-01 00:00:00.000000000 +0000 92660@@ -1,10 +0,0 @@ 92661-package extract 92662- 92663-func _() bool { 92664- x := 1 //@mark(exSt13, "x") 92665- if x == 0 { 92666- return true 92667- } 92668- return false //@mark(exEn13, "false") 92669- //@extractfunc(exSt13, exEn13) 92670-} 92671diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden 92672--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden 2000-01-01 00:00:00.000000000 -0000 92673+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden 1970-01-01 00:00:00.000000000 +0000 92674@@ -1,17 +0,0 @@ 92675--- functionextraction_extract_return_basic_nonnested_4_2 -- 92676-package extract 92677- 92678-func _() bool { 92679- //@mark(exSt13, "x") 92680- return newFunction() //@mark(exEn13, "false") 92681- //@extractfunc(exSt13, exEn13) 92682-} 92683- 92684-func newFunction() bool { 92685- x := 1 92686- if x == 0 { 92687- return true 92688- } 92689- return false 92690-} 92691- 92692diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go 92693--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go 2000-01-01 00:00:00.000000000 -0000 92694+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go 1970-01-01 00:00:00.000000000 +0000 92695@@ -1,17 +0,0 @@ 92696-package extract 92697- 92698-import "fmt" 92699- 92700-func _() (int, string, error) { 92701- x := 1 92702- y := "hello" 92703- z := "bye" //@mark(exSt3, "z") 92704- if y == z { 92705- return x, y, fmt.Errorf("same") 92706- } else { 92707- z = "hi" 92708- return x, z, nil 92709- } //@mark(exEn3, "}") 92710- return x, z, nil 92711- //@extractfunc(exSt3, exEn3) 92712-} 92713diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden 92714--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden 2000-01-01 00:00:00.000000000 -0000 92715+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden 1970-01-01 00:00:00.000000000 +0000 92716@@ -1,28 +0,0 @@ 92717--- functionextraction_extract_return_complex_8_2 -- 92718-package extract 92719- 92720-import "fmt" 92721- 92722-func _() (int, string, error) { 92723- x := 1 92724- y := "hello" 92725- //@mark(exSt3, "z") 92726- z, shouldReturn, returnValue, returnValue1, returnValue2 := newFunction(y, x) 92727- if shouldReturn { 92728- return returnValue, returnValue1, returnValue2 92729- } //@mark(exEn3, "}") 92730- return x, z, nil 92731- //@extractfunc(exSt3, exEn3) 92732-} 92733- 92734-func newFunction(y string, x int) (string, bool, int, string, error) { 92735- z := "bye" 92736- if y == z { 92737- return "", true, x, y, fmt.Errorf("same") 92738- } else { 92739- z = "hi" 92740- return "", true, x, z, nil 92741- } 92742- return z, false, 0, "", nil 92743-} 92744- 92745diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go 92746--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go 2000-01-01 00:00:00.000000000 -0000 92747+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go 1970-01-01 00:00:00.000000000 +0000 92748@@ -1,17 +0,0 @@ 92749-package extract 92750- 92751-import "fmt" 92752- 92753-func _() (int, string, error) { 92754- x := 1 92755- y := "hello" 92756- z := "bye" //@mark(exSt10, "z") 92757- if y == z { 92758- return x, y, fmt.Errorf("same") 92759- } else { 92760- z = "hi" 92761- return x, z, nil 92762- } 92763- return x, z, nil //@mark(exEn10, "nil") 92764- //@extractfunc(exSt10, exEn10) 92765-} 92766diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden 92767--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden 2000-01-01 00:00:00.000000000 -0000 92768+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden 1970-01-01 00:00:00.000000000 +0000 92769@@ -1,24 +0,0 @@ 92770--- functionextraction_extract_return_complex_nonnested_8_2 -- 92771-package extract 92772- 92773-import "fmt" 92774- 92775-func _() (int, string, error) { 92776- x := 1 92777- y := "hello" 92778- //@mark(exSt10, "z") 92779- return newFunction(y, x) //@mark(exEn10, "nil") 92780- //@extractfunc(exSt10, exEn10) 92781-} 92782- 92783-func newFunction(y string, x int) (int, string, error) { 92784- z := "bye" 92785- if y == z { 92786- return x, y, fmt.Errorf("same") 92787- } else { 92788- z = "hi" 92789- return x, z, nil 92790- } 92791- return x, z, nil 92792-} 92793- 92794diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go 92795--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go 2000-01-01 00:00:00.000000000 -0000 92796+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go 1970-01-01 00:00:00.000000000 +0000 92797@@ -1,13 +0,0 @@ 92798-package extract 92799- 92800-import "go/ast" 92801- 92802-func _() { 92803- ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { 92804- if n == nil { //@mark(exSt4, "if") 92805- return true 92806- } //@mark(exEn4, "}") 92807- return false 92808- }) 92809- //@extractfunc(exSt4, exEn4) 92810-} 92811diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden 92812--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden 2000-01-01 00:00:00.000000000 -0000 92813+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden 1970-01-01 00:00:00.000000000 +0000 92814@@ -1,24 +0,0 @@ 92815--- functionextraction_extract_return_func_lit_7_3 -- 92816-package extract 92817- 92818-import "go/ast" 92819- 92820-func _() { 92821- ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { 92822- //@mark(exSt4, "if") 92823- shouldReturn, returnValue := newFunction(n) 92824- if shouldReturn { 92825- return returnValue 92826- } //@mark(exEn4, "}") 92827- return false 92828- }) 92829- //@extractfunc(exSt4, exEn4) 92830-} 92831- 92832-func newFunction(n ast.Node) (bool, bool) { 92833- if n == nil { 92834- return true, true 92835- } 92836- return false, false 92837-} 92838- 92839diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go 92840--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go 2000-01-01 00:00:00.000000000 -0000 92841+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go 1970-01-01 00:00:00.000000000 +0000 92842@@ -1,13 +0,0 @@ 92843-package extract 92844- 92845-import "go/ast" 92846- 92847-func _() { 92848- ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { 92849- if n == nil { //@mark(exSt11, "if") 92850- return true 92851- } 92852- return false //@mark(exEn11, "false") 92853- }) 92854- //@extractfunc(exSt11, exEn11) 92855-} 92856diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden 92857--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden 2000-01-01 00:00:00.000000000 -0000 92858+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden 1970-01-01 00:00:00.000000000 +0000 92859@@ -1,20 +0,0 @@ 92860--- functionextraction_extract_return_func_lit_nonnested_7_3 -- 92861-package extract 92862- 92863-import "go/ast" 92864- 92865-func _() { 92866- ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { 92867- //@mark(exSt11, "if") 92868- return newFunction(n) //@mark(exEn11, "false") 92869- }) 92870- //@extractfunc(exSt11, exEn11) 92871-} 92872- 92873-func newFunction(n ast.Node) bool { 92874- if n == nil { 92875- return true 92876- } 92877- return false 92878-} 92879- 92880diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go 92881--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go 2000-01-01 00:00:00.000000000 -0000 92882+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go 1970-01-01 00:00:00.000000000 +0000 92883@@ -1,12 +0,0 @@ 92884-package extract 92885- 92886-func _() string { 92887- x := 1 92888- if x == 0 { //@mark(exSt5, "if") 92889- x = 3 92890- return "a" 92891- } //@mark(exEn5, "}") 92892- x = 2 92893- return "b" 92894- //@extractfunc(exSt5, exEn5) 92895-} 92896diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden 92897--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden 2000-01-01 00:00:00.000000000 -0000 92898+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden 1970-01-01 00:00:00.000000000 +0000 92899@@ -1,23 +0,0 @@ 92900--- functionextraction_extract_return_init_5_2 -- 92901-package extract 92902- 92903-func _() string { 92904- x := 1 92905- //@mark(exSt5, "if") 92906- shouldReturn, returnValue := newFunction(x) 92907- if shouldReturn { 92908- return returnValue 92909- } //@mark(exEn5, "}") 92910- x = 2 92911- return "b" 92912- //@extractfunc(exSt5, exEn5) 92913-} 92914- 92915-func newFunction(x int) (bool, string) { 92916- if x == 0 { 92917- x = 3 92918- return true, "a" 92919- } 92920- return false, "" 92921-} 92922- 92923diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go 92924--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go 2000-01-01 00:00:00.000000000 -0000 92925+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go 1970-01-01 00:00:00.000000000 +0000 92926@@ -1,12 +0,0 @@ 92927-package extract 92928- 92929-func _() string { 92930- x := 1 92931- if x == 0 { //@mark(exSt12, "if") 92932- x = 3 92933- return "a" 92934- } 92935- x = 2 92936- return "b" //@mark(exEn12, "\"b\"") 92937- //@extractfunc(exSt12, exEn12) 92938-} 92939diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden 92940--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden 2000-01-01 00:00:00.000000000 -0000 92941+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden 1970-01-01 00:00:00.000000000 +0000 92942@@ -1,19 +0,0 @@ 92943--- functionextraction_extract_return_init_nonnested_5_2 -- 92944-package extract 92945- 92946-func _() string { 92947- x := 1 92948- //@mark(exSt12, "if") 92949- return newFunction(x) //@mark(exEn12, "\"b\"") 92950- //@extractfunc(exSt12, exEn12) 92951-} 92952- 92953-func newFunction(x int) string { 92954- if x == 0 { 92955- x = 3 92956- return "a" 92957- } 92958- x = 2 92959- return "b" 92960-} 92961- 92962diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go 92963--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go 2000-01-01 00:00:00.000000000 -0000 92964+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go 1970-01-01 00:00:00.000000000 +0000 92965@@ -1,10 +0,0 @@ 92966-package extract 92967- 92968-func _() { 92969- newFunction := 1 92970- a := newFunction //@extractfunc("a", "newFunction") 92971-} 92972- 92973-func newFunction1() int { 92974- return 1 92975-} 92976diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden 92977--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden 2000-01-01 00:00:00.000000000 -0000 92978+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden 1970-01-01 00:00:00.000000000 +0000 92979@@ -1,16 +0,0 @@ 92980--- functionextraction_extract_scope_5_2 -- 92981-package extract 92982- 92983-func _() { 92984- newFunction := 1 92985- newFunction2(newFunction) //@extractfunc("a", "newFunction") 92986-} 92987- 92988-func newFunction2(newFunction int) { 92989- a := newFunction 92990-} 92991- 92992-func newFunction1() int { 92993- return 1 92994-} 92995- 92996diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go 92997--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go 2000-01-01 00:00:00.000000000 -0000 92998+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go 1970-01-01 00:00:00.000000000 +0000 92999@@ -1,9 +0,0 @@ 93000-package extract 93001- 93002-func _() { 93003- var a []int 93004- a = append(a, 2) //@mark(exSt6, "a") 93005- b := 4 //@mark(exEn6, "4") 93006- //@extractfunc(exSt6, exEn6) 93007- a = append(a, b) 93008-} 93009diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden 93010--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden 2000-01-01 00:00:00.000000000 -0000 93011+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden 1970-01-01 00:00:00.000000000 +0000 93012@@ -1,17 +0,0 @@ 93013--- functionextraction_extract_smart_initialization_5_2 -- 93014-package extract 93015- 93016-func _() { 93017- var a []int 93018- //@mark(exSt6, "a") 93019- a, b := newFunction(a) //@mark(exEn6, "4") 93020- //@extractfunc(exSt6, exEn6) 93021- a = append(a, b) 93022-} 93023- 93024-func newFunction(a []int) ([]int, int) { 93025- a = append(a, 2) 93026- b := 4 93027- return a, b 93028-} 93029- 93030diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go 93031--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go 2000-01-01 00:00:00.000000000 -0000 93032+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go 1970-01-01 00:00:00.000000000 +0000 93033@@ -1,11 +0,0 @@ 93034-package extract 93035- 93036-func _() { 93037- var b []int 93038- var a int 93039- a = 2 //@mark(exSt7, "a") 93040- b = []int{} 93041- b = append(b, a) //@mark(exEn7, ")") 93042- b[0] = 1 93043- //@extractfunc(exSt7, exEn7) 93044-} 93045diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden 93046--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden 2000-01-01 00:00:00.000000000 -0000 93047+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden 1970-01-01 00:00:00.000000000 +0000 93048@@ -1,19 +0,0 @@ 93049--- functionextraction_extract_smart_return_6_2 -- 93050-package extract 93051- 93052-func _() { 93053- var b []int 93054- var a int 93055- //@mark(exSt7, "a") 93056- b = newFunction(a, b) //@mark(exEn7, ")") 93057- b[0] = 1 93058- //@extractfunc(exSt7, exEn7) 93059-} 93060- 93061-func newFunction(a int, b []int) []int { 93062- a = 2 93063- b = []int{} 93064- b = append(b, a) 93065- return b 93066-} 93067- 93068diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go 93069--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go 2000-01-01 00:00:00.000000000 -0000 93070+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go 1970-01-01 00:00:00.000000000 +0000 93071@@ -1,14 +0,0 @@ 93072-package extract 93073- 93074-func _() { 93075- var b []int 93076- var a int 93077- a := 2 //@mark(exSt8, "a") 93078- b = []int{} 93079- b = append(b, a) //@mark(exEn8, ")") 93080- b[0] = 1 93081- if a == 2 { 93082- return 93083- } 93084- //@extractfunc(exSt8, exEn8) 93085-} 93086diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden 93087--- a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden 2000-01-01 00:00:00.000000000 -0000 93088+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden 1970-01-01 00:00:00.000000000 +0000 93089@@ -1,22 +0,0 @@ 93090--- functionextraction_extract_unnecessary_param_6_2 -- 93091-package extract 93092- 93093-func _() { 93094- var b []int 93095- var a int 93096- //@mark(exSt8, "a") 93097- a, b = newFunction(b) //@mark(exEn8, ")") 93098- b[0] = 1 93099- if a == 2 { 93100- return 93101- } 93102- //@extractfunc(exSt8, exEn8) 93103-} 93104- 93105-func newFunction(b []int) (int, []int) { 93106- a := 2 93107- b = []int{} 93108- b = append(b, a) 93109- return a, b 93110-} 93111- 93112diff -urN a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go 93113--- a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go 2000-01-01 00:00:00.000000000 -0000 93114+++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go 1970-01-01 00:00:00.000000000 +0000 93115@@ -1,24 +0,0 @@ 93116-package extract 93117- 93118-type A struct { 93119- x int 93120- y int 93121-} 93122- 93123-func (a *A) XLessThanYP() bool { 93124- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93125-} 93126- 93127-func (a *A) AddP() int { 93128- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93129- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93130-} 93131- 93132-func (a A) XLessThanY() bool { 93133- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93134-} 93135- 93136-func (a A) Add() int { 93137- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93138- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93139-} 93140diff -urN a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden 93141--- a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden 2000-01-01 00:00:00.000000000 -0000 93142+++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden 1970-01-01 00:00:00.000000000 +0000 93143@@ -1,364 +0,0 @@ 93144--- functionextraction_extract_basic_13_2 -- 93145-package extract 93146- 93147-type A struct { 93148- x int 93149- y int 93150-} 93151- 93152-func (a *A) XLessThanYP() bool { 93153- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93154-} 93155- 93156-func (a *A) AddP() int { 93157- sum := newFunction(a) //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93158- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93159-} 93160- 93161-func newFunction(a *A) int { 93162- sum := a.x + a.y 93163- return sum 93164-} 93165- 93166-func (a A) XLessThanY() bool { 93167- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93168-} 93169- 93170-func (a A) Add() int { 93171- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93172- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93173-} 93174- 93175--- functionextraction_extract_basic_14_2 -- 93176-package extract 93177- 93178-type A struct { 93179- x int 93180- y int 93181-} 93182- 93183-func (a *A) XLessThanYP() bool { 93184- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93185-} 93186- 93187-func (a *A) AddP() int { 93188- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93189- return newFunction(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") 93190-} 93191- 93192-func newFunction(sum int) int { 93193- return sum 93194-} 93195- 93196-func (a A) XLessThanY() bool { 93197- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93198-} 93199- 93200-func (a A) Add() int { 93201- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93202- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93203-} 93204- 93205--- functionextraction_extract_basic_18_2 -- 93206-package extract 93207- 93208-type A struct { 93209- x int 93210- y int 93211-} 93212- 93213-func (a *A) XLessThanYP() bool { 93214- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93215-} 93216- 93217-func (a *A) AddP() int { 93218- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93219- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93220-} 93221- 93222-func (a A) XLessThanY() bool { 93223- return newFunction(a) //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93224-} 93225- 93226-func newFunction(a A) bool { 93227- return a.x < a.y 93228-} 93229- 93230-func (a A) Add() int { 93231- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93232- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93233-} 93234- 93235--- functionextraction_extract_basic_22_2 -- 93236-package extract 93237- 93238-type A struct { 93239- x int 93240- y int 93241-} 93242- 93243-func (a *A) XLessThanYP() bool { 93244- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93245-} 93246- 93247-func (a *A) AddP() int { 93248- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93249- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93250-} 93251- 93252-func (a A) XLessThanY() bool { 93253- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93254-} 93255- 93256-func (a A) Add() int { 93257- sum := newFunction(a) //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93258- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93259-} 93260- 93261-func newFunction(a A) int { 93262- sum := a.x + a.y 93263- return sum 93264-} 93265- 93266--- functionextraction_extract_basic_23_2 -- 93267-package extract 93268- 93269-type A struct { 93270- x int 93271- y int 93272-} 93273- 93274-func (a *A) XLessThanYP() bool { 93275- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93276-} 93277- 93278-func (a *A) AddP() int { 93279- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93280- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93281-} 93282- 93283-func (a A) XLessThanY() bool { 93284- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93285-} 93286- 93287-func (a A) Add() int { 93288- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93289- return newFunction(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") 93290-} 93291- 93292-func newFunction(sum int) int { 93293- return sum 93294-} 93295- 93296--- functionextraction_extract_basic_9_2 -- 93297-package extract 93298- 93299-type A struct { 93300- x int 93301- y int 93302-} 93303- 93304-func (a *A) XLessThanYP() bool { 93305- return newFunction(a) //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93306-} 93307- 93308-func newFunction(a *A) bool { 93309- return a.x < a.y 93310-} 93311- 93312-func (a *A) AddP() int { 93313- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93314- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93315-} 93316- 93317-func (a A) XLessThanY() bool { 93318- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93319-} 93320- 93321-func (a A) Add() int { 93322- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93323- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93324-} 93325- 93326--- methodextraction_extract_basic_13_2 -- 93327-package extract 93328- 93329-type A struct { 93330- x int 93331- y int 93332-} 93333- 93334-func (a *A) XLessThanYP() bool { 93335- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93336-} 93337- 93338-func (a *A) AddP() int { 93339- sum := a.newMethod() //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93340- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93341-} 93342- 93343-func (a *A) newMethod() int { 93344- sum := a.x + a.y 93345- return sum 93346-} 93347- 93348-func (a A) XLessThanY() bool { 93349- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93350-} 93351- 93352-func (a A) Add() int { 93353- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93354- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93355-} 93356- 93357--- methodextraction_extract_basic_14_2 -- 93358-package extract 93359- 93360-type A struct { 93361- x int 93362- y int 93363-} 93364- 93365-func (a *A) XLessThanYP() bool { 93366- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93367-} 93368- 93369-func (a *A) AddP() int { 93370- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93371- return a.newMethod(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") 93372-} 93373- 93374-func (*A) newMethod(sum int) int { 93375- return sum 93376-} 93377- 93378-func (a A) XLessThanY() bool { 93379- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93380-} 93381- 93382-func (a A) Add() int { 93383- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93384- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93385-} 93386- 93387--- methodextraction_extract_basic_18_2 -- 93388-package extract 93389- 93390-type A struct { 93391- x int 93392- y int 93393-} 93394- 93395-func (a *A) XLessThanYP() bool { 93396- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93397-} 93398- 93399-func (a *A) AddP() int { 93400- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93401- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93402-} 93403- 93404-func (a A) XLessThanY() bool { 93405- return a.newMethod() //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93406-} 93407- 93408-func (a A) newMethod() bool { 93409- return a.x < a.y 93410-} 93411- 93412-func (a A) Add() int { 93413- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93414- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93415-} 93416- 93417--- methodextraction_extract_basic_22_2 -- 93418-package extract 93419- 93420-type A struct { 93421- x int 93422- y int 93423-} 93424- 93425-func (a *A) XLessThanYP() bool { 93426- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93427-} 93428- 93429-func (a *A) AddP() int { 93430- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93431- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93432-} 93433- 93434-func (a A) XLessThanY() bool { 93435- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93436-} 93437- 93438-func (a A) Add() int { 93439- sum := a.newMethod() //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93440- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93441-} 93442- 93443-func (a A) newMethod() int { 93444- sum := a.x + a.y 93445- return sum 93446-} 93447- 93448--- methodextraction_extract_basic_23_2 -- 93449-package extract 93450- 93451-type A struct { 93452- x int 93453- y int 93454-} 93455- 93456-func (a *A) XLessThanYP() bool { 93457- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93458-} 93459- 93460-func (a *A) AddP() int { 93461- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93462- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93463-} 93464- 93465-func (a A) XLessThanY() bool { 93466- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93467-} 93468- 93469-func (a A) Add() int { 93470- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93471- return a.newMethod(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") 93472-} 93473- 93474-func (A) newMethod(sum int) int { 93475- return sum 93476-} 93477- 93478--- methodextraction_extract_basic_9_2 -- 93479-package extract 93480- 93481-type A struct { 93482- x int 93483- y int 93484-} 93485- 93486-func (a *A) XLessThanYP() bool { 93487- return a.newMethod() //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93488-} 93489- 93490-func (a *A) newMethod() bool { 93491- return a.x < a.y 93492-} 93493- 93494-func (a *A) AddP() int { 93495- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93496- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93497-} 93498- 93499-func (a A) XLessThanY() bool { 93500- return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") 93501-} 93502- 93503-func (a A) Add() int { 93504- sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") 93505- return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") 93506-} 93507- 93508diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go 93509--- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go 2000-01-01 00:00:00.000000000 -0000 93510+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go 1970-01-01 00:00:00.000000000 +0000 93511@@ -1,6 +0,0 @@ 93512-package extract 93513- 93514-func _() { 93515- var _ = 1 + 2 //@suggestedfix("1", "refactor.extract", "") 93516- var _ = 3 + 4 //@suggestedfix("3 + 4", "refactor.extract", "") 93517-} 93518diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden 93519--- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden 2000-01-01 00:00:00.000000000 -0000 93520+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden 1970-01-01 00:00:00.000000000 +0000 93521@@ -1,18 +0,0 @@ 93522--- suggestedfix_extract_basic_lit_4_10 -- 93523-package extract 93524- 93525-func _() { 93526- x := 1 93527- var _ = x + 2 //@suggestedfix("1", "refactor.extract", "") 93528- var _ = 3 + 4 //@suggestedfix("3 + 4", "refactor.extract", "") 93529-} 93530- 93531--- suggestedfix_extract_basic_lit_5_10 -- 93532-package extract 93533- 93534-func _() { 93535- var _ = 1 + 2 //@suggestedfix("1", "refactor.extract", "") 93536- x := 3 + 4 93537- var _ = x //@suggestedfix("3 + 4", "refactor.extract", "") 93538-} 93539- 93540diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go 93541--- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go 2000-01-01 00:00:00.000000000 -0000 93542+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go 1970-01-01 00:00:00.000000000 +0000 93543@@ -1,9 +0,0 @@ 93544-package extract 93545- 93546-import "strconv" 93547- 93548-func _() { 93549- x0 := append([]int{}, 1) //@suggestedfix("append([]int{}, 1)", "refactor.extract", "") 93550- str := "1" 93551- b, err := strconv.Atoi(str) //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "") 93552-} 93553diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden 93554--- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden 2000-01-01 00:00:00.000000000 -0000 93555+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden 1970-01-01 00:00:00.000000000 +0000 93556@@ -1,24 +0,0 @@ 93557--- suggestedfix_extract_func_call_6_8 -- 93558-package extract 93559- 93560-import "strconv" 93561- 93562-func _() { 93563- x := append([]int{}, 1) 93564- x0 := x //@suggestedfix("append([]int{}, 1)", "refactor.extract", "") 93565- str := "1" 93566- b, err := strconv.Atoi(str) //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "") 93567-} 93568- 93569--- suggestedfix_extract_func_call_8_12 -- 93570-package extract 93571- 93572-import "strconv" 93573- 93574-func _() { 93575- x0 := append([]int{}, 1) //@suggestedfix("append([]int{}, 1)", "refactor.extract", "") 93576- str := "1" 93577- x, x1 := strconv.Atoi(str) 93578- b, err := x, x1 //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "") 93579-} 93580- 93581diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go 93582--- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go 2000-01-01 00:00:00.000000000 -0000 93583+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go 1970-01-01 00:00:00.000000000 +0000 93584@@ -1,13 +0,0 @@ 93585-package extract 93586- 93587-import "go/ast" 93588- 93589-func _() { 93590- x0 := 0 93591- if true { 93592- y := ast.CompositeLit{} //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "") 93593- } 93594- if true { 93595- x1 := !false //@suggestedfix("!false", "refactor.extract", "") 93596- } 93597-} 93598diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden 93599--- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden 2000-01-01 00:00:00.000000000 -0000 93600+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden 1970-01-01 00:00:00.000000000 +0000 93601@@ -1,32 +0,0 @@ 93602--- suggestedfix_extract_scope_11_9 -- 93603-package extract 93604- 93605-import "go/ast" 93606- 93607-func _() { 93608- x0 := 0 93609- if true { 93610- y := ast.CompositeLit{} //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "") 93611- } 93612- if true { 93613- x := !false 93614- x1 := x //@suggestedfix("!false", "refactor.extract", "") 93615- } 93616-} 93617- 93618--- suggestedfix_extract_scope_8_8 -- 93619-package extract 93620- 93621-import "go/ast" 93622- 93623-func _() { 93624- x0 := 0 93625- if true { 93626- x := ast.CompositeLit{} 93627- y := x //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "") 93628- } 93629- if true { 93630- x1 := !false //@suggestedfix("!false", "refactor.extract", "") 93631- } 93632-} 93633- 93634diff -urN a/gopls/internal/lsp/testdata/fieldlist/field_list.go b/gopls/internal/lsp/testdata/fieldlist/field_list.go 93635--- a/gopls/internal/lsp/testdata/fieldlist/field_list.go 2000-01-01 00:00:00.000000000 -0000 93636+++ b/gopls/internal/lsp/testdata/fieldlist/field_list.go 1970-01-01 00:00:00.000000000 +0000 93637@@ -1,27 +0,0 @@ 93638-package fieldlist 93639- 93640-var myInt int //@item(flVar, "myInt", "int", "var") 93641-type myType int //@item(flType, "myType", "int", "type") 93642- 93643-func (my) _() {} //@complete(") _", flType) 93644-func (my my) _() {} //@complete(" my)"),complete(") _", flType) 93645- 93646-func (myType) _() {} //@complete(") {", flType) 93647- 93648-func (myType) _(my my) {} //@complete(" my)"),complete(") {", flType) 93649- 93650-func (myType) _() my {} //@complete(" {", flType) 93651- 93652-func (myType) _() (my my) {} //@complete(" my"),complete(") {", flType) 93653- 93654-func _() { 93655- var _ struct { 93656- //@complete("", flType) 93657- m my //@complete(" my"),complete(" //", flType) 93658- } 93659- 93660- var _ interface { 93661- //@complete("", flType) 93662- m() my //@complete("("),complete(" //", flType) 93663- } 93664-} 93665diff -urN a/gopls/internal/lsp/testdata/fillstruct/a2.go b/gopls/internal/lsp/testdata/fillstruct/a2.go 93666--- a/gopls/internal/lsp/testdata/fillstruct/a2.go 2000-01-01 00:00:00.000000000 -0000 93667+++ b/gopls/internal/lsp/testdata/fillstruct/a2.go 1970-01-01 00:00:00.000000000 +0000 93668@@ -1,29 +0,0 @@ 93669-package fillstruct 93670- 93671-type typedStruct struct { 93672- m map[string]int 93673- s []int 93674- c chan int 93675- c1 <-chan int 93676- a [2]string 93677-} 93678- 93679-var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93680- 93681-type funStruct struct { 93682- fn func(i int) int 93683-} 93684- 93685-var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93686- 93687-type funStructCompex struct { 93688- fn func(i int, s string) (string, int) 93689-} 93690- 93691-var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93692- 93693-type funStructEmpty struct { 93694- fn func() 93695-} 93696- 93697-var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93698diff -urN a/gopls/internal/lsp/testdata/fillstruct/a2.go.golden b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden 93699--- a/gopls/internal/lsp/testdata/fillstruct/a2.go.golden 2000-01-01 00:00:00.000000000 -0000 93700+++ b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden 1970-01-01 00:00:00.000000000 +0000 93701@@ -1,139 +0,0 @@ 93702--- suggestedfix_a2_11_21 -- 93703-package fillstruct 93704- 93705-type typedStruct struct { 93706- m map[string]int 93707- s []int 93708- c chan int 93709- c1 <-chan int 93710- a [2]string 93711-} 93712- 93713-var _ = typedStruct{ 93714- m: map[string]int{}, 93715- s: []int{}, 93716- c: make(chan int), 93717- c1: make(<-chan int), 93718- a: [2]string{}, 93719-} //@suggestedfix("}", "refactor.rewrite", "Fill") 93720- 93721-type funStruct struct { 93722- fn func(i int) int 93723-} 93724- 93725-var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93726- 93727-type funStructCompex struct { 93728- fn func(i int, s string) (string, int) 93729-} 93730- 93731-var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93732- 93733-type funStructEmpty struct { 93734- fn func() 93735-} 93736- 93737-var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93738- 93739--- suggestedfix_a2_17_19 -- 93740-package fillstruct 93741- 93742-type typedStruct struct { 93743- m map[string]int 93744- s []int 93745- c chan int 93746- c1 <-chan int 93747- a [2]string 93748-} 93749- 93750-var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93751- 93752-type funStruct struct { 93753- fn func(i int) int 93754-} 93755- 93756-var _ = funStruct{ 93757- fn: func(i int) int { 93758- }, 93759-} //@suggestedfix("}", "refactor.rewrite", "Fill") 93760- 93761-type funStructCompex struct { 93762- fn func(i int, s string) (string, int) 93763-} 93764- 93765-var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93766- 93767-type funStructEmpty struct { 93768- fn func() 93769-} 93770- 93771-var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93772- 93773--- suggestedfix_a2_23_25 -- 93774-package fillstruct 93775- 93776-type typedStruct struct { 93777- m map[string]int 93778- s []int 93779- c chan int 93780- c1 <-chan int 93781- a [2]string 93782-} 93783- 93784-var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93785- 93786-type funStruct struct { 93787- fn func(i int) int 93788-} 93789- 93790-var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93791- 93792-type funStructCompex struct { 93793- fn func(i int, s string) (string, int) 93794-} 93795- 93796-var _ = funStructCompex{ 93797- fn: func(i int, s string) (string, int) { 93798- }, 93799-} //@suggestedfix("}", "refactor.rewrite", "Fill") 93800- 93801-type funStructEmpty struct { 93802- fn func() 93803-} 93804- 93805-var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93806- 93807--- suggestedfix_a2_29_24 -- 93808-package fillstruct 93809- 93810-type typedStruct struct { 93811- m map[string]int 93812- s []int 93813- c chan int 93814- c1 <-chan int 93815- a [2]string 93816-} 93817- 93818-var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93819- 93820-type funStruct struct { 93821- fn func(i int) int 93822-} 93823- 93824-var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93825- 93826-type funStructCompex struct { 93827- fn func(i int, s string) (string, int) 93828-} 93829- 93830-var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93831- 93832-type funStructEmpty struct { 93833- fn func() 93834-} 93835- 93836-var _ = funStructEmpty{ 93837- fn: func() { 93838- }, 93839-} //@suggestedfix("}", "refactor.rewrite", "Fill") 93840- 93841diff -urN a/gopls/internal/lsp/testdata/fillstruct/a3.go b/gopls/internal/lsp/testdata/fillstruct/a3.go 93842--- a/gopls/internal/lsp/testdata/fillstruct/a3.go 2000-01-01 00:00:00.000000000 -0000 93843+++ b/gopls/internal/lsp/testdata/fillstruct/a3.go 1970-01-01 00:00:00.000000000 +0000 93844@@ -1,42 +0,0 @@ 93845-package fillstruct 93846- 93847-import ( 93848- "go/ast" 93849- "go/token" 93850-) 93851- 93852-type Foo struct { 93853- A int 93854-} 93855- 93856-type Bar struct { 93857- X *Foo 93858- Y *Foo 93859-} 93860- 93861-var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93862- 93863-type importedStruct struct { 93864- m map[*ast.CompositeLit]ast.Field 93865- s []ast.BadExpr 93866- a [3]token.Token 93867- c chan ast.EmptyStmt 93868- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 93869- st ast.CompositeLit 93870-} 93871- 93872-var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93873- 93874-type pointerBuiltinStruct struct { 93875- b *bool 93876- s *string 93877- i *int 93878-} 93879- 93880-var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93881- 93882-var _ = []ast.BasicLit{ 93883- {}, //@suggestedfix("}", "refactor.rewrite", "Fill") 93884-} 93885- 93886-var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") 93887diff -urN a/gopls/internal/lsp/testdata/fillstruct/a3.go.golden b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden 93888--- a/gopls/internal/lsp/testdata/fillstruct/a3.go.golden 2000-01-01 00:00:00.000000000 -0000 93889+++ b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden 1970-01-01 00:00:00.000000000 +0000 93890@@ -1,243 +0,0 @@ 93891--- suggestedfix_a3_17_13 -- 93892-package fillstruct 93893- 93894-import ( 93895- "go/ast" 93896- "go/token" 93897-) 93898- 93899-type Foo struct { 93900- A int 93901-} 93902- 93903-type Bar struct { 93904- X *Foo 93905- Y *Foo 93906-} 93907- 93908-var _ = Bar{ 93909- X: &Foo{}, 93910- Y: &Foo{}, 93911-} //@suggestedfix("}", "refactor.rewrite", "Fill") 93912- 93913-type importedStruct struct { 93914- m map[*ast.CompositeLit]ast.Field 93915- s []ast.BadExpr 93916- a [3]token.Token 93917- c chan ast.EmptyStmt 93918- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 93919- st ast.CompositeLit 93920-} 93921- 93922-var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93923- 93924-type pointerBuiltinStruct struct { 93925- b *bool 93926- s *string 93927- i *int 93928-} 93929- 93930-var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93931- 93932-var _ = []ast.BasicLit{ 93933- {}, //@suggestedfix("}", "refactor.rewrite", "Fill") 93934-} 93935- 93936-var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") 93937- 93938--- suggestedfix_a3_28_24 -- 93939-package fillstruct 93940- 93941-import ( 93942- "go/ast" 93943- "go/token" 93944-) 93945- 93946-type Foo struct { 93947- A int 93948-} 93949- 93950-type Bar struct { 93951- X *Foo 93952- Y *Foo 93953-} 93954- 93955-var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93956- 93957-type importedStruct struct { 93958- m map[*ast.CompositeLit]ast.Field 93959- s []ast.BadExpr 93960- a [3]token.Token 93961- c chan ast.EmptyStmt 93962- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 93963- st ast.CompositeLit 93964-} 93965- 93966-var _ = importedStruct{ 93967- m: map[*ast.CompositeLit]ast.Field{}, 93968- s: []ast.BadExpr{}, 93969- a: [3]token.Token{}, 93970- c: make(chan ast.EmptyStmt), 93971- fn: func(ast_decl ast.DeclStmt) ast.Ellipsis { 93972- }, 93973- st: ast.CompositeLit{}, 93974-} //@suggestedfix("}", "refactor.rewrite", "Fill") 93975- 93976-type pointerBuiltinStruct struct { 93977- b *bool 93978- s *string 93979- i *int 93980-} 93981- 93982-var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 93983- 93984-var _ = []ast.BasicLit{ 93985- {}, //@suggestedfix("}", "refactor.rewrite", "Fill") 93986-} 93987- 93988-var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") 93989- 93990--- suggestedfix_a3_36_30 -- 93991-package fillstruct 93992- 93993-import ( 93994- "go/ast" 93995- "go/token" 93996-) 93997- 93998-type Foo struct { 93999- A int 94000-} 94001- 94002-type Bar struct { 94003- X *Foo 94004- Y *Foo 94005-} 94006- 94007-var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94008- 94009-type importedStruct struct { 94010- m map[*ast.CompositeLit]ast.Field 94011- s []ast.BadExpr 94012- a [3]token.Token 94013- c chan ast.EmptyStmt 94014- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 94015- st ast.CompositeLit 94016-} 94017- 94018-var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94019- 94020-type pointerBuiltinStruct struct { 94021- b *bool 94022- s *string 94023- i *int 94024-} 94025- 94026-var _ = pointerBuiltinStruct{ 94027- b: new(bool), 94028- s: new(string), 94029- i: new(int), 94030-} //@suggestedfix("}", "refactor.rewrite", "Fill") 94031- 94032-var _ = []ast.BasicLit{ 94033- {}, //@suggestedfix("}", "refactor.rewrite", "Fill") 94034-} 94035- 94036-var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") 94037- 94038--- suggestedfix_a3_39_3 -- 94039-package fillstruct 94040- 94041-import ( 94042- "go/ast" 94043- "go/token" 94044-) 94045- 94046-type Foo struct { 94047- A int 94048-} 94049- 94050-type Bar struct { 94051- X *Foo 94052- Y *Foo 94053-} 94054- 94055-var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94056- 94057-type importedStruct struct { 94058- m map[*ast.CompositeLit]ast.Field 94059- s []ast.BadExpr 94060- a [3]token.Token 94061- c chan ast.EmptyStmt 94062- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 94063- st ast.CompositeLit 94064-} 94065- 94066-var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94067- 94068-type pointerBuiltinStruct struct { 94069- b *bool 94070- s *string 94071- i *int 94072-} 94073- 94074-var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94075- 94076-var _ = []ast.BasicLit{ 94077- { 94078- ValuePos: 0, 94079- Kind: 0, 94080- Value: "", 94081- }, //@suggestedfix("}", "refactor.rewrite", "Fill") 94082-} 94083- 94084-var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") 94085- 94086--- suggestedfix_a3_42_25 -- 94087-package fillstruct 94088- 94089-import ( 94090- "go/ast" 94091- "go/token" 94092-) 94093- 94094-type Foo struct { 94095- A int 94096-} 94097- 94098-type Bar struct { 94099- X *Foo 94100- Y *Foo 94101-} 94102- 94103-var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94104- 94105-type importedStruct struct { 94106- m map[*ast.CompositeLit]ast.Field 94107- s []ast.BadExpr 94108- a [3]token.Token 94109- c chan ast.EmptyStmt 94110- fn func(ast_decl ast.DeclStmt) ast.Ellipsis 94111- st ast.CompositeLit 94112-} 94113- 94114-var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94115- 94116-type pointerBuiltinStruct struct { 94117- b *bool 94118- s *string 94119- i *int 94120-} 94121- 94122-var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94123- 94124-var _ = []ast.BasicLit{ 94125- {}, //@suggestedfix("}", "refactor.rewrite", "Fill") 94126-} 94127- 94128-var _ = []ast.BasicLit{{ 94129- ValuePos: 0, 94130- Kind: 0, 94131- Value: "", 94132-}} //@suggestedfix("}", "refactor.rewrite", "Fill") 94133- 94134diff -urN a/gopls/internal/lsp/testdata/fillstruct/a4.go b/gopls/internal/lsp/testdata/fillstruct/a4.go 94135--- a/gopls/internal/lsp/testdata/fillstruct/a4.go 2000-01-01 00:00:00.000000000 -0000 94136+++ b/gopls/internal/lsp/testdata/fillstruct/a4.go 1970-01-01 00:00:00.000000000 +0000 94137@@ -1,39 +0,0 @@ 94138-package fillstruct 94139- 94140-import "go/ast" 94141- 94142-type iStruct struct { 94143- X int 94144-} 94145- 94146-type sStruct struct { 94147- str string 94148-} 94149- 94150-type multiFill struct { 94151- num int 94152- strin string 94153- arr []int 94154-} 94155- 94156-type assignStruct struct { 94157- n ast.Node 94158-} 94159- 94160-func fill() { 94161- var x int 94162- var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94163- 94164- var s string 94165- var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94166- 94167- var n int 94168- _ = []int{} 94169- if true { 94170- arr := []int{1, 2} 94171- } 94172- var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94173- 94174- var node *ast.CompositeLit 94175- var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94176-} 94177diff -urN a/gopls/internal/lsp/testdata/fillstruct/a4.go.golden b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden 94178--- a/gopls/internal/lsp/testdata/fillstruct/a4.go.golden 2000-01-01 00:00:00.000000000 -0000 94179+++ b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden 1970-01-01 00:00:00.000000000 +0000 94180@@ -1,174 +0,0 @@ 94181--- suggestedfix_a4_25_18 -- 94182-package fillstruct 94183- 94184-import "go/ast" 94185- 94186-type iStruct struct { 94187- X int 94188-} 94189- 94190-type sStruct struct { 94191- str string 94192-} 94193- 94194-type multiFill struct { 94195- num int 94196- strin string 94197- arr []int 94198-} 94199- 94200-type assignStruct struct { 94201- n ast.Node 94202-} 94203- 94204-func fill() { 94205- var x int 94206- var _ = iStruct{ 94207- X: x, 94208- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94209- 94210- var s string 94211- var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94212- 94213- var n int 94214- _ = []int{} 94215- if true { 94216- arr := []int{1, 2} 94217- } 94218- var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94219- 94220- var node *ast.CompositeLit 94221- var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94222-} 94223- 94224--- suggestedfix_a4_28_18 -- 94225-package fillstruct 94226- 94227-import "go/ast" 94228- 94229-type iStruct struct { 94230- X int 94231-} 94232- 94233-type sStruct struct { 94234- str string 94235-} 94236- 94237-type multiFill struct { 94238- num int 94239- strin string 94240- arr []int 94241-} 94242- 94243-type assignStruct struct { 94244- n ast.Node 94245-} 94246- 94247-func fill() { 94248- var x int 94249- var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94250- 94251- var s string 94252- var _ = sStruct{ 94253- str: s, 94254- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94255- 94256- var n int 94257- _ = []int{} 94258- if true { 94259- arr := []int{1, 2} 94260- } 94261- var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94262- 94263- var node *ast.CompositeLit 94264- var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94265-} 94266- 94267--- suggestedfix_a4_35_20 -- 94268-package fillstruct 94269- 94270-import "go/ast" 94271- 94272-type iStruct struct { 94273- X int 94274-} 94275- 94276-type sStruct struct { 94277- str string 94278-} 94279- 94280-type multiFill struct { 94281- num int 94282- strin string 94283- arr []int 94284-} 94285- 94286-type assignStruct struct { 94287- n ast.Node 94288-} 94289- 94290-func fill() { 94291- var x int 94292- var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94293- 94294- var s string 94295- var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94296- 94297- var n int 94298- _ = []int{} 94299- if true { 94300- arr := []int{1, 2} 94301- } 94302- var _ = multiFill{ 94303- num: n, 94304- strin: s, 94305- arr: []int{}, 94306- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94307- 94308- var node *ast.CompositeLit 94309- var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94310-} 94311- 94312--- suggestedfix_a4_38_23 -- 94313-package fillstruct 94314- 94315-import "go/ast" 94316- 94317-type iStruct struct { 94318- X int 94319-} 94320- 94321-type sStruct struct { 94322- str string 94323-} 94324- 94325-type multiFill struct { 94326- num int 94327- strin string 94328- arr []int 94329-} 94330- 94331-type assignStruct struct { 94332- n ast.Node 94333-} 94334- 94335-func fill() { 94336- var x int 94337- var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94338- 94339- var s string 94340- var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94341- 94342- var n int 94343- _ = []int{} 94344- if true { 94345- arr := []int{1, 2} 94346- } 94347- var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94348- 94349- var node *ast.CompositeLit 94350- var _ = assignStruct{ 94351- n: node, 94352- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94353-} 94354- 94355diff -urN a/gopls/internal/lsp/testdata/fillstruct/a.go b/gopls/internal/lsp/testdata/fillstruct/a.go 94356--- a/gopls/internal/lsp/testdata/fillstruct/a.go 2000-01-01 00:00:00.000000000 -0000 94357+++ b/gopls/internal/lsp/testdata/fillstruct/a.go 1970-01-01 00:00:00.000000000 +0000 94358@@ -1,27 +0,0 @@ 94359-package fillstruct 94360- 94361-import ( 94362- "golang.org/lsptests/fillstruct/data" 94363-) 94364- 94365-type basicStruct struct { 94366- foo int 94367-} 94368- 94369-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94370- 94371-type twoArgStruct struct { 94372- foo int 94373- bar string 94374-} 94375- 94376-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94377- 94378-type nestedStruct struct { 94379- bar string 94380- basic basicStruct 94381-} 94382- 94383-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94384- 94385-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94386diff -urN a/gopls/internal/lsp/testdata/fillstruct/a.go.golden b/gopls/internal/lsp/testdata/fillstruct/a.go.golden 94387--- a/gopls/internal/lsp/testdata/fillstruct/a.go.golden 2000-01-01 00:00:00.000000000 -0000 94388+++ b/gopls/internal/lsp/testdata/fillstruct/a.go.golden 1970-01-01 00:00:00.000000000 +0000 94389@@ -1,126 +0,0 @@ 94390--- suggestedfix_a_11_21 -- 94391-package fillstruct 94392- 94393-import ( 94394- "golang.org/lsptests/fillstruct/data" 94395-) 94396- 94397-type basicStruct struct { 94398- foo int 94399-} 94400- 94401-var _ = basicStruct{ 94402- foo: 0, 94403-} //@suggestedfix("}", "refactor.rewrite", "Fill") 94404- 94405-type twoArgStruct struct { 94406- foo int 94407- bar string 94408-} 94409- 94410-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94411- 94412-type nestedStruct struct { 94413- bar string 94414- basic basicStruct 94415-} 94416- 94417-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94418- 94419-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94420- 94421--- suggestedfix_a_18_22 -- 94422-package fillstruct 94423- 94424-import ( 94425- "golang.org/lsptests/fillstruct/data" 94426-) 94427- 94428-type basicStruct struct { 94429- foo int 94430-} 94431- 94432-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94433- 94434-type twoArgStruct struct { 94435- foo int 94436- bar string 94437-} 94438- 94439-var _ = twoArgStruct{ 94440- foo: 0, 94441- bar: "", 94442-} //@suggestedfix("}", "refactor.rewrite", "Fill") 94443- 94444-type nestedStruct struct { 94445- bar string 94446- basic basicStruct 94447-} 94448- 94449-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94450- 94451-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94452- 94453--- suggestedfix_a_25_22 -- 94454-package fillstruct 94455- 94456-import ( 94457- "golang.org/lsptests/fillstruct/data" 94458-) 94459- 94460-type basicStruct struct { 94461- foo int 94462-} 94463- 94464-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94465- 94466-type twoArgStruct struct { 94467- foo int 94468- bar string 94469-} 94470- 94471-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94472- 94473-type nestedStruct struct { 94474- bar string 94475- basic basicStruct 94476-} 94477- 94478-var _ = nestedStruct{ 94479- bar: "", 94480- basic: basicStruct{}, 94481-} //@suggestedfix("}", "refactor.rewrite", "Fill") 94482- 94483-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94484- 94485--- suggestedfix_a_27_16 -- 94486-package fillstruct 94487- 94488-import ( 94489- "golang.org/lsptests/fillstruct/data" 94490-) 94491- 94492-type basicStruct struct { 94493- foo int 94494-} 94495- 94496-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94497- 94498-type twoArgStruct struct { 94499- foo int 94500- bar string 94501-} 94502- 94503-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94504- 94505-type nestedStruct struct { 94506- bar string 94507- basic basicStruct 94508-} 94509- 94510-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94511- 94512-var _ = data.B{ 94513- ExportedInt: 0, 94514-} //@suggestedfix("}", "refactor.rewrite", "Fill") 94515- 94516diff -urN a/gopls/internal/lsp/testdata/fillstruct/data/a.go b/gopls/internal/lsp/testdata/fillstruct/data/a.go 94517--- a/gopls/internal/lsp/testdata/fillstruct/data/a.go 2000-01-01 00:00:00.000000000 -0000 94518+++ b/gopls/internal/lsp/testdata/fillstruct/data/a.go 1970-01-01 00:00:00.000000000 +0000 94519@@ -1,6 +0,0 @@ 94520-package data 94521- 94522-type B struct { 94523- ExportedInt int 94524- unexportedInt int 94525-} 94526diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go 94527--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go 2000-01-01 00:00:00.000000000 -0000 94528+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go 1970-01-01 00:00:00.000000000 +0000 94529@@ -1,14 +0,0 @@ 94530-package fillstruct 94531- 94532-type StructAnon struct { 94533- a struct{} 94534- b map[string]interface{} 94535- c map[string]struct { 94536- d int 94537- e bool 94538- } 94539-} 94540- 94541-func fill() { 94542- _ := StructAnon{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94543-} 94544diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden 94545--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden 2000-01-01 00:00:00.000000000 -0000 94546+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden 1970-01-01 00:00:00.000000000 +0000 94547@@ -1,20 +0,0 @@ 94548--- suggestedfix_fill_struct_anon_13_18 -- 94549-package fillstruct 94550- 94551-type StructAnon struct { 94552- a struct{} 94553- b map[string]interface{} 94554- c map[string]struct { 94555- d int 94556- e bool 94557- } 94558-} 94559- 94560-func fill() { 94561- _ := StructAnon{ 94562- a: struct{}{}, 94563- b: map[string]interface{}{}, 94564- c: map[string]struct{d int; e bool}{}, 94565- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94566-} 94567- 94568diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go 94569--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go 2000-01-01 00:00:00.000000000 -0000 94570+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go 1970-01-01 00:00:00.000000000 +0000 94571@@ -1,26 +0,0 @@ 94572-package fillstruct 94573- 94574-type StructA struct { 94575- unexportedIntField int 94576- ExportedIntField int 94577- MapA map[int]string 94578- Array []int 94579- StructB 94580-} 94581- 94582-type StructA2 struct { 94583- B *StructB 94584-} 94585- 94586-type StructA3 struct { 94587- B StructB 94588-} 94589- 94590-func fill() { 94591- a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94592- b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94593- c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94594- if true { 94595- _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94596- } 94597-} 94598diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden 94599--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden 2000-01-01 00:00:00.000000000 -0000 94600+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden 1970-01-01 00:00:00.000000000 +0000 94601@@ -1,124 +0,0 @@ 94602--- suggestedfix_fill_struct_20_15 -- 94603-package fillstruct 94604- 94605-type StructA struct { 94606- unexportedIntField int 94607- ExportedIntField int 94608- MapA map[int]string 94609- Array []int 94610- StructB 94611-} 94612- 94613-type StructA2 struct { 94614- B *StructB 94615-} 94616- 94617-type StructA3 struct { 94618- B StructB 94619-} 94620- 94621-func fill() { 94622- a := StructA{ 94623- unexportedIntField: 0, 94624- ExportedIntField: 0, 94625- MapA: map[int]string{}, 94626- Array: []int{}, 94627- StructB: StructB{}, 94628- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94629- b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94630- c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94631- if true { 94632- _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94633- } 94634-} 94635- 94636--- suggestedfix_fill_struct_21_16 -- 94637-package fillstruct 94638- 94639-type StructA struct { 94640- unexportedIntField int 94641- ExportedIntField int 94642- MapA map[int]string 94643- Array []int 94644- StructB 94645-} 94646- 94647-type StructA2 struct { 94648- B *StructB 94649-} 94650- 94651-type StructA3 struct { 94652- B StructB 94653-} 94654- 94655-func fill() { 94656- a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94657- b := StructA2{ 94658- B: &StructB{}, 94659- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94660- c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94661- if true { 94662- _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94663- } 94664-} 94665- 94666--- suggestedfix_fill_struct_22_16 -- 94667-package fillstruct 94668- 94669-type StructA struct { 94670- unexportedIntField int 94671- ExportedIntField int 94672- MapA map[int]string 94673- Array []int 94674- StructB 94675-} 94676- 94677-type StructA2 struct { 94678- B *StructB 94679-} 94680- 94681-type StructA3 struct { 94682- B StructB 94683-} 94684- 94685-func fill() { 94686- a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94687- b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94688- c := StructA3{ 94689- B: StructB{}, 94690- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94691- if true { 94692- _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94693- } 94694-} 94695- 94696--- suggestedfix_fill_struct_24_16 -- 94697-package fillstruct 94698- 94699-type StructA struct { 94700- unexportedIntField int 94701- ExportedIntField int 94702- MapA map[int]string 94703- Array []int 94704- StructB 94705-} 94706- 94707-type StructA2 struct { 94708- B *StructB 94709-} 94710- 94711-type StructA3 struct { 94712- B StructB 94713-} 94714- 94715-func fill() { 94716- a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94717- b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94718- c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94719- if true { 94720- _ = StructA3{ 94721- B: StructB{}, 94722- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94723- } 94724-} 94725- 94726diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go 94727--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go 2000-01-01 00:00:00.000000000 -0000 94728+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go 1970-01-01 00:00:00.000000000 +0000 94729@@ -1,15 +0,0 @@ 94730-package fillstruct 94731- 94732-type StructB struct { 94733- StructC 94734-} 94735- 94736-type StructC struct { 94737- unexportedInt int 94738-} 94739- 94740-func nested() { 94741- c := StructB{ 94742- StructC: StructC{}, //@suggestedfix("}", "refactor.rewrite", "Fill") 94743- } 94744-} 94745diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden 94746--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden 2000-01-01 00:00:00.000000000 -0000 94747+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden 1970-01-01 00:00:00.000000000 +0000 94748@@ -1,19 +0,0 @@ 94749--- suggestedfix_fill_struct_nested_13_20 -- 94750-package fillstruct 94751- 94752-type StructB struct { 94753- StructC 94754-} 94755- 94756-type StructC struct { 94757- unexportedInt int 94758-} 94759- 94760-func nested() { 94761- c := StructB{ 94762- StructC: StructC{ 94763- unexportedInt: 0, 94764- }, //@suggestedfix("}", "refactor.rewrite", "Fill") 94765- } 94766-} 94767- 94768diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go 94769--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go 2000-01-01 00:00:00.000000000 -0000 94770+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go 1970-01-01 00:00:00.000000000 +0000 94771@@ -1,12 +0,0 @@ 94772-package fillstruct 94773- 94774-import ( 94775- h2 "net/http" 94776- 94777- "golang.org/lsptests/fillstruct/data" 94778-) 94779- 94780-func unexported() { 94781- a := data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94782- _ = h2.Client{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94783-} 94784diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden 94785--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden 2000-01-01 00:00:00.000000000 -0000 94786+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden 1970-01-01 00:00:00.000000000 +0000 94787@@ -1,36 +0,0 @@ 94788--- suggestedfix_fill_struct_package_10_14 -- 94789-package fillstruct 94790- 94791-import ( 94792- h2 "net/http" 94793- 94794- "golang.org/lsptests/fillstruct/data" 94795-) 94796- 94797-func unexported() { 94798- a := data.B{ 94799- ExportedInt: 0, 94800- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94801- _ = h2.Client{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94802-} 94803- 94804--- suggestedfix_fill_struct_package_11_16 -- 94805-package fillstruct 94806- 94807-import ( 94808- h2 "net/http" 94809- 94810- "golang.org/lsptests/fillstruct/data" 94811-) 94812- 94813-func unexported() { 94814- a := data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94815- _ = h2.Client{ 94816- Transport: nil, 94817- CheckRedirect: func(req *h2.Request, via []*h2.Request) error { 94818- }, 94819- Jar: nil, 94820- Timeout: 0, 94821- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94822-} 94823- 94824diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go 94825--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go 2000-01-01 00:00:00.000000000 -0000 94826+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go 1970-01-01 00:00:00.000000000 +0000 94827@@ -1,24 +0,0 @@ 94828-package fillstruct 94829- 94830-type StructPartialA struct { 94831- PrefilledInt int 94832- UnfilledInt int 94833- StructPartialB 94834-} 94835- 94836-type StructPartialB struct { 94837- PrefilledInt int 94838- UnfilledInt int 94839-} 94840- 94841-func fill() { 94842- a := StructPartialA{ 94843- PrefilledInt: 5, 94844- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94845- b := StructPartialB{ 94846- /* this comment should disappear */ 94847- PrefilledInt: 7, // This comment should be blown away. 94848- /* As should 94849- this one */ 94850- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94851-} 94852diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden 94853--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden 2000-01-01 00:00:00.000000000 -0000 94854+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden 1970-01-01 00:00:00.000000000 +0000 94855@@ -1,52 +0,0 @@ 94856--- suggestedfix_fill_struct_partial_17_2 -- 94857-package fillstruct 94858- 94859-type StructPartialA struct { 94860- PrefilledInt int 94861- UnfilledInt int 94862- StructPartialB 94863-} 94864- 94865-type StructPartialB struct { 94866- PrefilledInt int 94867- UnfilledInt int 94868-} 94869- 94870-func fill() { 94871- a := StructPartialA{ 94872- PrefilledInt: 5, 94873- UnfilledInt: 0, 94874- StructPartialB: StructPartialB{}, 94875- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94876- b := StructPartialB{ 94877- /* this comment should disappear */ 94878- PrefilledInt: 7, // This comment should be blown away. 94879- /* As should 94880- this one */ 94881- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94882-} 94883- 94884--- suggestedfix_fill_struct_partial_23_2 -- 94885-package fillstruct 94886- 94887-type StructPartialA struct { 94888- PrefilledInt int 94889- UnfilledInt int 94890- StructPartialB 94891-} 94892- 94893-type StructPartialB struct { 94894- PrefilledInt int 94895- UnfilledInt int 94896-} 94897- 94898-func fill() { 94899- a := StructPartialA{ 94900- PrefilledInt: 5, 94901- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94902- b := StructPartialB{ 94903- PrefilledInt: 7, 94904- UnfilledInt: 0, 94905- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94906-} 94907- 94908diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go 94909--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go 2000-01-01 00:00:00.000000000 -0000 94910+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go 1970-01-01 00:00:00.000000000 +0000 94911@@ -1,9 +0,0 @@ 94912-package fillstruct 94913- 94914-type StructD struct { 94915- ExportedIntField int 94916-} 94917- 94918-func spaces() { 94919- d := StructD{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94920-} 94921diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden 94922--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden 2000-01-01 00:00:00.000000000 -0000 94923+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden 1970-01-01 00:00:00.000000000 +0000 94924@@ -1,13 +0,0 @@ 94925--- suggestedfix_fill_struct_spaces_8_15 -- 94926-package fillstruct 94927- 94928-type StructD struct { 94929- ExportedIntField int 94930-} 94931- 94932-func spaces() { 94933- d := StructD{ 94934- ExportedIntField: 0, 94935- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94936-} 94937- 94938diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go 94939--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go 2000-01-01 00:00:00.000000000 -0000 94940+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go 1970-01-01 00:00:00.000000000 +0000 94941@@ -1,12 +0,0 @@ 94942-package fillstruct 94943- 94944-import "unsafe" 94945- 94946-type unsafeStruct struct { 94947- x int 94948- p unsafe.Pointer 94949-} 94950- 94951-func fill() { 94952- _ := unsafeStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94953-} 94954diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden 94955--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden 2000-01-01 00:00:00.000000000 -0000 94956+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden 1970-01-01 00:00:00.000000000 +0000 94957@@ -1,17 +0,0 @@ 94958--- suggestedfix_fill_struct_unsafe_11_20 -- 94959-package fillstruct 94960- 94961-import "unsafe" 94962- 94963-type unsafeStruct struct { 94964- x int 94965- p unsafe.Pointer 94966-} 94967- 94968-func fill() { 94969- _ := unsafeStruct{ 94970- x: 0, 94971- p: nil, 94972- } //@suggestedfix("}", "refactor.rewrite", "Fill") 94973-} 94974- 94975diff -urN a/gopls/internal/lsp/testdata/fillstruct/typeparams.go b/gopls/internal/lsp/testdata/fillstruct/typeparams.go 94976--- a/gopls/internal/lsp/testdata/fillstruct/typeparams.go 2000-01-01 00:00:00.000000000 -0000 94977+++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go 1970-01-01 00:00:00.000000000 +0000 94978@@ -1,37 +0,0 @@ 94979-//go:build go1.18 94980-// +build go1.18 94981- 94982-package fillstruct 94983- 94984-type emptyStructWithTypeParams[A any] struct{} 94985- 94986-var _ = emptyStructWithTypeParams[int]{} // no suggested fix 94987- 94988-type basicStructWithTypeParams[T any] struct { 94989- foo T 94990-} 94991- 94992-var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 94993- 94994-type twoArgStructWithTypeParams[F, B any] struct { 94995- foo F 94996- bar B 94997-} 94998- 94999-var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95000- 95001-var _ = twoArgStructWithTypeParams[int, string]{ 95002- bar: "bar", 95003-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95004- 95005-type nestedStructWithTypeParams struct { 95006- bar string 95007- basic basicStructWithTypeParams[int] 95008-} 95009- 95010-var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95011- 95012-func _[T any]() { 95013- type S struct{ t T } 95014- _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95015-} 95016diff -urN a/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden 95017--- a/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden 2000-01-01 00:00:00.000000000 -0000 95018+++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden 1970-01-01 00:00:00.000000000 +0000 95019@@ -1,206 +0,0 @@ 95020--- suggestedfix_typeparams_14_40 -- 95021-//go:build go1.18 95022-// +build go1.18 95023- 95024-package fillstruct 95025- 95026-type emptyStructWithTypeParams[A any] struct{} 95027- 95028-var _ = emptyStructWithTypeParams[int]{} // no suggested fix 95029- 95030-type basicStructWithTypeParams[T any] struct { 95031- foo T 95032-} 95033- 95034-var _ = basicStructWithTypeParams[int]{ 95035- foo: 0, 95036-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95037- 95038-type twoArgStructWithTypeParams[F, B any] struct { 95039- foo F 95040- bar B 95041-} 95042- 95043-var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95044- 95045-var _ = twoArgStructWithTypeParams[int, string]{ 95046- bar: "bar", 95047-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95048- 95049-type nestedStructWithTypeParams struct { 95050- bar string 95051- basic basicStructWithTypeParams[int] 95052-} 95053- 95054-var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95055- 95056-func _[T any]() { 95057- type S struct{ t T } 95058- _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95059-} 95060- 95061--- suggestedfix_typeparams_21_49 -- 95062-//go:build go1.18 95063-// +build go1.18 95064- 95065-package fillstruct 95066- 95067-type emptyStructWithTypeParams[A any] struct{} 95068- 95069-var _ = emptyStructWithTypeParams[int]{} // no suggested fix 95070- 95071-type basicStructWithTypeParams[T any] struct { 95072- foo T 95073-} 95074- 95075-var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95076- 95077-type twoArgStructWithTypeParams[F, B any] struct { 95078- foo F 95079- bar B 95080-} 95081- 95082-var _ = twoArgStructWithTypeParams[string, int]{ 95083- foo: "", 95084- bar: 0, 95085-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95086- 95087-var _ = twoArgStructWithTypeParams[int, string]{ 95088- bar: "bar", 95089-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95090- 95091-type nestedStructWithTypeParams struct { 95092- bar string 95093- basic basicStructWithTypeParams[int] 95094-} 95095- 95096-var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95097- 95098-func _[T any]() { 95099- type S struct{ t T } 95100- _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95101-} 95102- 95103--- suggestedfix_typeparams_25_1 -- 95104-//go:build go1.18 95105-// +build go1.18 95106- 95107-package fillstruct 95108- 95109-type emptyStructWithTypeParams[A any] struct{} 95110- 95111-var _ = emptyStructWithTypeParams[int]{} // no suggested fix 95112- 95113-type basicStructWithTypeParams[T any] struct { 95114- foo T 95115-} 95116- 95117-var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95118- 95119-type twoArgStructWithTypeParams[F, B any] struct { 95120- foo F 95121- bar B 95122-} 95123- 95124-var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95125- 95126-var _ = twoArgStructWithTypeParams[int, string]{ 95127- foo: 0, 95128- bar: "bar", 95129-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95130- 95131-type nestedStructWithTypeParams struct { 95132- bar string 95133- basic basicStructWithTypeParams[int] 95134-} 95135- 95136-var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95137- 95138-func _[T any]() { 95139- type S struct{ t T } 95140- _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95141-} 95142- 95143--- suggestedfix_typeparams_32_36 -- 95144-//go:build go1.18 95145-// +build go1.18 95146- 95147-package fillstruct 95148- 95149-type emptyStructWithTypeParams[A any] struct{} 95150- 95151-var _ = emptyStructWithTypeParams[int]{} // no suggested fix 95152- 95153-type basicStructWithTypeParams[T any] struct { 95154- foo T 95155-} 95156- 95157-var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95158- 95159-type twoArgStructWithTypeParams[F, B any] struct { 95160- foo F 95161- bar B 95162-} 95163- 95164-var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95165- 95166-var _ = twoArgStructWithTypeParams[int, string]{ 95167- bar: "bar", 95168-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95169- 95170-type nestedStructWithTypeParams struct { 95171- bar string 95172- basic basicStructWithTypeParams[int] 95173-} 95174- 95175-var _ = nestedStructWithTypeParams{ 95176- bar: "", 95177- basic: basicStructWithTypeParams{}, 95178-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95179- 95180-func _[T any]() { 95181- type S struct{ t T } 95182- _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95183-} 95184- 95185--- suggestedfix_typeparams_36_8 -- 95186-//go:build go1.18 95187-// +build go1.18 95188- 95189-package fillstruct 95190- 95191-type emptyStructWithTypeParams[A any] struct{} 95192- 95193-var _ = emptyStructWithTypeParams[int]{} // no suggested fix 95194- 95195-type basicStructWithTypeParams[T any] struct { 95196- foo T 95197-} 95198- 95199-var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95200- 95201-type twoArgStructWithTypeParams[F, B any] struct { 95202- foo F 95203- bar B 95204-} 95205- 95206-var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95207- 95208-var _ = twoArgStructWithTypeParams[int, string]{ 95209- bar: "bar", 95210-} //@suggestedfix("}", "refactor.rewrite", "Fill") 95211- 95212-type nestedStructWithTypeParams struct { 95213- bar string 95214- basic basicStructWithTypeParams[int] 95215-} 95216- 95217-var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") 95218- 95219-func _[T any]() { 95220- type S struct{ t T } 95221- _ = S{ 95222- t: *new(T), 95223- } //@suggestedfix("}", "refactor.rewrite", "Fill") 95224-} 95225- 95226diff -urN a/gopls/internal/lsp/testdata/folding/a.go b/gopls/internal/lsp/testdata/folding/a.go 95227--- a/gopls/internal/lsp/testdata/folding/a.go 2000-01-01 00:00:00.000000000 -0000 95228+++ b/gopls/internal/lsp/testdata/folding/a.go 1970-01-01 00:00:00.000000000 +0000 95229@@ -1,75 +0,0 @@ 95230-package folding //@fold("package") 95231- 95232-import ( 95233- "fmt" 95234- _ "log" 95235-) 95236- 95237-import _ "os" 95238- 95239-// bar is a function. 95240-// With a multiline doc comment. 95241-func bar() string { 95242- /* This is a single line comment */ 95243- switch { 95244- case true: 95245- if true { 95246- fmt.Println("true") 95247- } else { 95248- fmt.Println("false") 95249- } 95250- case false: 95251- fmt.Println("false") 95252- default: 95253- fmt.Println("default") 95254- } 95255- /* This is a multiline 95256- block 95257- comment */ 95258- 95259- /* This is a multiline 95260- block 95261- comment */ 95262- // Followed by another comment. 95263- _ = []int{ 95264- 1, 95265- 2, 95266- 3, 95267- } 95268- _ = [2]string{"d", 95269- "e", 95270- } 95271- _ = map[string]int{ 95272- "a": 1, 95273- "b": 2, 95274- "c": 3, 95275- } 95276- type T struct { 95277- f string 95278- g int 95279- h string 95280- } 95281- _ = T{ 95282- f: "j", 95283- g: 4, 95284- h: "i", 95285- } 95286- x, y := make(chan bool), make(chan bool) 95287- select { 95288- case val := <-x: 95289- if val { 95290- fmt.Println("true from x") 95291- } else { 95292- fmt.Println("false from x") 95293- } 95294- case <-y: 95295- fmt.Println("y") 95296- default: 95297- fmt.Println("default") 95298- } 95299- // This is a multiline comment 95300- // that is not a doc comment. 95301- return ` 95302-this string 95303-is not indented` 95304-} 95305diff -urN a/gopls/internal/lsp/testdata/folding/a.go.golden b/gopls/internal/lsp/testdata/folding/a.go.golden 95306--- a/gopls/internal/lsp/testdata/folding/a.go.golden 2000-01-01 00:00:00.000000000 -0000 95307+++ b/gopls/internal/lsp/testdata/folding/a.go.golden 1970-01-01 00:00:00.000000000 +0000 95308@@ -1,722 +0,0 @@ 95309--- foldingRange-0 -- 95310-package folding //@fold("package") 95311- 95312-import (<>) 95313- 95314-import _ "os" 95315- 95316-// bar is a function.<> 95317-func bar(<>) string {<>} 95318- 95319--- foldingRange-1 -- 95320-package folding //@fold("package") 95321- 95322-import ( 95323- "fmt" 95324- _ "log" 95325-) 95326- 95327-import _ "os" 95328- 95329-// bar is a function. 95330-// With a multiline doc comment. 95331-func bar() string { 95332- /* This is a single line comment */ 95333- switch {<>} 95334- /* This is a multiline<> 95335- 95336- /* This is a multiline<> 95337- _ = []int{<>} 95338- _ = [2]string{<>} 95339- _ = map[string]int{<>} 95340- type T struct {<>} 95341- _ = T{<>} 95342- x, y := make(<>), make(<>) 95343- select {<>} 95344- // This is a multiline comment<> 95345- return <> 95346-} 95347- 95348--- foldingRange-2 -- 95349-package folding //@fold("package") 95350- 95351-import ( 95352- "fmt" 95353- _ "log" 95354-) 95355- 95356-import _ "os" 95357- 95358-// bar is a function. 95359-// With a multiline doc comment. 95360-func bar() string { 95361- /* This is a single line comment */ 95362- switch { 95363- case true:<> 95364- case false:<> 95365- default:<> 95366- } 95367- /* This is a multiline 95368- block 95369- comment */ 95370- 95371- /* This is a multiline 95372- block 95373- comment */ 95374- // Followed by another comment. 95375- _ = []int{ 95376- 1, 95377- 2, 95378- 3, 95379- } 95380- _ = [2]string{"d", 95381- "e", 95382- } 95383- _ = map[string]int{ 95384- "a": 1, 95385- "b": 2, 95386- "c": 3, 95387- } 95388- type T struct { 95389- f string 95390- g int 95391- h string 95392- } 95393- _ = T{ 95394- f: "j", 95395- g: 4, 95396- h: "i", 95397- } 95398- x, y := make(chan bool), make(chan bool) 95399- select { 95400- case val := <-x:<> 95401- case <-y:<> 95402- default:<> 95403- } 95404- // This is a multiline comment 95405- // that is not a doc comment. 95406- return ` 95407-this string 95408-is not indented` 95409-} 95410- 95411--- foldingRange-3 -- 95412-package folding //@fold("package") 95413- 95414-import ( 95415- "fmt" 95416- _ "log" 95417-) 95418- 95419-import _ "os" 95420- 95421-// bar is a function. 95422-// With a multiline doc comment. 95423-func bar() string { 95424- /* This is a single line comment */ 95425- switch { 95426- case true: 95427- if true {<>} else {<>} 95428- case false: 95429- fmt.Println(<>) 95430- default: 95431- fmt.Println(<>) 95432- } 95433- /* This is a multiline 95434- block 95435- comment */ 95436- 95437- /* This is a multiline 95438- block 95439- comment */ 95440- // Followed by another comment. 95441- _ = []int{ 95442- 1, 95443- 2, 95444- 3, 95445- } 95446- _ = [2]string{"d", 95447- "e", 95448- } 95449- _ = map[string]int{ 95450- "a": 1, 95451- "b": 2, 95452- "c": 3, 95453- } 95454- type T struct { 95455- f string 95456- g int 95457- h string 95458- } 95459- _ = T{ 95460- f: "j", 95461- g: 4, 95462- h: "i", 95463- } 95464- x, y := make(chan bool), make(chan bool) 95465- select { 95466- case val := <-x: 95467- if val {<>} else {<>} 95468- case <-y: 95469- fmt.Println(<>) 95470- default: 95471- fmt.Println(<>) 95472- } 95473- // This is a multiline comment 95474- // that is not a doc comment. 95475- return ` 95476-this string 95477-is not indented` 95478-} 95479- 95480--- foldingRange-4 -- 95481-package folding //@fold("package") 95482- 95483-import ( 95484- "fmt" 95485- _ "log" 95486-) 95487- 95488-import _ "os" 95489- 95490-// bar is a function. 95491-// With a multiline doc comment. 95492-func bar() string { 95493- /* This is a single line comment */ 95494- switch { 95495- case true: 95496- if true { 95497- fmt.Println(<>) 95498- } else { 95499- fmt.Println(<>) 95500- } 95501- case false: 95502- fmt.Println("false") 95503- default: 95504- fmt.Println("default") 95505- } 95506- /* This is a multiline 95507- block 95508- comment */ 95509- 95510- /* This is a multiline 95511- block 95512- comment */ 95513- // Followed by another comment. 95514- _ = []int{ 95515- 1, 95516- 2, 95517- 3, 95518- } 95519- _ = [2]string{"d", 95520- "e", 95521- } 95522- _ = map[string]int{ 95523- "a": 1, 95524- "b": 2, 95525- "c": 3, 95526- } 95527- type T struct { 95528- f string 95529- g int 95530- h string 95531- } 95532- _ = T{ 95533- f: "j", 95534- g: 4, 95535- h: "i", 95536- } 95537- x, y := make(chan bool), make(chan bool) 95538- select { 95539- case val := <-x: 95540- if val { 95541- fmt.Println(<>) 95542- } else { 95543- fmt.Println(<>) 95544- } 95545- case <-y: 95546- fmt.Println("y") 95547- default: 95548- fmt.Println("default") 95549- } 95550- // This is a multiline comment 95551- // that is not a doc comment. 95552- return ` 95553-this string 95554-is not indented` 95555-} 95556- 95557--- foldingRange-comment-0 -- 95558-package folding //@fold("package") 95559- 95560-import ( 95561- "fmt" 95562- _ "log" 95563-) 95564- 95565-import _ "os" 95566- 95567-// bar is a function.<> 95568-func bar() string { 95569- /* This is a single line comment */ 95570- switch { 95571- case true: 95572- if true { 95573- fmt.Println("true") 95574- } else { 95575- fmt.Println("false") 95576- } 95577- case false: 95578- fmt.Println("false") 95579- default: 95580- fmt.Println("default") 95581- } 95582- /* This is a multiline<> 95583- 95584- /* This is a multiline<> 95585- _ = []int{ 95586- 1, 95587- 2, 95588- 3, 95589- } 95590- _ = [2]string{"d", 95591- "e", 95592- } 95593- _ = map[string]int{ 95594- "a": 1, 95595- "b": 2, 95596- "c": 3, 95597- } 95598- type T struct { 95599- f string 95600- g int 95601- h string 95602- } 95603- _ = T{ 95604- f: "j", 95605- g: 4, 95606- h: "i", 95607- } 95608- x, y := make(chan bool), make(chan bool) 95609- select { 95610- case val := <-x: 95611- if val { 95612- fmt.Println("true from x") 95613- } else { 95614- fmt.Println("false from x") 95615- } 95616- case <-y: 95617- fmt.Println("y") 95618- default: 95619- fmt.Println("default") 95620- } 95621- // This is a multiline comment<> 95622- return ` 95623-this string 95624-is not indented` 95625-} 95626- 95627--- foldingRange-imports-0 -- 95628-package folding //@fold("package") 95629- 95630-import (<>) 95631- 95632-import _ "os" 95633- 95634-// bar is a function. 95635-// With a multiline doc comment. 95636-func bar() string { 95637- /* This is a single line comment */ 95638- switch { 95639- case true: 95640- if true { 95641- fmt.Println("true") 95642- } else { 95643- fmt.Println("false") 95644- } 95645- case false: 95646- fmt.Println("false") 95647- default: 95648- fmt.Println("default") 95649- } 95650- /* This is a multiline 95651- block 95652- comment */ 95653- 95654- /* This is a multiline 95655- block 95656- comment */ 95657- // Followed by another comment. 95658- _ = []int{ 95659- 1, 95660- 2, 95661- 3, 95662- } 95663- _ = [2]string{"d", 95664- "e", 95665- } 95666- _ = map[string]int{ 95667- "a": 1, 95668- "b": 2, 95669- "c": 3, 95670- } 95671- type T struct { 95672- f string 95673- g int 95674- h string 95675- } 95676- _ = T{ 95677- f: "j", 95678- g: 4, 95679- h: "i", 95680- } 95681- x, y := make(chan bool), make(chan bool) 95682- select { 95683- case val := <-x: 95684- if val { 95685- fmt.Println("true from x") 95686- } else { 95687- fmt.Println("false from x") 95688- } 95689- case <-y: 95690- fmt.Println("y") 95691- default: 95692- fmt.Println("default") 95693- } 95694- // This is a multiline comment 95695- // that is not a doc comment. 95696- return ` 95697-this string 95698-is not indented` 95699-} 95700- 95701--- foldingRange-lineFolding-0 -- 95702-package folding //@fold("package") 95703- 95704-import (<> 95705-) 95706- 95707-import _ "os" 95708- 95709-// bar is a function.<> 95710-func bar() string {<> 95711-} 95712- 95713--- foldingRange-lineFolding-1 -- 95714-package folding //@fold("package") 95715- 95716-import ( 95717- "fmt" 95718- _ "log" 95719-) 95720- 95721-import _ "os" 95722- 95723-// bar is a function. 95724-// With a multiline doc comment. 95725-func bar() string { 95726- /* This is a single line comment */ 95727- switch {<> 95728- } 95729- /* This is a multiline<> 95730- 95731- /* This is a multiline<> 95732- _ = []int{<>, 95733- } 95734- _ = [2]string{"d", 95735- "e", 95736- } 95737- _ = map[string]int{<>, 95738- } 95739- type T struct {<> 95740- } 95741- _ = T{<>, 95742- } 95743- x, y := make(chan bool), make(chan bool) 95744- select {<> 95745- } 95746- // This is a multiline comment<> 95747- return <> 95748-} 95749- 95750--- foldingRange-lineFolding-2 -- 95751-package folding //@fold("package") 95752- 95753-import ( 95754- "fmt" 95755- _ "log" 95756-) 95757- 95758-import _ "os" 95759- 95760-// bar is a function. 95761-// With a multiline doc comment. 95762-func bar() string { 95763- /* This is a single line comment */ 95764- switch { 95765- case true:<> 95766- case false:<> 95767- default:<> 95768- } 95769- /* This is a multiline 95770- block 95771- comment */ 95772- 95773- /* This is a multiline 95774- block 95775- comment */ 95776- // Followed by another comment. 95777- _ = []int{ 95778- 1, 95779- 2, 95780- 3, 95781- } 95782- _ = [2]string{"d", 95783- "e", 95784- } 95785- _ = map[string]int{ 95786- "a": 1, 95787- "b": 2, 95788- "c": 3, 95789- } 95790- type T struct { 95791- f string 95792- g int 95793- h string 95794- } 95795- _ = T{ 95796- f: "j", 95797- g: 4, 95798- h: "i", 95799- } 95800- x, y := make(chan bool), make(chan bool) 95801- select { 95802- case val := <-x:<> 95803- case <-y:<> 95804- default:<> 95805- } 95806- // This is a multiline comment 95807- // that is not a doc comment. 95808- return ` 95809-this string 95810-is not indented` 95811-} 95812- 95813--- foldingRange-lineFolding-3 -- 95814-package folding //@fold("package") 95815- 95816-import ( 95817- "fmt" 95818- _ "log" 95819-) 95820- 95821-import _ "os" 95822- 95823-// bar is a function. 95824-// With a multiline doc comment. 95825-func bar() string { 95826- /* This is a single line comment */ 95827- switch { 95828- case true: 95829- if true {<> 95830- } else {<> 95831- } 95832- case false: 95833- fmt.Println("false") 95834- default: 95835- fmt.Println("default") 95836- } 95837- /* This is a multiline 95838- block 95839- comment */ 95840- 95841- /* This is a multiline 95842- block 95843- comment */ 95844- // Followed by another comment. 95845- _ = []int{ 95846- 1, 95847- 2, 95848- 3, 95849- } 95850- _ = [2]string{"d", 95851- "e", 95852- } 95853- _ = map[string]int{ 95854- "a": 1, 95855- "b": 2, 95856- "c": 3, 95857- } 95858- type T struct { 95859- f string 95860- g int 95861- h string 95862- } 95863- _ = T{ 95864- f: "j", 95865- g: 4, 95866- h: "i", 95867- } 95868- x, y := make(chan bool), make(chan bool) 95869- select { 95870- case val := <-x: 95871- if val {<> 95872- } else {<> 95873- } 95874- case <-y: 95875- fmt.Println("y") 95876- default: 95877- fmt.Println("default") 95878- } 95879- // This is a multiline comment 95880- // that is not a doc comment. 95881- return ` 95882-this string 95883-is not indented` 95884-} 95885- 95886--- foldingRange-lineFolding-comment-0 -- 95887-package folding //@fold("package") 95888- 95889-import ( 95890- "fmt" 95891- _ "log" 95892-) 95893- 95894-import _ "os" 95895- 95896-// bar is a function.<> 95897-func bar() string { 95898- /* This is a single line comment */ 95899- switch { 95900- case true: 95901- if true { 95902- fmt.Println("true") 95903- } else { 95904- fmt.Println("false") 95905- } 95906- case false: 95907- fmt.Println("false") 95908- default: 95909- fmt.Println("default") 95910- } 95911- /* This is a multiline<> 95912- 95913- /* This is a multiline<> 95914- _ = []int{ 95915- 1, 95916- 2, 95917- 3, 95918- } 95919- _ = [2]string{"d", 95920- "e", 95921- } 95922- _ = map[string]int{ 95923- "a": 1, 95924- "b": 2, 95925- "c": 3, 95926- } 95927- type T struct { 95928- f string 95929- g int 95930- h string 95931- } 95932- _ = T{ 95933- f: "j", 95934- g: 4, 95935- h: "i", 95936- } 95937- x, y := make(chan bool), make(chan bool) 95938- select { 95939- case val := <-x: 95940- if val { 95941- fmt.Println("true from x") 95942- } else { 95943- fmt.Println("false from x") 95944- } 95945- case <-y: 95946- fmt.Println("y") 95947- default: 95948- fmt.Println("default") 95949- } 95950- // This is a multiline comment<> 95951- return ` 95952-this string 95953-is not indented` 95954-} 95955- 95956--- foldingRange-lineFolding-imports-0 -- 95957-package folding //@fold("package") 95958- 95959-import (<> 95960-) 95961- 95962-import _ "os" 95963- 95964-// bar is a function. 95965-// With a multiline doc comment. 95966-func bar() string { 95967- /* This is a single line comment */ 95968- switch { 95969- case true: 95970- if true { 95971- fmt.Println("true") 95972- } else { 95973- fmt.Println("false") 95974- } 95975- case false: 95976- fmt.Println("false") 95977- default: 95978- fmt.Println("default") 95979- } 95980- /* This is a multiline 95981- block 95982- comment */ 95983- 95984- /* This is a multiline 95985- block 95986- comment */ 95987- // Followed by another comment. 95988- _ = []int{ 95989- 1, 95990- 2, 95991- 3, 95992- } 95993- _ = [2]string{"d", 95994- "e", 95995- } 95996- _ = map[string]int{ 95997- "a": 1, 95998- "b": 2, 95999- "c": 3, 96000- } 96001- type T struct { 96002- f string 96003- g int 96004- h string 96005- } 96006- _ = T{ 96007- f: "j", 96008- g: 4, 96009- h: "i", 96010- } 96011- x, y := make(chan bool), make(chan bool) 96012- select { 96013- case val := <-x: 96014- if val { 96015- fmt.Println("true from x") 96016- } else { 96017- fmt.Println("false from x") 96018- } 96019- case <-y: 96020- fmt.Println("y") 96021- default: 96022- fmt.Println("default") 96023- } 96024- // This is a multiline comment 96025- // that is not a doc comment. 96026- return ` 96027-this string 96028-is not indented` 96029-} 96030- 96031diff -urN a/gopls/internal/lsp/testdata/folding/bad.go.golden b/gopls/internal/lsp/testdata/folding/bad.go.golden 96032--- a/gopls/internal/lsp/testdata/folding/bad.go.golden 2000-01-01 00:00:00.000000000 -0000 96033+++ b/gopls/internal/lsp/testdata/folding/bad.go.golden 1970-01-01 00:00:00.000000000 +0000 96034@@ -1,81 +0,0 @@ 96035--- foldingRange-0 -- 96036-package folding //@fold("package") 96037- 96038-import (<>) 96039- 96040-import (<>) 96041- 96042-// badBar is a function. 96043-func badBar(<>) string {<>} 96044- 96045--- foldingRange-1 -- 96046-package folding //@fold("package") 96047- 96048-import ( "fmt" 96049- _ "log" 96050-) 96051- 96052-import ( 96053- _ "os" ) 96054- 96055-// badBar is a function. 96056-func badBar() string { x := true 96057- if x {<>} else {<>} 96058- return 96059-} 96060- 96061--- foldingRange-2 -- 96062-package folding //@fold("package") 96063- 96064-import ( "fmt" 96065- _ "log" 96066-) 96067- 96068-import ( 96069- _ "os" ) 96070- 96071-// badBar is a function. 96072-func badBar() string { x := true 96073- if x { 96074- // This is the only foldable thing in this file when lineFoldingOnly 96075- fmt.Println(<>) 96076- } else { 96077- fmt.Println(<>) } 96078- return 96079-} 96080- 96081--- foldingRange-imports-0 -- 96082-package folding //@fold("package") 96083- 96084-import (<>) 96085- 96086-import (<>) 96087- 96088-// badBar is a function. 96089-func badBar() string { x := true 96090- if x { 96091- // This is the only foldable thing in this file when lineFoldingOnly 96092- fmt.Println("true") 96093- } else { 96094- fmt.Println("false") } 96095- return 96096-} 96097- 96098--- foldingRange-lineFolding-0 -- 96099-package folding //@fold("package") 96100- 96101-import ( "fmt" 96102- _ "log" 96103-) 96104- 96105-import ( 96106- _ "os" ) 96107- 96108-// badBar is a function. 96109-func badBar() string { x := true 96110- if x {<> 96111- } else { 96112- fmt.Println("false") } 96113- return 96114-} 96115- 96116diff -urN a/gopls/internal/lsp/testdata/folding/bad.go.in b/gopls/internal/lsp/testdata/folding/bad.go.in 96117--- a/gopls/internal/lsp/testdata/folding/bad.go.in 2000-01-01 00:00:00.000000000 -0000 96118+++ b/gopls/internal/lsp/testdata/folding/bad.go.in 1970-01-01 00:00:00.000000000 +0000 96119@@ -1,18 +0,0 @@ 96120-package folding //@fold("package") 96121- 96122-import ( "fmt" 96123- _ "log" 96124-) 96125- 96126-import ( 96127- _ "os" ) 96128- 96129-// badBar is a function. 96130-func badBar() string { x := true 96131- if x { 96132- // This is the only foldable thing in this file when lineFoldingOnly 96133- fmt.Println("true") 96134- } else { 96135- fmt.Println("false") } 96136- return 96137-} 96138diff -urN a/gopls/internal/lsp/testdata/foo/foo.go b/gopls/internal/lsp/testdata/foo/foo.go 96139--- a/gopls/internal/lsp/testdata/foo/foo.go 2000-01-01 00:00:00.000000000 -0000 96140+++ b/gopls/internal/lsp/testdata/foo/foo.go 1970-01-01 00:00:00.000000000 +0000 96141@@ -1,30 +0,0 @@ 96142-package foo //@mark(PackageFoo, "foo"),item(PackageFoo, "foo", "\"golang.org/lsptests/foo\"", "package") 96143- 96144-type StructFoo struct { //@item(StructFoo, "StructFoo", "struct{...}", "struct") 96145- Value int //@item(Value, "Value", "int", "field") 96146-} 96147- 96148-// Pre-set this marker, as we don't have a "source" for it in this package. 96149-/* Error() */ //@item(Error, "Error", "func() string", "method") 96150- 96151-func Foo() { //@item(Foo, "Foo", "func()", "func") 96152- var err error 96153- err.Error() //@complete("E", Error) 96154-} 96155- 96156-func _() { 96157- var sFoo StructFoo //@mark(sFoo1, "sFoo"),complete("t", StructFoo) 96158- if x := sFoo; x.Value == 1 { //@mark(sFoo2, "sFoo"),complete("V", Value),typdef("sFoo", StructFoo),refs("sFo", sFoo1, sFoo2) 96159- return 96160- } 96161-} 96162- 96163-func _() { 96164- shadowed := 123 96165- { 96166- shadowed := "hi" //@item(shadowed, "shadowed", "string", "var"),refs("shadowed", shadowed) 96167- sha //@complete("a", shadowed) 96168- } 96169-} 96170- 96171-type IntFoo int //@item(IntFoo, "IntFoo", "int", "type") 96172diff -urN a/gopls/internal/lsp/testdata/format/bad_format.go.golden b/gopls/internal/lsp/testdata/format/bad_format.go.golden 96173--- a/gopls/internal/lsp/testdata/format/bad_format.go.golden 2000-01-01 00:00:00.000000000 -0000 96174+++ b/gopls/internal/lsp/testdata/format/bad_format.go.golden 1970-01-01 00:00:00.000000000 +0000 96175@@ -1,21 +0,0 @@ 96176--- gofmt -- 96177-package format //@format("package") 96178- 96179-import ( 96180- "fmt" 96181- "log" 96182- "runtime" 96183-) 96184- 96185-func hello() { 96186- 96187- var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") 96188-} 96189- 96190-func hi() { 96191- runtime.GOROOT() 96192- fmt.Printf("") 96193- 96194- log.Printf("") 96195-} 96196- 96197diff -urN a/gopls/internal/lsp/testdata/format/bad_format.go.in b/gopls/internal/lsp/testdata/format/bad_format.go.in 96198--- a/gopls/internal/lsp/testdata/format/bad_format.go.in 2000-01-01 00:00:00.000000000 -0000 96199+++ b/gopls/internal/lsp/testdata/format/bad_format.go.in 1970-01-01 00:00:00.000000000 +0000 96200@@ -1,22 +0,0 @@ 96201-package format //@format("package") 96202- 96203-import ( 96204- "runtime" 96205- "fmt" 96206- "log" 96207-) 96208- 96209-func hello() { 96210- 96211- 96212- 96213- 96214- var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") 96215-} 96216- 96217-func hi() { 96218- runtime.GOROOT() 96219- fmt.Printf("") 96220- 96221- log.Printf("") 96222-} 96223diff -urN a/gopls/internal/lsp/testdata/format/good_format.go b/gopls/internal/lsp/testdata/format/good_format.go 96224--- a/gopls/internal/lsp/testdata/format/good_format.go 2000-01-01 00:00:00.000000000 -0000 96225+++ b/gopls/internal/lsp/testdata/format/good_format.go 1970-01-01 00:00:00.000000000 +0000 96226@@ -1,9 +0,0 @@ 96227-package format //@format("package") 96228- 96229-import ( 96230- "log" 96231-) 96232- 96233-func goodbye() { 96234- log.Printf("byeeeee") 96235-} 96236diff -urN a/gopls/internal/lsp/testdata/format/good_format.go.golden b/gopls/internal/lsp/testdata/format/good_format.go.golden 96237--- a/gopls/internal/lsp/testdata/format/good_format.go.golden 2000-01-01 00:00:00.000000000 -0000 96238+++ b/gopls/internal/lsp/testdata/format/good_format.go.golden 1970-01-01 00:00:00.000000000 +0000 96239@@ -1,11 +0,0 @@ 96240--- gofmt -- 96241-package format //@format("package") 96242- 96243-import ( 96244- "log" 96245-) 96246- 96247-func goodbye() { 96248- log.Printf("byeeeee") 96249-} 96250- 96251diff -urN a/gopls/internal/lsp/testdata/format/newline_format.go.golden b/gopls/internal/lsp/testdata/format/newline_format.go.golden 96252--- a/gopls/internal/lsp/testdata/format/newline_format.go.golden 2000-01-01 00:00:00.000000000 -0000 96253+++ b/gopls/internal/lsp/testdata/format/newline_format.go.golden 1970-01-01 00:00:00.000000000 +0000 96254@@ -1,4 +0,0 @@ 96255--- gofmt -- 96256-package format //@format("package") 96257-func _() {} 96258- 96259diff -urN a/gopls/internal/lsp/testdata/format/newline_format.go.in b/gopls/internal/lsp/testdata/format/newline_format.go.in 96260--- a/gopls/internal/lsp/testdata/format/newline_format.go.in 2000-01-01 00:00:00.000000000 -0000 96261+++ b/gopls/internal/lsp/testdata/format/newline_format.go.in 1970-01-01 00:00:00.000000000 +0000 96262@@ -1,2 +0,0 @@ 96263-package format //@format("package") 96264-func _() {} 96265\ No newline at end of file 96266diff -urN a/gopls/internal/lsp/testdata/format/one_line.go.golden b/gopls/internal/lsp/testdata/format/one_line.go.golden 96267--- a/gopls/internal/lsp/testdata/format/one_line.go.golden 2000-01-01 00:00:00.000000000 -0000 96268+++ b/gopls/internal/lsp/testdata/format/one_line.go.golden 1970-01-01 00:00:00.000000000 +0000 96269@@ -1,3 +0,0 @@ 96270--- gofmt -- 96271-package format //@format("package") 96272- 96273diff -urN a/gopls/internal/lsp/testdata/format/one_line.go.in b/gopls/internal/lsp/testdata/format/one_line.go.in 96274--- a/gopls/internal/lsp/testdata/format/one_line.go.in 2000-01-01 00:00:00.000000000 -0000 96275+++ b/gopls/internal/lsp/testdata/format/one_line.go.in 1970-01-01 00:00:00.000000000 +0000 96276@@ -1 +0,0 @@ 96277-package format //@format("package") 96278\ No newline at end of file 96279diff -urN a/gopls/internal/lsp/testdata/func_rank/func_rank.go.in b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in 96280--- a/gopls/internal/lsp/testdata/func_rank/func_rank.go.in 2000-01-01 00:00:00.000000000 -0000 96281+++ b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in 1970-01-01 00:00:00.000000000 +0000 96282@@ -1,70 +0,0 @@ 96283-package func_rank 96284- 96285-import "net/http" 96286- 96287-var stringAVar = "var" //@item(stringAVar, "stringAVar", "string", "var") 96288-func stringBFunc() string { return "str" } //@item(stringBFunc, "stringBFunc", "func() string", "func") 96289-type stringer struct{} //@item(stringer, "stringer", "struct{...}", "struct") 96290- 96291-func _() stringer //@complete("tr", stringer) 96292- 96293-func _(val stringer) {} //@complete("tr", stringer) 96294- 96295-func (stringer) _() {} //@complete("tr", stringer) 96296- 96297-func _() { 96298- var s struct { 96299- AA int //@item(rankAA, "AA", "int", "field") 96300- AB string //@item(rankAB, "AB", "string", "field") 96301- AC int //@item(rankAC, "AC", "int", "field") 96302- } 96303- fnStr := func(string) {} 96304- fnStr(s.A) //@complete(")", rankAB, rankAA, rankAC) 96305- fnStr("" + s.A) //@complete(")", rankAB, rankAA, rankAC) 96306- 96307- fnInt := func(int) {} 96308- fnInt(-s.A) //@complete(")", rankAA, rankAC, rankAB) 96309- 96310- // no expected type 96311- fnInt(func() int { s.A }) //@complete(" }", rankAA, rankAB, rankAC) 96312- fnInt(s.A()) //@complete("()", rankAA, rankAC, rankAB) 96313- fnInt([]int{}[s.A]) //@complete("])", rankAA, rankAC, rankAB) 96314- fnInt([]int{}[:s.A]) //@complete("])", rankAA, rankAC, rankAB) 96315- 96316- fnInt(s.A.(int)) //@complete(".(", rankAA, rankAC, rankAB) 96317- 96318- fnPtr := func(*string) {} 96319- fnPtr(&s.A) //@complete(")", rankAB, rankAA, rankAC) 96320- 96321- var aaPtr *string //@item(rankAAPtr, "aaPtr", "*string", "var") 96322- var abPtr *int //@item(rankABPtr, "abPtr", "*int", "var") 96323- fnInt(*a) //@complete(")", rankABPtr, rankAAPtr) 96324- 96325- _ = func() string { 96326- return s.A //@complete(" //", rankAB, rankAA, rankAC) 96327- } 96328-} 96329- 96330-type foo struct { 96331- fooPrivateField int //@item(rankFooPrivField, "fooPrivateField", "int", "field") 96332- FooPublicField int //@item(rankFooPubField, "FooPublicField", "int", "field") 96333-} 96334- 96335-func (foo) fooPrivateMethod() int { //@item(rankFooPrivMeth, "fooPrivateMethod", "func() int", "method") 96336- return 0 96337-} 96338- 96339-func (foo) FooPublicMethod() int { //@item(rankFooPubMeth, "FooPublicMethod", "func() int", "method") 96340- return 0 96341-} 96342- 96343-func _() { 96344- var _ int = foo{}. //@rank(" //", rankFooPrivField, rankFooPubField),rank(" //", rankFooPrivMeth, rankFooPubMeth),rank(" //", rankFooPrivField, rankFooPrivMeth) 96345-} 96346- 96347-func _() { 96348- HandleFunc //@item(httpHandleFunc, "HandleFunc", "func(pattern string, handler func(http.ResponseWriter, *http.Request))", "func") 96349- HandlerFunc //@item(httpHandlerFunc, "HandlerFunc", "func(http.ResponseWriter, *http.Request)", "type") 96350- 96351- http.HandleFunc //@rank(" //", httpHandleFunc, httpHandlerFunc) 96352-} 96353diff -urN a/gopls/internal/lsp/testdata/funcsig/func_sig.go b/gopls/internal/lsp/testdata/funcsig/func_sig.go 96354--- a/gopls/internal/lsp/testdata/funcsig/func_sig.go 2000-01-01 00:00:00.000000000 -0000 96355+++ b/gopls/internal/lsp/testdata/funcsig/func_sig.go 1970-01-01 00:00:00.000000000 +0000 96356@@ -1,9 +0,0 @@ 96357-package funcsig 96358- 96359-type someType int //@item(sigSomeType, "someType", "int", "type") 96360- 96361-// Don't complete "foo" in signature. 96362-func (foo someType) _() { //@item(sigFoo, "foo", "someType", "var"),complete(") {", sigSomeType) 96363- 96364- //@complete("", sigFoo, sigSomeType) 96365-} 96366diff -urN a/gopls/internal/lsp/testdata/funcvalue/func_value.go b/gopls/internal/lsp/testdata/funcvalue/func_value.go 96367--- a/gopls/internal/lsp/testdata/funcvalue/func_value.go 2000-01-01 00:00:00.000000000 -0000 96368+++ b/gopls/internal/lsp/testdata/funcvalue/func_value.go 1970-01-01 00:00:00.000000000 +0000 96369@@ -1,27 +0,0 @@ 96370-package funcvalue 96371- 96372-func fooFunc() int { //@item(fvFooFunc, "fooFunc", "func() int", "func") 96373- return 0 96374-} 96375- 96376-var _ = fooFunc() //@item(fvFooFuncCall, "fooFunc", "func() int", "func") 96377- 96378-var fooVar = func() int { //@item(fvFooVar, "fooVar", "func() int", "var") 96379- return 0 96380-} 96381- 96382-var _ = fooVar() //@item(fvFooVarCall, "fooVar", "func() int", "var") 96383- 96384-type myFunc func() int 96385- 96386-var fooType myFunc = fooVar //@item(fvFooType, "fooType", "myFunc", "var") 96387- 96388-var _ = fooType() //@item(fvFooTypeCall, "fooType", "func() int", "var") 96389- 96390-func _() { 96391- var f func() int 96392- f = foo //@complete(" //", fvFooFunc, fvFooType, fvFooVar) 96393- 96394- var i int 96395- i = foo //@complete(" //", fvFooFuncCall, fvFooTypeCall, fvFooVarCall) 96396-} 96397diff -urN a/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go 96398--- a/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go 2000-01-01 00:00:00.000000000 -0000 96399+++ b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go 1970-01-01 00:00:00.000000000 +0000 96400@@ -1,48 +0,0 @@ 96401-// Copyright 2019 The Go Authors. All rights reserved. 96402-// Use of this source code is governed by a BSD-style 96403-// license that can be found in the LICENSE file. 96404- 96405-package fuzzy 96406- 96407-func _() { 96408- var a struct { 96409- fabar int 96410- fooBar string 96411- } 96412- 96413- a.fabar //@item(fuzzFabarField, "a.fabar", "int", "field") 96414- a.fooBar //@item(fuzzFooBarField, "a.fooBar", "string", "field") 96415- 96416- afa //@fuzzy(" //", fuzzFabarField, fuzzFooBarField) 96417- afb //@fuzzy(" //", fuzzFooBarField, fuzzFabarField) 96418- 96419- fab //@fuzzy(" //", fuzzFabarField) 96420- 96421- var myString string 96422- myString = af //@fuzzy(" //", fuzzFooBarField, fuzzFabarField) 96423- 96424- var b struct { 96425- c struct { 96426- d struct { 96427- e struct { 96428- abc string 96429- } 96430- abc float32 96431- } 96432- abc bool 96433- } 96434- abc int 96435- } 96436- 96437- b.abc //@item(fuzzABCInt, "b.abc", "int", "field") 96438- b.c.abc //@item(fuzzABCbool, "b.c.abc", "bool", "field") 96439- b.c.d.abc //@item(fuzzABCfloat, "b.c.d.abc", "float32", "field") 96440- b.c.d.e.abc //@item(fuzzABCstring, "b.c.d.e.abc", "string", "field") 96441- 96442- // in depth order by default 96443- abc //@fuzzy(" //", fuzzABCInt, fuzzABCbool, fuzzABCfloat) 96444- 96445- // deep candidate that matches expected type should still ranked first 96446- var s string 96447- s = abc //@fuzzy(" //", fuzzABCstring, fuzzABCInt, fuzzABCbool) 96448-} 96449diff -urN a/gopls/internal/lsp/testdata/generate/generate.go b/gopls/internal/lsp/testdata/generate/generate.go 96450--- a/gopls/internal/lsp/testdata/generate/generate.go 2000-01-01 00:00:00.000000000 -0000 96451+++ b/gopls/internal/lsp/testdata/generate/generate.go 1970-01-01 00:00:00.000000000 +0000 96452@@ -1,4 +0,0 @@ 96453-package generate 96454- 96455-//go:generate echo Hi //@ codelens("//go:generate", "run go generate", "generate"), codelens("//go:generate", "run go generate ./...", "generate") 96456-//go:generate echo I shall have no CodeLens 96457diff -urN a/gopls/internal/lsp/testdata/generated/generated.go b/gopls/internal/lsp/testdata/generated/generated.go 96458--- a/gopls/internal/lsp/testdata/generated/generated.go 2000-01-01 00:00:00.000000000 -0000 96459+++ b/gopls/internal/lsp/testdata/generated/generated.go 1970-01-01 00:00:00.000000000 +0000 96460@@ -1,7 +0,0 @@ 96461-package generated 96462- 96463-// Code generated by generator.go. DO NOT EDIT. 96464- 96465-func _() { 96466- var y int //@diag("y", "compiler", "y declared (and|but) not used", "error") 96467-} 96468diff -urN a/gopls/internal/lsp/testdata/generated/generator.go b/gopls/internal/lsp/testdata/generated/generator.go 96469--- a/gopls/internal/lsp/testdata/generated/generator.go 2000-01-01 00:00:00.000000000 -0000 96470+++ b/gopls/internal/lsp/testdata/generated/generator.go 1970-01-01 00:00:00.000000000 +0000 96471@@ -1,5 +0,0 @@ 96472-package generated 96473- 96474-func _() { 96475- var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") 96476-} 96477diff -urN a/gopls/internal/lsp/testdata/godef/a/a_x_test.go b/gopls/internal/lsp/testdata/godef/a/a_x_test.go 96478--- a/gopls/internal/lsp/testdata/godef/a/a_x_test.go 2000-01-01 00:00:00.000000000 -0000 96479+++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go 1970-01-01 00:00:00.000000000 +0000 96480@@ -1,9 +0,0 @@ 96481-package a_test 96482- 96483-import ( 96484- "testing" 96485-) 96486- 96487-func TestA2(t *testing.T) { //@TestA2,godef(TestA2, TestA2) 96488- Nonexistant() //@diag("Nonexistant", "compiler", "(undeclared name|undefined): Nonexistant", "error") 96489-} 96490diff -urN a/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden 96491--- a/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden 2000-01-01 00:00:00.000000000 -0000 96492+++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden 1970-01-01 00:00:00.000000000 +0000 96493@@ -1,26 +0,0 @@ 96494--- TestA2-definition -- 96495-godef/a/a_x_test.go:7:6-12: defined here as ```go 96496-func TestA2(t *testing.T) 96497-``` 96498--- TestA2-definition-json -- 96499-{ 96500- "span": { 96501- "uri": "file://godef/a/a_x_test.go", 96502- "start": { 96503- "line": 7, 96504- "column": 6, 96505- "offset": 44 96506- }, 96507- "end": { 96508- "line": 7, 96509- "column": 12, 96510- "offset": 50 96511- } 96512- }, 96513- "description": "```go\nfunc TestA2(t *testing.T)\n```" 96514-} 96515- 96516--- TestA2-hoverdef -- 96517-```go 96518-func TestA2(t *testing.T) 96519-``` 96520diff -urN a/gopls/internal/lsp/testdata/godef/a/d.go b/gopls/internal/lsp/testdata/godef/a/d.go 96521--- a/gopls/internal/lsp/testdata/godef/a/d.go 2000-01-01 00:00:00.000000000 -0000 96522+++ b/gopls/internal/lsp/testdata/godef/a/d.go 1970-01-01 00:00:00.000000000 +0000 96523@@ -1,69 +0,0 @@ 96524-package a //@mark(a, "a "),hoverdef("a ", a) 96525- 96526-import "fmt" 96527- 96528-type Thing struct { //@Thing 96529- Member string //@Member 96530-} 96531- 96532-var Other Thing //@Other 96533- 96534-func Things(val []string) []Thing { //@Things 96535- return nil 96536-} 96537- 96538-func (t Thing) Method(i int) string { //@Method 96539- return t.Member 96540-} 96541- 96542-func (t Thing) Method3() { 96543-} 96544- 96545-func (t *Thing) Method2(i int, j int) (error, string) { 96546- return nil, t.Member 96547-} 96548- 96549-func (t *Thing) private() { 96550-} 96551- 96552-func useThings() { 96553- t := Thing{ //@mark(aStructType, "ing") 96554- Member: "string", //@mark(fMember, "ember") 96555- } 96556- fmt.Print(t.Member) //@mark(aMember, "ember") 96557- fmt.Print(Other) //@mark(aVar, "ther") 96558- Things() //@mark(aFunc, "ings") 96559- t.Method() //@mark(aMethod, "eth") 96560-} 96561- 96562-type NextThing struct { //@NextThing 96563- Thing 96564- Value int 96565-} 96566- 96567-func (n NextThing) another() string { 96568- return n.Member 96569-} 96570- 96571-// Shadows Thing.Method3 96572-func (n *NextThing) Method3() int { 96573- return n.Value 96574-} 96575- 96576-var nextThing NextThing //@hoverdef("NextThing", NextThing) 96577- 96578-/*@ 96579-godef(aStructType, Thing) 96580-godef(aMember, Member) 96581-godef(aVar, Other) 96582-godef(aFunc, Things) 96583-godef(aMethod, Method) 96584-godef(fMember, Member) 96585-godef(Member, Member) 96586- 96587-//param 96588-//package name 96589-//const 96590-//anon field 96591- 96592-*/ 96593diff -urN a/gopls/internal/lsp/testdata/godef/a/d.go.golden b/gopls/internal/lsp/testdata/godef/a/d.go.golden 96594--- a/gopls/internal/lsp/testdata/godef/a/d.go.golden 2000-01-01 00:00:00.000000000 -0000 96595+++ b/gopls/internal/lsp/testdata/godef/a/d.go.golden 1970-01-01 00:00:00.000000000 +0000 96596@@ -1,191 +0,0 @@ 96597--- Member-definition -- 96598-godef/a/d.go:6:2-8: defined here as ```go 96599-field Member string 96600-``` 96601- 96602-@Member 96603- 96604- 96605-[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) 96606--- Member-definition-json -- 96607-{ 96608- "span": { 96609- "uri": "file://godef/a/d.go", 96610- "start": { 96611- "line": 6, 96612- "column": 2, 96613- "offset": 90 96614- }, 96615- "end": { 96616- "line": 6, 96617- "column": 8, 96618- "offset": 96 96619- } 96620- }, 96621- "description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)" 96622-} 96623- 96624--- Member-hoverdef -- 96625-```go 96626-field Member string 96627-``` 96628- 96629-@Member 96630- 96631- 96632-[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) 96633--- Method-definition -- 96634-godef/a/d.go:15:16-22: defined here as ```go 96635-func (Thing).Method(i int) string 96636-``` 96637- 96638-[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method) 96639--- Method-definition-json -- 96640-{ 96641- "span": { 96642- "uri": "file://godef/a/d.go", 96643- "start": { 96644- "line": 15, 96645- "column": 16, 96646- "offset": 219 96647- }, 96648- "end": { 96649- "line": 15, 96650- "column": 22, 96651- "offset": 225 96652- } 96653- }, 96654- "description": "```go\nfunc (Thing).Method(i int) string\n```\n\n[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)" 96655-} 96656- 96657--- Method-hoverdef -- 96658-```go 96659-func (Thing).Method(i int) string 96660-``` 96661- 96662-[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method) 96663--- NextThing-hoverdef -- 96664-```go 96665-type NextThing struct { 96666- Thing 96667- Value int 96668-} 96669- 96670-func (*NextThing).Method3() int 96671-func (NextThing).another() string 96672-``` 96673- 96674-[`a.NextThing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#NextThing) 96675--- Other-definition -- 96676-godef/a/d.go:9:5-10: defined here as ```go 96677-var Other Thing 96678-``` 96679- 96680-@Other 96681- 96682- 96683-[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) 96684--- Other-definition-json -- 96685-{ 96686- "span": { 96687- "uri": "file://godef/a/d.go", 96688- "start": { 96689- "line": 9, 96690- "column": 5, 96691- "offset": 121 96692- }, 96693- "end": { 96694- "line": 9, 96695- "column": 10, 96696- "offset": 126 96697- } 96698- }, 96699- "description": "```go\nvar Other Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)" 96700-} 96701- 96702--- Other-hoverdef -- 96703-```go 96704-var Other Thing 96705-``` 96706- 96707-@Other 96708- 96709- 96710-[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) 96711--- Thing-definition -- 96712-godef/a/d.go:5:6-11: defined here as ```go 96713-type Thing struct { 96714- Member string //@Member 96715-} 96716- 96717-func (Thing).Method(i int) string 96718-func (*Thing).Method2(i int, j int) (error, string) 96719-func (Thing).Method3() 96720-func (*Thing).private() 96721-``` 96722- 96723-[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) 96724--- Thing-definition-json -- 96725-{ 96726- "span": { 96727- "uri": "file://godef/a/d.go", 96728- "start": { 96729- "line": 5, 96730- "column": 6, 96731- "offset": 65 96732- }, 96733- "end": { 96734- "line": 5, 96735- "column": 11, 96736- "offset": 70 96737- } 96738- }, 96739- "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (Thing).Method(i int) string\nfunc (*Thing).Method2(i int, j int) (error, string)\nfunc (Thing).Method3()\nfunc (*Thing).private()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)" 96740-} 96741- 96742--- Thing-hoverdef -- 96743-```go 96744-type Thing struct { 96745- Member string //@Member 96746-} 96747- 96748-func (Thing).Method(i int) string 96749-func (*Thing).Method2(i int, j int) (error, string) 96750-func (Thing).Method3() 96751-func (*Thing).private() 96752-``` 96753- 96754-[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) 96755--- Things-definition -- 96756-godef/a/d.go:11:6-12: defined here as ```go 96757-func Things(val []string) []Thing 96758-``` 96759- 96760-[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) 96761--- Things-definition-json -- 96762-{ 96763- "span": { 96764- "uri": "file://godef/a/d.go", 96765- "start": { 96766- "line": 11, 96767- "column": 6, 96768- "offset": 148 96769- }, 96770- "end": { 96771- "line": 11, 96772- "column": 12, 96773- "offset": 154 96774- } 96775- }, 96776- "description": "```go\nfunc Things(val []string) []Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)" 96777-} 96778- 96779--- Things-hoverdef -- 96780-```go 96781-func Things(val []string) []Thing 96782-``` 96783- 96784-[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) 96785--- a-hoverdef -- 96786-Package a is a package for testing go to definition. 96787- 96788diff -urN a/gopls/internal/lsp/testdata/godef/a/f.go b/gopls/internal/lsp/testdata/godef/a/f.go 96789--- a/gopls/internal/lsp/testdata/godef/a/f.go 2000-01-01 00:00:00.000000000 -0000 96790+++ b/gopls/internal/lsp/testdata/godef/a/f.go 1970-01-01 00:00:00.000000000 +0000 96791@@ -1,16 +0,0 @@ 96792-// Package a is a package for testing go to definition. 96793-package a 96794- 96795-import "fmt" 96796- 96797-func TypeStuff() { //@Stuff 96798- var x string 96799- 96800- switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY) 96801- case int: //@mark(intY, "int") 96802- fmt.Printf("%v", y) //@hoverdef("y", intY) 96803- case string: //@mark(stringY, "string") 96804- fmt.Printf("%v", y) //@hoverdef("y", stringY) 96805- } 96806- 96807-} 96808diff -urN a/gopls/internal/lsp/testdata/godef/a/f.go.golden b/gopls/internal/lsp/testdata/godef/a/f.go.golden 96809--- a/gopls/internal/lsp/testdata/godef/a/f.go.golden 2000-01-01 00:00:00.000000000 -0000 96810+++ b/gopls/internal/lsp/testdata/godef/a/f.go.golden 1970-01-01 00:00:00.000000000 +0000 96811@@ -1,34 +0,0 @@ 96812--- intY-hoverdef -- 96813-```go 96814-var y int 96815-``` 96816--- stringY-hoverdef -- 96817-```go 96818-var y string 96819-``` 96820--- switchY-definition -- 96821-godef/a/f.go:8:9-10: defined here as ```go 96822-var y interface{} 96823-``` 96824--- switchY-definition-json -- 96825-{ 96826- "span": { 96827- "uri": "file://godef/a/f.go", 96828- "start": { 96829- "line": 8, 96830- "column": 9, 96831- "offset": 76 96832- }, 96833- "end": { 96834- "line": 8, 96835- "column": 10, 96836- "offset": 77 96837- } 96838- }, 96839- "description": "```go\nvar y interface{}\n```" 96840-} 96841- 96842--- switchY-hoverdef -- 96843-```go 96844-var y interface{} 96845-``` 96846diff -urN a/gopls/internal/lsp/testdata/godef/a/g.go b/gopls/internal/lsp/testdata/godef/a/g.go 96847--- a/gopls/internal/lsp/testdata/godef/a/g.go 2000-01-01 00:00:00.000000000 -0000 96848+++ b/gopls/internal/lsp/testdata/godef/a/g.go 1970-01-01 00:00:00.000000000 +0000 96849@@ -1,6 +0,0 @@ 96850-package a 96851- 96852-import "time" 96853- 96854-// dur is a constant of type time.Duration. 96855-const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hoverdef("dur", dur) 96856diff -urN a/gopls/internal/lsp/testdata/godef/a/g.go.golden b/gopls/internal/lsp/testdata/godef/a/g.go.golden 96857--- a/gopls/internal/lsp/testdata/godef/a/g.go.golden 2000-01-01 00:00:00.000000000 -0000 96858+++ b/gopls/internal/lsp/testdata/godef/a/g.go.golden 1970-01-01 00:00:00.000000000 +0000 96859@@ -1,7 +0,0 @@ 96860--- dur-hoverdef -- 96861-```go 96862-const dur time.Duration = 910350000000 // 15m10.35s 96863-``` 96864- 96865-dur is a constant of type time.Duration. 96866- 96867diff -urN a/gopls/internal/lsp/testdata/godef/a/h.go b/gopls/internal/lsp/testdata/godef/a/h.go 96868--- a/gopls/internal/lsp/testdata/godef/a/h.go 2000-01-01 00:00:00.000000000 -0000 96869+++ b/gopls/internal/lsp/testdata/godef/a/h.go 1970-01-01 00:00:00.000000000 +0000 96870@@ -1,147 +0,0 @@ 96871-package a 96872- 96873-func _() { 96874- type s struct { 96875- nested struct { 96876- // nested number 96877- number int64 //@mark(nestedNumber, "number") 96878- } 96879- nested2 []struct { 96880- // nested string 96881- str string //@mark(nestedString, "str") 96882- } 96883- x struct { 96884- x struct { 96885- x struct { 96886- x struct { 96887- x struct { 96888- // nested map 96889- m map[string]float64 //@mark(nestedMap, "m") 96890- } 96891- } 96892- } 96893- } 96894- } 96895- } 96896- 96897- var t s 96898- _ = t.nested.number //@hoverdef("number", nestedNumber) 96899- _ = t.nested2[0].str //@hoverdef("str", nestedString) 96900- _ = t.x.x.x.x.x.m //@hoverdef("m", nestedMap) 96901-} 96902- 96903-func _() { 96904- var s struct { 96905- // a field 96906- a int //@mark(structA, "a") 96907- // b nested struct 96908- b struct { //@mark(structB, "b") 96909- // c field of nested struct 96910- c int //@mark(structC, "c") 96911- } 96912- } 96913- _ = s.a //@hoverdef("a", structA) 96914- _ = s.b //@hoverdef("b", structB) 96915- _ = s.b.c //@hoverdef("c", structC) 96916- 96917- var arr []struct { 96918- // d field 96919- d int //@mark(arrD, "d") 96920- // e nested struct 96921- e struct { //@mark(arrE, "e") 96922- // f field of nested struct 96923- f int //@mark(arrF, "f") 96924- } 96925- } 96926- _ = arr[0].d //@hoverdef("d", arrD) 96927- _ = arr[0].e //@hoverdef("e", arrE) 96928- _ = arr[0].e.f //@hoverdef("f", arrF) 96929- 96930- var complex []struct { 96931- c <-chan map[string][]struct { 96932- // h field 96933- h int //@mark(complexH, "h") 96934- // i nested struct 96935- i struct { //@mark(complexI, "i") 96936- // j field of nested struct 96937- j int //@mark(complexJ, "j") 96938- } 96939- } 96940- } 96941- _ = (<-complex[0].c)["0"][0].h //@hoverdef("h", complexH) 96942- _ = (<-complex[0].c)["0"][0].i //@hoverdef("i", complexI) 96943- _ = (<-complex[0].c)["0"][0].i.j //@hoverdef("j", complexJ) 96944- 96945- var mapWithStructKey map[struct { 96946- // X key field 96947- x []string //@mark(mapStructKeyX, "x") 96948- }]int 96949- for k := range mapWithStructKey { 96950- _ = k.x //@hoverdef("x", mapStructKeyX) 96951- } 96952- 96953- var mapWithStructKeyAndValue map[struct { 96954- // Y key field 96955- y string //@mark(mapStructKeyY, "y") 96956- }]struct { 96957- // X value field 96958- x string //@mark(mapStructValueX, "x") 96959- } 96960- for k, v := range mapWithStructKeyAndValue { 96961- // TODO: we don't show docs for y field because both map key and value 96962- // are structs. And in this case, we parse only map value 96963- _ = k.y //@hoverdef("y", mapStructKeyY) 96964- _ = v.x //@hoverdef("x", mapStructValueX) 96965- } 96966- 96967- var i []map[string]interface { 96968- // open method comment 96969- open() error //@mark(openMethod, "open") 96970- } 96971- i[0]["1"].open() //@hoverdef("open", openMethod) 96972-} 96973- 96974-func _() { 96975- test := struct { 96976- // test description 96977- desc string //@mark(testDescription, "desc") 96978- }{} 96979- _ = test.desc //@hoverdef("desc", testDescription) 96980- 96981- for _, tt := range []struct { 96982- // test input 96983- in map[string][]struct { //@mark(testInput, "in") 96984- // test key 96985- key string //@mark(testInputKey, "key") 96986- // test value 96987- value interface{} //@mark(testInputValue, "value") 96988- } 96989- result struct { 96990- v <-chan struct { 96991- // expected test value 96992- value int //@mark(testResultValue, "value") 96993- } 96994- } 96995- }{} { 96996- _ = tt.in //@hoverdef("in", testInput) 96997- _ = tt.in["0"][0].key //@hoverdef("key", testInputKey) 96998- _ = tt.in["0"][0].value //@hoverdef("value", testInputValue) 96999- 97000- _ = (<-tt.result.v).value //@hoverdef("value", testResultValue) 97001- } 97002-} 97003- 97004-func _() { 97005- getPoints := func() []struct { 97006- // X coord 97007- x int //@mark(returnX, "x") 97008- // Y coord 97009- y int //@mark(returnY, "y") 97010- } { 97011- return nil 97012- } 97013- 97014- r := getPoints() 97015- r[0].x //@hoverdef("x", returnX) 97016- r[0].y //@hoverdef("y", returnY) 97017-} 97018diff -urN a/gopls/internal/lsp/testdata/godef/a/h.go.golden b/gopls/internal/lsp/testdata/godef/a/h.go.golden 97019--- a/gopls/internal/lsp/testdata/godef/a/h.go.golden 2000-01-01 00:00:00.000000000 -0000 97020+++ b/gopls/internal/lsp/testdata/godef/a/h.go.golden 1970-01-01 00:00:00.000000000 +0000 97021@@ -1,161 +0,0 @@ 97022--- arrD-hoverdef -- 97023-```go 97024-field d int 97025-``` 97026- 97027-d field 97028- 97029--- arrE-hoverdef -- 97030-```go 97031-field e struct{f int} 97032-``` 97033- 97034-e nested struct 97035- 97036--- arrF-hoverdef -- 97037-```go 97038-field f int 97039-``` 97040- 97041-f field of nested struct 97042- 97043--- complexH-hoverdef -- 97044-```go 97045-field h int 97046-``` 97047- 97048-h field 97049- 97050--- complexI-hoverdef -- 97051-```go 97052-field i struct{j int} 97053-``` 97054- 97055-i nested struct 97056- 97057--- complexJ-hoverdef -- 97058-```go 97059-field j int 97060-``` 97061- 97062-j field of nested struct 97063- 97064--- mapStructKeyX-hoverdef -- 97065-```go 97066-field x []string 97067-``` 97068- 97069-X key field 97070- 97071--- mapStructKeyY-hoverdef -- 97072-```go 97073-field y string 97074-``` 97075- 97076-Y key field 97077- 97078--- mapStructValueX-hoverdef -- 97079-```go 97080-field x string 97081-``` 97082- 97083-X value field 97084- 97085--- nestedMap-hoverdef -- 97086-```go 97087-field m map[string]float64 97088-``` 97089- 97090-nested map 97091- 97092--- nestedNumber-hoverdef -- 97093-```go 97094-field number int64 97095-``` 97096- 97097-nested number 97098- 97099--- nestedString-hoverdef -- 97100-```go 97101-field str string 97102-``` 97103- 97104-nested string 97105- 97106--- openMethod-hoverdef -- 97107-```go 97108-func (interface).open() error 97109-``` 97110- 97111-open method comment 97112- 97113--- returnX-hoverdef -- 97114-```go 97115-field x int 97116-``` 97117- 97118-X coord 97119- 97120--- returnY-hoverdef -- 97121-```go 97122-field y int 97123-``` 97124- 97125-Y coord 97126- 97127--- structA-hoverdef -- 97128-```go 97129-field a int 97130-``` 97131- 97132-a field 97133- 97134--- structB-hoverdef -- 97135-```go 97136-field b struct{c int} 97137-``` 97138- 97139-b nested struct 97140- 97141--- structC-hoverdef -- 97142-```go 97143-field c int 97144-``` 97145- 97146-c field of nested struct 97147- 97148--- testDescription-hoverdef -- 97149-```go 97150-field desc string 97151-``` 97152- 97153-test description 97154- 97155--- testInput-hoverdef -- 97156-```go 97157-field in map[string][]struct{key string; value interface{}} 97158-``` 97159- 97160-test input 97161- 97162--- testInputKey-hoverdef -- 97163-```go 97164-field key string 97165-``` 97166- 97167-test key 97168- 97169--- testInputValue-hoverdef -- 97170-```go 97171-field value interface{} 97172-``` 97173- 97174-test value 97175- 97176--- testResultValue-hoverdef -- 97177-```go 97178-field value int 97179-``` 97180- 97181-expected test value 97182- 97183diff -urN a/gopls/internal/lsp/testdata/godef/b/e.go b/gopls/internal/lsp/testdata/godef/b/e.go 97184--- a/gopls/internal/lsp/testdata/godef/b/e.go 2000-01-01 00:00:00.000000000 -0000 97185+++ b/gopls/internal/lsp/testdata/godef/b/e.go 1970-01-01 00:00:00.000000000 +0000 97186@@ -1,31 +0,0 @@ 97187-package b 97188- 97189-import ( 97190- "fmt" 97191- 97192- "golang.org/lsptests/godef/a" 97193-) 97194- 97195-func useThings() { 97196- t := a.Thing{} //@mark(bStructType, "ing") 97197- fmt.Print(t.Member) //@mark(bMember, "ember") 97198- fmt.Print(a.Other) //@mark(bVar, "ther") 97199- a.Things() //@mark(bFunc, "ings") 97200-} 97201- 97202-/*@ 97203-godef(bStructType, Thing) 97204-godef(bMember, Member) 97205-godef(bVar, Other) 97206-godef(bFunc, Things) 97207-*/ 97208- 97209-func _() { 97210- var x interface{} //@mark(eInterface, "interface{}") 97211- switch x := x.(type) { //@hoverdef("x", eInterface) 97212- case string: //@mark(eString, "string") 97213- fmt.Println(x) //@hoverdef("x", eString) 97214- case int: //@mark(eInt, "int") 97215- fmt.Println(x) //@hoverdef("x", eInt) 97216- } 97217-} 97218diff -urN a/gopls/internal/lsp/testdata/godef/b/e.go.golden b/gopls/internal/lsp/testdata/godef/b/e.go.golden 97219--- a/gopls/internal/lsp/testdata/godef/b/e.go.golden 2000-01-01 00:00:00.000000000 -0000 97220+++ b/gopls/internal/lsp/testdata/godef/b/e.go.golden 1970-01-01 00:00:00.000000000 +0000 97221@@ -1,156 +0,0 @@ 97222--- Member-definition -- 97223-godef/a/d.go:6:2-8: defined here as ```go 97224-field Member string 97225-``` 97226- 97227-@Member 97228- 97229- 97230-[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) 97231--- Member-definition-json -- 97232-{ 97233- "span": { 97234- "uri": "file://godef/a/d.go", 97235- "start": { 97236- "line": 6, 97237- "column": 2, 97238- "offset": 90 97239- }, 97240- "end": { 97241- "line": 6, 97242- "column": 8, 97243- "offset": 96 97244- } 97245- }, 97246- "description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)" 97247-} 97248- 97249--- Member-hoverdef -- 97250-```go 97251-field Member string 97252-``` 97253- 97254-@Member 97255- 97256- 97257-[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) 97258--- Other-definition -- 97259-godef/a/d.go:9:5-10: defined here as ```go 97260-var a.Other a.Thing 97261-``` 97262- 97263-@Other 97264- 97265- 97266-[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) 97267--- Other-definition-json -- 97268-{ 97269- "span": { 97270- "uri": "file://godef/a/d.go", 97271- "start": { 97272- "line": 9, 97273- "column": 5, 97274- "offset": 121 97275- }, 97276- "end": { 97277- "line": 9, 97278- "column": 10, 97279- "offset": 126 97280- } 97281- }, 97282- "description": "```go\nvar a.Other a.Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)" 97283-} 97284- 97285--- Other-hoverdef -- 97286-```go 97287-var a.Other a.Thing 97288-``` 97289- 97290-@Other 97291- 97292- 97293-[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) 97294--- Thing-definition -- 97295-godef/a/d.go:5:6-11: defined here as ```go 97296-type Thing struct { 97297- Member string //@Member 97298-} 97299- 97300-func (a.Thing).Method(i int) string 97301-func (*a.Thing).Method2(i int, j int) (error, string) 97302-func (a.Thing).Method3() 97303-``` 97304- 97305-[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) 97306--- Thing-definition-json -- 97307-{ 97308- "span": { 97309- "uri": "file://godef/a/d.go", 97310- "start": { 97311- "line": 5, 97312- "column": 6, 97313- "offset": 65 97314- }, 97315- "end": { 97316- "line": 5, 97317- "column": 11, 97318- "offset": 70 97319- } 97320- }, 97321- "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (a.Thing).Method(i int) string\nfunc (*a.Thing).Method2(i int, j int) (error, string)\nfunc (a.Thing).Method3()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)" 97322-} 97323- 97324--- Thing-hoverdef -- 97325-```go 97326-type Thing struct { 97327- Member string //@Member 97328-} 97329- 97330-func (a.Thing).Method(i int) string 97331-func (*a.Thing).Method2(i int, j int) (error, string) 97332-func (a.Thing).Method3() 97333-``` 97334- 97335-[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) 97336--- Things-definition -- 97337-godef/a/d.go:11:6-12: defined here as ```go 97338-func a.Things(val []string) []a.Thing 97339-``` 97340- 97341-[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) 97342--- Things-definition-json -- 97343-{ 97344- "span": { 97345- "uri": "file://godef/a/d.go", 97346- "start": { 97347- "line": 11, 97348- "column": 6, 97349- "offset": 148 97350- }, 97351- "end": { 97352- "line": 11, 97353- "column": 12, 97354- "offset": 154 97355- } 97356- }, 97357- "description": "```go\nfunc a.Things(val []string) []a.Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)" 97358-} 97359- 97360--- Things-hoverdef -- 97361-```go 97362-func a.Things(val []string) []a.Thing 97363-``` 97364- 97365-[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) 97366--- eInt-hoverdef -- 97367-```go 97368-var x int 97369-``` 97370--- eInterface-hoverdef -- 97371-```go 97372-var x interface{} 97373-``` 97374--- eString-hoverdef -- 97375-```go 97376-var x string 97377-``` 97378diff -urN a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden 97379--- a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden 2000-01-01 00:00:00.000000000 -0000 97380+++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden 1970-01-01 00:00:00.000000000 +0000 97381@@ -1,31 +0,0 @@ 97382--- myUnclosedIf-definition -- 97383-godef/broken/unclosedIf.go:7:7-19: defined here as ```go 97384-var myUnclosedIf string 97385-``` 97386- 97387-@myUnclosedIf 97388--- myUnclosedIf-definition-json -- 97389-{ 97390- "span": { 97391- "uri": "file://godef/broken/unclosedIf.go", 97392- "start": { 97393- "line": 7, 97394- "column": 7, 97395- "offset": 68 97396- }, 97397- "end": { 97398- "line": 7, 97399- "column": 19, 97400- "offset": 80 97401- } 97402- }, 97403- "description": "```go\nvar myUnclosedIf string\n```\n\n@myUnclosedIf" 97404-} 97405- 97406--- myUnclosedIf-hoverdef -- 97407-```go 97408-var myUnclosedIf string 97409-``` 97410- 97411-@myUnclosedIf 97412- 97413diff -urN a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in 97414--- a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in 2000-01-01 00:00:00.000000000 -0000 97415+++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in 1970-01-01 00:00:00.000000000 +0000 97416@@ -1,9 +0,0 @@ 97417-package broken 97418- 97419-import "fmt" 97420- 97421-func unclosedIf() { 97422- if false { 97423- var myUnclosedIf string //@myUnclosedIf 97424- fmt.Printf("s = %v\n", myUnclosedIf) //@godef("my", myUnclosedIf) 97425-} 97426diff -urN a/gopls/internal/lsp/testdata/good/good0.go b/gopls/internal/lsp/testdata/good/good0.go 97427--- a/gopls/internal/lsp/testdata/good/good0.go 2000-01-01 00:00:00.000000000 -0000 97428+++ b/gopls/internal/lsp/testdata/good/good0.go 1970-01-01 00:00:00.000000000 +0000 97429@@ -1,6 +0,0 @@ 97430-package good //@diag("package", "no_diagnostics", "", "error") 97431- 97432-func stuff() { //@item(good_stuff, "stuff", "func()", "func"),prepare("stu", "stuff", "stuff") 97433- x := 5 97434- random2(x) //@prepare("dom", "random2", "random2") 97435-} 97436diff -urN a/gopls/internal/lsp/testdata/good/good1.go b/gopls/internal/lsp/testdata/good/good1.go 97437--- a/gopls/internal/lsp/testdata/good/good1.go 2000-01-01 00:00:00.000000000 -0000 97438+++ b/gopls/internal/lsp/testdata/good/good1.go 1970-01-01 00:00:00.000000000 +0000 97439@@ -1,21 +0,0 @@ 97440-package good //@diag("package", "no_diagnostics", "", "error") 97441- 97442-import ( 97443- "golang.org/lsptests/types" //@item(types_import, "types", "\"golang.org/lsptests/types\"", "package") 97444-) 97445- 97446-func random() int { //@item(good_random, "random", "func() int", "func") 97447- _ = "random() int" //@prepare("random", "", "") 97448- y := 6 + 7 //@prepare("7", "", "") 97449- return y //@prepare("return", "","") 97450-} 97451- 97452-func random2(y int) int { //@item(good_random2, "random2", "func(y int) int", "func"),item(good_y_param, "y", "int", "var") 97453- //@complete("", good_y_param, types_import, good_random, good_random2, good_stuff) 97454- var b types.Bob = &types.X{} //@prepare("ypes","types", "types") 97455- if _, ok := b.(*types.X); ok { //@complete("X", X_struct, Y_struct, Bob_interface, CoolAlias) 97456- _ = 0 // suppress "empty branch" diagnostic 97457- } 97458- 97459- return y 97460-} 97461diff -urN a/gopls/internal/lsp/testdata/highlights/highlights.go b/gopls/internal/lsp/testdata/highlights/highlights.go 97462--- a/gopls/internal/lsp/testdata/highlights/highlights.go 2000-01-01 00:00:00.000000000 -0000 97463+++ b/gopls/internal/lsp/testdata/highlights/highlights.go 1970-01-01 00:00:00.000000000 +0000 97464@@ -1,151 +0,0 @@ 97465-package highlights 97466- 97467-import ( 97468- "fmt" //@mark(fmtImp, "\"fmt\""),highlight(fmtImp, fmtImp, fmt1, fmt2, fmt3, fmt4) 97469- h2 "net/http" //@mark(hImp, "h2"),highlight(hImp, hImp, hUse) 97470- "sort" 97471-) 97472- 97473-type F struct{ bar int } //@mark(barDeclaration, "bar"),highlight(barDeclaration, barDeclaration, bar1, bar2, bar3) 97474- 97475-func _() F { 97476- return F{ 97477- bar: 123, //@mark(bar1, "bar"),highlight(bar1, barDeclaration, bar1, bar2, bar3) 97478- } 97479-} 97480- 97481-var foo = F{bar: 52} //@mark(fooDeclaration, "foo"),mark(bar2, "bar"),highlight(fooDeclaration, fooDeclaration, fooUse),highlight(bar2, barDeclaration, bar1, bar2, bar3) 97482- 97483-func Print() { //@mark(printFunc, "Print"),highlight(printFunc, printFunc, printTest) 97484- _ = h2.Client{} //@mark(hUse, "h2"),highlight(hUse, hImp, hUse) 97485- 97486- fmt.Println(foo) //@mark(fooUse, "foo"),highlight(fooUse, fooDeclaration, fooUse),mark(fmt1, "fmt"),highlight(fmt1, fmtImp, fmt1, fmt2, fmt3, fmt4) 97487- fmt.Print("yo") //@mark(printSep, "Print"),highlight(printSep, printSep, print1, print2),mark(fmt2, "fmt"),highlight(fmt2, fmtImp, fmt1, fmt2, fmt3, fmt4) 97488-} 97489- 97490-func (x *F) Inc() { //@mark(xRightDecl, "x"),mark(xLeftDecl, " *"),highlight(xRightDecl, xRightDecl, xUse),highlight(xLeftDecl, xRightDecl, xUse) 97491- x.bar++ //@mark(xUse, "x"),mark(bar3, "bar"),highlight(xUse, xRightDecl, xUse),highlight(bar3, barDeclaration, bar1, bar2, bar3) 97492-} 97493- 97494-func testFunctions() { 97495- fmt.Print("main start") //@mark(print1, "Print"),highlight(print1, printSep, print1, print2),mark(fmt3, "fmt"),highlight(fmt3, fmtImp, fmt1, fmt2, fmt3, fmt4) 97496- fmt.Print("ok") //@mark(print2, "Print"),highlight(print2, printSep, print1, print2),mark(fmt4, "fmt"),highlight(fmt4, fmtImp, fmt1, fmt2, fmt3, fmt4) 97497- Print() //@mark(printTest, "Print"),highlight(printTest, printFunc, printTest) 97498-} 97499- 97500-func toProtocolHighlight(rngs []int) []DocumentHighlight { //@mark(doc1, "DocumentHighlight"),mark(docRet1, "[]DocumentHighlight"),highlight(doc1, docRet1, doc1, doc2, doc3, result) 97501- result := make([]DocumentHighlight, 0, len(rngs)) //@mark(doc2, "DocumentHighlight"),highlight(doc2, doc1, doc2, doc3) 97502- for _, rng := range rngs { 97503- result = append(result, DocumentHighlight{ //@mark(doc3, "DocumentHighlight"),highlight(doc3, doc1, doc2, doc3) 97504- Range: rng, 97505- }) 97506- } 97507- return result //@mark(result, "result") 97508-} 97509- 97510-func testForLoops() { 97511- for i := 0; i < 10; i++ { //@mark(forDecl1, "for"),highlight(forDecl1, forDecl1, brk1, cont1) 97512- if i > 8 { 97513- break //@mark(brk1, "break"),highlight(brk1, forDecl1, brk1, cont1) 97514- } 97515- if i < 2 { 97516- for j := 1; j < 10; j++ { //@mark(forDecl2, "for"),highlight(forDecl2, forDecl2, cont2) 97517- if j < 3 { 97518- for k := 1; k < 10; k++ { //@mark(forDecl3, "for"),highlight(forDecl3, forDecl3, cont3) 97519- if k < 3 { 97520- continue //@mark(cont3, "continue"),highlight(cont3, forDecl3, cont3) 97521- } 97522- } 97523- continue //@mark(cont2, "continue"),highlight(cont2, forDecl2, cont2) 97524- } 97525- } 97526- continue //@mark(cont1, "continue"),highlight(cont1, forDecl1, brk1, cont1) 97527- } 97528- } 97529- 97530- arr := []int{} 97531- for i := range arr { //@mark(forDecl4, "for"),highlight(forDecl4, forDecl4, brk4, cont4) 97532- if i > 8 { 97533- break //@mark(brk4, "break"),highlight(brk4, forDecl4, brk4, cont4) 97534- } 97535- if i < 4 { 97536- continue //@mark(cont4, "continue"),highlight(cont4, forDecl4, brk4, cont4) 97537- } 97538- } 97539- 97540-Outer: 97541- for i := 0; i < 10; i++ { //@mark(forDecl5, "for"),highlight(forDecl5, forDecl5, brk5, brk6, brk8) 97542- break //@mark(brk5, "break"),highlight(brk5, forDecl5, brk5, brk6, brk8) 97543- for { //@mark(forDecl6, "for"),highlight(forDecl6, forDecl6, cont5) 97544- if i == 1 { 97545- break Outer //@mark(brk6, "break Outer"),highlight(brk6, forDecl5, brk5, brk6, brk8) 97546- } 97547- switch i { //@mark(switch1, "switch"),highlight(switch1, switch1, brk7) 97548- case 5: 97549- break //@mark(brk7, "break"),highlight(brk7, switch1, brk7) 97550- case 6: 97551- continue //@mark(cont5, "continue"),highlight(cont5, forDecl6, cont5) 97552- case 7: 97553- break Outer //@mark(brk8, "break Outer"),highlight(brk8, forDecl5, brk5, brk6, brk8) 97554- } 97555- } 97556- } 97557-} 97558- 97559-func testSwitch() { 97560- var i, j int 97561- 97562-L1: 97563- for { //@mark(forDecl7, "for"),highlight(forDecl7, forDecl7, brk10, cont6) 97564- L2: 97565- switch i { //@mark(switch2, "switch"),highlight(switch2, switch2, brk11, brk12, brk13) 97566- case 1: 97567- switch j { //@mark(switch3, "switch"),highlight(switch3, switch3, brk9) 97568- case 1: 97569- break //@mark(brk9, "break"),highlight(brk9, switch3, brk9) 97570- case 2: 97571- break L1 //@mark(brk10, "break L1"),highlight(brk10, forDecl7, brk10, cont6) 97572- case 3: 97573- break L2 //@mark(brk11, "break L2"),highlight(brk11, switch2, brk11, brk12, brk13) 97574- default: 97575- continue //@mark(cont6, "continue"),highlight(cont6, forDecl7, brk10, cont6) 97576- } 97577- case 2: 97578- break //@mark(brk12, "break"),highlight(brk12, switch2, brk11, brk12, brk13) 97579- default: 97580- break L2 //@mark(brk13, "break L2"),highlight(brk13, switch2, brk11, brk12, brk13) 97581- } 97582- } 97583-} 97584- 97585-func testReturn() bool { //@mark(func1, "func"),mark(bool1, "bool"),highlight(func1, func1, fullRet11, fullRet12),highlight(bool1, bool1, false1, bool2, true1) 97586- if 1 < 2 { 97587- return false //@mark(ret11, "return"),mark(fullRet11, "return false"),mark(false1, "false"),highlight(ret11, func1, fullRet11, fullRet12) 97588- } 97589- candidates := []int{} 97590- sort.SliceStable(candidates, func(i, j int) bool { //@mark(func2, "func"),mark(bool2, "bool"),highlight(func2, func2, fullRet2) 97591- return candidates[i] > candidates[j] //@mark(ret2, "return"),mark(fullRet2, "return candidates[i] > candidates[j]"),highlight(ret2, func2, fullRet2) 97592- }) 97593- return true //@mark(ret12, "return"),mark(fullRet12, "return true"),mark(true1, "true"),highlight(ret12, func1, fullRet11, fullRet12) 97594-} 97595- 97596-func testReturnFields() float64 { //@mark(retVal1, "float64"),highlight(retVal1, retVal1, retVal11, retVal21) 97597- if 1 < 2 { 97598- return 20.1 //@mark(retVal11, "20.1"),highlight(retVal11, retVal1, retVal11, retVal21) 97599- } 97600- z := 4.3 //@mark(zDecl, "z") 97601- return z //@mark(retVal21, "z"),highlight(retVal21, retVal1, retVal11, zDecl, retVal21) 97602-} 97603- 97604-func testReturnMultipleFields() (float32, string) { //@mark(retVal31, "float32"),mark(retVal32, "string"),highlight(retVal31, retVal31, retVal41, retVal51),highlight(retVal32, retVal32, retVal42, retVal52) 97605- y := "im a var" //@mark(yDecl, "y"), 97606- if 1 < 2 { 97607- return 20.1, y //@mark(retVal41, "20.1"),mark(retVal42, "y"),highlight(retVal41, retVal31, retVal41, retVal51),highlight(retVal42, retVal32, yDecl, retVal42, retVal52) 97608- } 97609- return 4.9, "test" //@mark(retVal51, "4.9"),mark(retVal52, "\"test\""),highlight(retVal51, retVal31, retVal41, retVal51),highlight(retVal52, retVal32, retVal42, retVal52) 97610-} 97611- 97612-func testReturnFunc() int32 { //@mark(retCall, "int32") 97613- mulch := 1 //@mark(mulchDec, "mulch"),highlight(mulchDec, mulchDec, mulchRet) 97614- return int32(mulch) //@mark(mulchRet, "mulch"),mark(retFunc, "int32"),mark(retTotal, "int32(mulch)"),highlight(mulchRet, mulchDec, mulchRet),highlight(retFunc, retCall, retFunc, retTotal) 97615-} 97616diff -urN a/gopls/internal/lsp/testdata/implementation/implementation_generics.go b/gopls/internal/lsp/testdata/implementation/implementation_generics.go 97617--- a/gopls/internal/lsp/testdata/implementation/implementation_generics.go 2000-01-01 00:00:00.000000000 -0000 97618+++ b/gopls/internal/lsp/testdata/implementation/implementation_generics.go 1970-01-01 00:00:00.000000000 +0000 97619@@ -1,16 +0,0 @@ 97620-//go:build go1.18 97621-// +build go1.18 97622- 97623-package implementation 97624- 97625-// -- generics -- 97626- 97627-type GenIface[T any] interface { //@mark(GenIface, "GenIface"),implementations("GenIface", GC) 97628- F(int, string, T) //@mark(GenIfaceF, "F"),implementations("F", GCF) 97629-} 97630- 97631-type GenConc[U any] int //@mark(GenConc, "GenConc"),implementations("GenConc", GI) 97632- 97633-func (GenConc[V]) F(int, string, V) {} //@mark(GenConcF, "F"),implementations("F", GIF) 97634- 97635-type GenConcString struct{ GenConc[string] } //@mark(GenConcString, "GenConcString"),implementations(GenConcString, GIString) 97636diff -urN a/gopls/internal/lsp/testdata/implementation/implementation.go b/gopls/internal/lsp/testdata/implementation/implementation.go 97637--- a/gopls/internal/lsp/testdata/implementation/implementation.go 2000-01-01 00:00:00.000000000 -0000 97638+++ b/gopls/internal/lsp/testdata/implementation/implementation.go 1970-01-01 00:00:00.000000000 +0000 97639@@ -1,37 +0,0 @@ 97640-package implementation 97641- 97642-import "golang.org/lsptests/implementation/other" 97643- 97644-type ImpP struct{} //@ImpP,implementations("ImpP", Laugher, OtherLaugher) 97645- 97646-func (*ImpP) Laugh() { //@mark(LaughP, "Laugh"),implementations("Laugh", Laugh, OtherLaugh) 97647-} 97648- 97649-type ImpS struct{} //@ImpS,implementations("ImpS", Laugher, OtherLaugher) 97650- 97651-func (ImpS) Laugh() { //@mark(LaughS, "Laugh"),implementations("Laugh", Laugh, OtherLaugh) 97652-} 97653- 97654-type Laugher interface { //@Laugher,implementations("Laugher", ImpP, OtherImpP, ImpS, OtherImpS, embedsImpP) 97655- Laugh() //@Laugh,implementations("Laugh", LaughP, OtherLaughP, LaughS, OtherLaughS) 97656-} 97657- 97658-type Foo struct { //@implementations("Foo", Joker) 97659- other.Foo 97660-} 97661- 97662-type Joker interface { //@Joker 97663- Joke() //@Joke,implementations("Joke", ImpJoker) 97664-} 97665- 97666-type cryer int //@implementations("cryer", Cryer) 97667- 97668-func (cryer) Cry(other.CryType) {} //@mark(CryImpl, "Cry"),implementations("Cry", Cry) 97669- 97670-type Empty interface{} //@implementations("Empty") 97671- 97672-var _ interface{ Joke() } //@implementations("Joke", ImpJoker) 97673- 97674-type embedsImpP struct { //@embedsImpP 97675- ImpP //@implementations("ImpP", Laugher, OtherLaugher) 97676-} 97677diff -urN a/gopls/internal/lsp/testdata/implementation/other/other_generics.go b/gopls/internal/lsp/testdata/implementation/other/other_generics.go 97678--- a/gopls/internal/lsp/testdata/implementation/other/other_generics.go 2000-01-01 00:00:00.000000000 -0000 97679+++ b/gopls/internal/lsp/testdata/implementation/other/other_generics.go 1970-01-01 00:00:00.000000000 +0000 97680@@ -1,16 +0,0 @@ 97681-//go:build go1.18 97682-// +build go1.18 97683- 97684-package other 97685- 97686-// -- generics (limited support) -- 97687- 97688-type GI[T any] interface { //@mark(GI, "GI"),implementations("GI", GenConc) 97689- F(int, string, T) //@mark(GIF, "F"),implementations("F", GenConcF) 97690-} 97691- 97692-type GIString GI[string] //@mark(GIString, "GIString"),implementations("GIString", GenConcString) 97693- 97694-type GC[U any] int //@mark(GC, "GC"),implementations("GC", GenIface) 97695- 97696-func (GC[V]) F(int, string, V) {} //@mark(GCF, "F"),implementations("F", GenIfaceF) 97697diff -urN a/gopls/internal/lsp/testdata/implementation/other/other.go b/gopls/internal/lsp/testdata/implementation/other/other.go 97698--- a/gopls/internal/lsp/testdata/implementation/other/other.go 2000-01-01 00:00:00.000000000 -0000 97699+++ b/gopls/internal/lsp/testdata/implementation/other/other.go 1970-01-01 00:00:00.000000000 +0000 97700@@ -1,27 +0,0 @@ 97701-package other 97702- 97703-type ImpP struct{} //@mark(OtherImpP, "ImpP") 97704- 97705-func (*ImpP) Laugh() { //@mark(OtherLaughP, "Laugh") 97706-} 97707- 97708-type ImpS struct{} //@mark(OtherImpS, "ImpS") 97709- 97710-func (ImpS) Laugh() { //@mark(OtherLaughS, "Laugh") 97711-} 97712- 97713-type ImpI interface { //@mark(OtherLaugher, "ImpI") 97714- Laugh() //@mark(OtherLaugh, "Laugh") 97715-} 97716- 97717-type Foo struct { //@implementations("Foo", Joker) 97718-} 97719- 97720-func (Foo) Joke() { //@mark(ImpJoker, "Joke"),implementations("Joke", Joke) 97721-} 97722- 97723-type CryType int 97724- 97725-type Cryer interface { //@Cryer 97726- Cry(CryType) //@Cry,implementations("Cry", CryImpl) 97727-} 97728diff -urN a/gopls/internal/lsp/testdata/implementation/other/other_test.go b/gopls/internal/lsp/testdata/implementation/other/other_test.go 97729--- a/gopls/internal/lsp/testdata/implementation/other/other_test.go 2000-01-01 00:00:00.000000000 -0000 97730+++ b/gopls/internal/lsp/testdata/implementation/other/other_test.go 1970-01-01 00:00:00.000000000 +0000 97731@@ -1,10 +0,0 @@ 97732-package other 97733- 97734-import ( 97735- "testing" 97736-) 97737- 97738-// This exists so the other.test package comes into existence. 97739- 97740-func TestOther(t *testing.T) { 97741-} 97742diff -urN a/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in 97743--- a/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in 2000-01-01 00:00:00.000000000 -0000 97744+++ b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in 1970-01-01 00:00:00.000000000 +0000 97745@@ -1,42 +0,0 @@ 97746-package importedcomplit 97747- 97748-import ( 97749- "golang.org/lsptests/foo" 97750- 97751- // import completions 97752- "fm" //@complete("\" //", fmtImport) 97753- "go/pars" //@complete("\" //", parserImport) 97754- "golang.org/lsptests/signa" //@complete("na\" //", signatureImport) 97755- "golang.org/lspte" //@complete("\" //", lsptestsImport) 97756- "crypto/elli" //@complete("\" //", cryptoImport) 97757- "golang.org/lsptests/sign" //@complete("\" //", signatureImport) 97758- "golang.org/lsptests/sign" //@complete("ests", lsptestsImport) 97759- namedParser "go/pars" //@complete("\" //", parserImport) 97760-) 97761- 97762-func _() { 97763- var V int //@item(icVVar, "V", "int", "var") 97764- _ = foo.StructFoo{V} //@complete("}", Value, icVVar) 97765-} 97766- 97767-func _() { 97768- var ( 97769- aa string //@item(icAAVar, "aa", "string", "var") 97770- ab int //@item(icABVar, "ab", "int", "var") 97771- ) 97772- 97773- _ = foo.StructFoo{a} //@complete("}", abVar, aaVar) 97774- 97775- var s struct { 97776- AA string //@item(icFieldAA, "AA", "string", "field") 97777- AB int //@item(icFieldAB, "AB", "int", "field") 97778- } 97779- 97780- _ = foo.StructFoo{s.} //@complete("}", icFieldAB, icFieldAA) 97781-} 97782- 97783-/* "fmt" */ //@item(fmtImport, "fmt", "\"fmt\"", "package") 97784-/* "go/parser" */ //@item(parserImport, "parser", "\"go/parser\"", "package") 97785-/* "golang.org/lsptests/signature" */ //@item(signatureImport, "signature", "\"golang.org/lsptests/signature\"", "package") 97786-/* "golang.org/lsptests/" */ //@item(lsptestsImport, "lsptests/", "\"golang.org/lsptests/\"", "package") 97787-/* "crypto/elliptic" */ //@item(cryptoImport, "elliptic", "\"crypto/elliptic\"", "package") 97788diff -urN a/gopls/internal/lsp/testdata/imports/add_import.go.golden b/gopls/internal/lsp/testdata/imports/add_import.go.golden 97789--- a/gopls/internal/lsp/testdata/imports/add_import.go.golden 2000-01-01 00:00:00.000000000 -0000 97790+++ b/gopls/internal/lsp/testdata/imports/add_import.go.golden 1970-01-01 00:00:00.000000000 +0000 97791@@ -1,13 +0,0 @@ 97792--- goimports -- 97793-package imports //@import("package") 97794- 97795-import ( 97796- "bytes" 97797- "fmt" 97798-) 97799- 97800-func _() { 97801- fmt.Println("") 97802- bytes.NewBuffer(nil) 97803-} 97804- 97805diff -urN a/gopls/internal/lsp/testdata/imports/add_import.go.in b/gopls/internal/lsp/testdata/imports/add_import.go.in 97806--- a/gopls/internal/lsp/testdata/imports/add_import.go.in 2000-01-01 00:00:00.000000000 -0000 97807+++ b/gopls/internal/lsp/testdata/imports/add_import.go.in 1970-01-01 00:00:00.000000000 +0000 97808@@ -1,10 +0,0 @@ 97809-package imports //@import("package") 97810- 97811-import ( 97812- "fmt" 97813-) 97814- 97815-func _() { 97816- fmt.Println("") 97817- bytes.NewBuffer(nil) 97818-} 97819diff -urN a/gopls/internal/lsp/testdata/imports/good_imports.go.golden b/gopls/internal/lsp/testdata/imports/good_imports.go.golden 97820--- a/gopls/internal/lsp/testdata/imports/good_imports.go.golden 2000-01-01 00:00:00.000000000 -0000 97821+++ b/gopls/internal/lsp/testdata/imports/good_imports.go.golden 1970-01-01 00:00:00.000000000 +0000 97822@@ -1,9 +0,0 @@ 97823--- goimports -- 97824-package imports //@import("package") 97825- 97826-import "fmt" 97827- 97828-func _() { 97829-fmt.Println("") 97830-} 97831- 97832diff -urN a/gopls/internal/lsp/testdata/imports/good_imports.go.in b/gopls/internal/lsp/testdata/imports/good_imports.go.in 97833--- a/gopls/internal/lsp/testdata/imports/good_imports.go.in 2000-01-01 00:00:00.000000000 -0000 97834+++ b/gopls/internal/lsp/testdata/imports/good_imports.go.in 1970-01-01 00:00:00.000000000 +0000 97835@@ -1,7 +0,0 @@ 97836-package imports //@import("package") 97837- 97838-import "fmt" 97839- 97840-func _() { 97841-fmt.Println("") 97842-} 97843diff -urN a/gopls/internal/lsp/testdata/imports/issue35458.go.golden b/gopls/internal/lsp/testdata/imports/issue35458.go.golden 97844--- a/gopls/internal/lsp/testdata/imports/issue35458.go.golden 2000-01-01 00:00:00.000000000 -0000 97845+++ b/gopls/internal/lsp/testdata/imports/issue35458.go.golden 1970-01-01 00:00:00.000000000 +0000 97846@@ -1,20 +0,0 @@ 97847--- goimports -- 97848-// package doc 97849-package imports //@import("package") 97850- 97851- 97852- 97853- 97854- 97855- 97856-func _() { 97857- println("Hello, world!") 97858-} 97859- 97860- 97861- 97862- 97863- 97864- 97865- 97866- 97867diff -urN a/gopls/internal/lsp/testdata/imports/issue35458.go.in b/gopls/internal/lsp/testdata/imports/issue35458.go.in 97868--- a/gopls/internal/lsp/testdata/imports/issue35458.go.in 2000-01-01 00:00:00.000000000 -0000 97869+++ b/gopls/internal/lsp/testdata/imports/issue35458.go.in 1970-01-01 00:00:00.000000000 +0000 97870@@ -1,23 +0,0 @@ 97871- 97872- 97873- 97874- 97875- 97876-// package doc 97877-package imports //@import("package") 97878- 97879- 97880- 97881- 97882- 97883- 97884-func _() { 97885- println("Hello, world!") 97886-} 97887- 97888- 97889- 97890- 97891- 97892- 97893- 97894diff -urN a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden 97895--- a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden 2000-01-01 00:00:00.000000000 -0000 97896+++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden 1970-01-01 00:00:00.000000000 +0000 97897@@ -1,9 +0,0 @@ 97898--- goimports -- 97899-package imports //@import("package") 97900- 97901-import "fmt" 97902- 97903-func _() { 97904- fmt.Println("") 97905-} 97906- 97907diff -urN a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in 97908--- a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in 2000-01-01 00:00:00.000000000 -0000 97909+++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in 1970-01-01 00:00:00.000000000 +0000 97910@@ -1,9 +0,0 @@ 97911-package imports //@import("package") 97912- 97913-import "fmt" 97914- 97915-import "bytes" 97916- 97917-func _() { 97918- fmt.Println("") 97919-} 97920diff -urN a/gopls/internal/lsp/testdata/imports/needs_imports.go.golden b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden 97921--- a/gopls/internal/lsp/testdata/imports/needs_imports.go.golden 2000-01-01 00:00:00.000000000 -0000 97922+++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden 1970-01-01 00:00:00.000000000 +0000 97923@@ -1,13 +0,0 @@ 97924--- goimports -- 97925-package imports //@import("package") 97926- 97927-import ( 97928- "fmt" 97929- "log" 97930-) 97931- 97932-func goodbye() { 97933- fmt.Printf("HI") 97934- log.Printf("byeeeee") 97935-} 97936- 97937diff -urN a/gopls/internal/lsp/testdata/imports/needs_imports.go.in b/gopls/internal/lsp/testdata/imports/needs_imports.go.in 97938--- a/gopls/internal/lsp/testdata/imports/needs_imports.go.in 2000-01-01 00:00:00.000000000 -0000 97939+++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.in 1970-01-01 00:00:00.000000000 +0000 97940@@ -1,6 +0,0 @@ 97941-package imports //@import("package") 97942- 97943-func goodbye() { 97944- fmt.Printf("HI") 97945- log.Printf("byeeeee") 97946-} 97947diff -urN a/gopls/internal/lsp/testdata/imports/remove_import.go.golden b/gopls/internal/lsp/testdata/imports/remove_import.go.golden 97948--- a/gopls/internal/lsp/testdata/imports/remove_import.go.golden 2000-01-01 00:00:00.000000000 -0000 97949+++ b/gopls/internal/lsp/testdata/imports/remove_import.go.golden 1970-01-01 00:00:00.000000000 +0000 97950@@ -1,11 +0,0 @@ 97951--- goimports -- 97952-package imports //@import("package") 97953- 97954-import ( 97955- "fmt" 97956-) 97957- 97958-func _() { 97959- fmt.Println("") 97960-} 97961- 97962diff -urN a/gopls/internal/lsp/testdata/imports/remove_import.go.in b/gopls/internal/lsp/testdata/imports/remove_import.go.in 97963--- a/gopls/internal/lsp/testdata/imports/remove_import.go.in 2000-01-01 00:00:00.000000000 -0000 97964+++ b/gopls/internal/lsp/testdata/imports/remove_import.go.in 1970-01-01 00:00:00.000000000 +0000 97965@@ -1,10 +0,0 @@ 97966-package imports //@import("package") 97967- 97968-import ( 97969- "bytes" 97970- "fmt" 97971-) 97972- 97973-func _() { 97974- fmt.Println("") 97975-} 97976diff -urN a/gopls/internal/lsp/testdata/imports/remove_imports.go.golden b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden 97977--- a/gopls/internal/lsp/testdata/imports/remove_imports.go.golden 2000-01-01 00:00:00.000000000 -0000 97978+++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden 1970-01-01 00:00:00.000000000 +0000 97979@@ -1,6 +0,0 @@ 97980--- goimports -- 97981-package imports //@import("package") 97982- 97983-func _() { 97984-} 97985- 97986diff -urN a/gopls/internal/lsp/testdata/imports/remove_imports.go.in b/gopls/internal/lsp/testdata/imports/remove_imports.go.in 97987--- a/gopls/internal/lsp/testdata/imports/remove_imports.go.in 2000-01-01 00:00:00.000000000 -0000 97988+++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.in 1970-01-01 00:00:00.000000000 +0000 97989@@ -1,9 +0,0 @@ 97990-package imports //@import("package") 97991- 97992-import ( 97993- "bytes" 97994- "fmt" 97995-) 97996- 97997-func _() { 97998-} 97999diff -urN a/gopls/internal/lsp/testdata/imports/two_lines.go.golden b/gopls/internal/lsp/testdata/imports/two_lines.go.golden 98000--- a/gopls/internal/lsp/testdata/imports/two_lines.go.golden 2000-01-01 00:00:00.000000000 -0000 98001+++ b/gopls/internal/lsp/testdata/imports/two_lines.go.golden 1970-01-01 00:00:00.000000000 +0000 98002@@ -1,4 +0,0 @@ 98003--- goimports -- 98004-package main 98005-func main() {} //@import("main") 98006- 98007diff -urN a/gopls/internal/lsp/testdata/imports/two_lines.go.in b/gopls/internal/lsp/testdata/imports/two_lines.go.in 98008--- a/gopls/internal/lsp/testdata/imports/two_lines.go.in 2000-01-01 00:00:00.000000000 -0000 98009+++ b/gopls/internal/lsp/testdata/imports/two_lines.go.in 1970-01-01 00:00:00.000000000 +0000 98010@@ -1,2 +0,0 @@ 98011-package main 98012-func main() {} //@import("main") 98013diff -urN a/gopls/internal/lsp/testdata/index/index.go b/gopls/internal/lsp/testdata/index/index.go 98014--- a/gopls/internal/lsp/testdata/index/index.go 2000-01-01 00:00:00.000000000 -0000 98015+++ b/gopls/internal/lsp/testdata/index/index.go 1970-01-01 00:00:00.000000000 +0000 98016@@ -1,25 +0,0 @@ 98017-package index 98018- 98019-func _() { 98020- var ( 98021- aa = "123" //@item(indexAA, "aa", "string", "var") 98022- ab = 123 //@item(indexAB, "ab", "int", "var") 98023- ) 98024- 98025- var foo [1]int 98026- foo[a] //@complete("]", indexAB, indexAA) 98027- foo[:a] //@complete("]", indexAB, indexAA) 98028- a[:a] //@complete("[", indexAA, indexAB) 98029- a[a] //@complete("[", indexAA, indexAB) 98030- 98031- var bar map[string]int 98032- bar[a] //@complete("]", indexAA, indexAB) 98033- 98034- type myMap map[string]int 98035- var baz myMap 98036- baz[a] //@complete("]", indexAA, indexAB) 98037- 98038- type myInt int 98039- var mi myInt //@item(indexMyInt, "mi", "myInt", "var") 98040- foo[m] //@snippet("]", indexMyInt, "mi", "mi") 98041-} 98042diff -urN a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go 98043--- a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go 2000-01-01 00:00:00.000000000 -0000 98044+++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go 1970-01-01 00:00:00.000000000 +0000 98045@@ -1,27 +0,0 @@ 98046-package inlayHint //@inlayHint("package") 98047- 98048-import "fmt" 98049- 98050-func fieldNames() { 98051- for _, c := range []struct { 98052- in, want string 98053- }{ 98054- struct{ in, want string }{"Hello, world", "dlrow ,olleH"}, 98055- {"Hello, 世界", "界世 ,olleH"}, 98056- {"", ""}, 98057- } { 98058- fmt.Println(c.in == c.want) 98059- } 98060-} 98061- 98062-func fieldNamesPointers() { 98063- for _, c := range []*struct { 98064- in, want string 98065- }{ 98066- &struct{ in, want string }{"Hello, world", "dlrow ,olleH"}, 98067- {"Hello, 世界", "界世 ,olleH"}, 98068- {"", ""}, 98069- } { 98070- fmt.Println(c.in == c.want) 98071- } 98072-} 98073diff -urN a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden 98074--- a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden 2000-01-01 00:00:00.000000000 -0000 98075+++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden 1970-01-01 00:00:00.000000000 +0000 98076@@ -1,29 +0,0 @@ 98077--- inlayHint -- 98078-package inlayHint //@inlayHint("package") 98079- 98080-import "fmt" 98081- 98082-func fieldNames() { 98083- for _< int>, c< struct{in string; want string}> := range []struct { 98084- in, want string 98085- }{ 98086- struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"}, 98087- <struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"}, 98088- <struct{in string; want string}>{<in: >"", <want: >""}, 98089- } { 98090- fmt.Println(<a...: >c.in == c.want) 98091- } 98092-} 98093- 98094-func fieldNamesPointers() { 98095- for _< int>, c< *struct{in string; want string}> := range []*struct { 98096- in, want string 98097- }{ 98098- &struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"}, 98099- <&struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"}, 98100- <&struct{in string; want string}>{<in: >"", <want: >""}, 98101- } { 98102- fmt.Println(<a...: >c.in == c.want) 98103- } 98104-} 98105- 98106diff -urN a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go 98107--- a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go 2000-01-01 00:00:00.000000000 -0000 98108+++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go 1970-01-01 00:00:00.000000000 +0000 98109@@ -1,45 +0,0 @@ 98110-package inlayHint //@inlayHint("package") 98111- 98112-const True = true 98113- 98114-type Kind int 98115- 98116-const ( 98117- KindNone Kind = iota 98118- KindPrint 98119- KindPrintf 98120- KindErrorf 98121-) 98122- 98123-const ( 98124- u = iota * 4 98125- v float64 = iota * 42 98126- w = iota * 42 98127-) 98128- 98129-const ( 98130- a, b = 1, 2 98131- c, d 98132- e, f = 5 * 5, "hello" + "world" 98133- g, h 98134- i, j = true, f 98135-) 98136- 98137-// No hint 98138-const ( 98139- Int = 3 98140- Float = 3.14 98141- Bool = true 98142- Rune = '3' 98143- Complex = 2.7i 98144- String = "Hello, world!" 98145-) 98146- 98147-var ( 98148- varInt = 3 98149- varFloat = 3.14 98150- varBool = true 98151- varRune = '3' + '4' 98152- varComplex = 2.7i 98153- varString = "Hello, world!" 98154-) 98155diff -urN a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden 98156--- a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden 2000-01-01 00:00:00.000000000 -0000 98157+++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden 1970-01-01 00:00:00.000000000 +0000 98158@@ -1,47 +0,0 @@ 98159--- inlayHint -- 98160-package inlayHint //@inlayHint("package") 98161- 98162-const True = true 98163- 98164-type Kind int 98165- 98166-const ( 98167- KindNone Kind = iota< = 0> 98168- KindPrint< = 1> 98169- KindPrintf< = 2> 98170- KindErrorf< = 3> 98171-) 98172- 98173-const ( 98174- u = iota * 4< = 0> 98175- v float64 = iota * 42< = 42> 98176- w = iota * 42< = 84> 98177-) 98178- 98179-const ( 98180- a, b = 1, 2 98181- c, d< = 1, 2> 98182- e, f = 5 * 5, "hello" + "world"< = 25, "helloworld"> 98183- g, h< = 25, "helloworld"> 98184- i, j = true, f< = true, "helloworld"> 98185-) 98186- 98187-// No hint 98188-const ( 98189- Int = 3 98190- Float = 3.14 98191- Bool = true 98192- Rune = '3' 98193- Complex = 2.7i 98194- String = "Hello, world!" 98195-) 98196- 98197-var ( 98198- varInt = 3 98199- varFloat = 3.14 98200- varBool = true 98201- varRune = '3' + '4' 98202- varComplex = 2.7i 98203- varString = "Hello, world!" 98204-) 98205- 98206diff -urN a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go 98207--- a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go 2000-01-01 00:00:00.000000000 -0000 98208+++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go 1970-01-01 00:00:00.000000000 +0000 98209@@ -1,50 +0,0 @@ 98210-package inlayHint //@inlayHint("package") 98211- 98212-import "fmt" 98213- 98214-func hello(name string) string { 98215- return "Hello " + name 98216-} 98217- 98218-func helloWorld() string { 98219- return hello("World") 98220-} 98221- 98222-type foo struct{} 98223- 98224-func (*foo) bar(baz string, qux int) int { 98225- if baz != "" { 98226- return qux + 1 98227- } 98228- return qux 98229-} 98230- 98231-func kase(foo int, bar bool, baz ...string) { 98232- fmt.Println(foo, bar, baz) 98233-} 98234- 98235-func kipp(foo string, bar, baz string) { 98236- fmt.Println(foo, bar, baz) 98237-} 98238- 98239-func plex(foo, bar string, baz string) { 98240- fmt.Println(foo, bar, baz) 98241-} 98242- 98243-func tars(foo string, bar, baz string) { 98244- fmt.Println(foo, bar, baz) 98245-} 98246- 98247-func foobar() { 98248- var x foo 98249- x.bar("", 1) 98250- kase(0, true, "c", "d", "e") 98251- kipp("a", "b", "c") 98252- plex("a", "b", "c") 98253- tars("a", "b", "c") 98254- foo, bar, baz := "a", "b", "c" 98255- kipp(foo, bar, baz) 98256- plex("a", bar, baz) 98257- tars(foo+foo, (bar), "c") 98258- 98259-} 98260diff -urN a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden 98261--- a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden 2000-01-01 00:00:00.000000000 -0000 98262+++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden 1970-01-01 00:00:00.000000000 +0000 98263@@ -1,52 +0,0 @@ 98264--- inlayHint -- 98265-package inlayHint //@inlayHint("package") 98266- 98267-import "fmt" 98268- 98269-func hello(name string) string { 98270- return "Hello " + name 98271-} 98272- 98273-func helloWorld() string { 98274- return hello(<name: >"World") 98275-} 98276- 98277-type foo struct{} 98278- 98279-func (*foo) bar(baz string, qux int) int { 98280- if baz != "" { 98281- return qux + 1 98282- } 98283- return qux 98284-} 98285- 98286-func kase(foo int, bar bool, baz ...string) { 98287- fmt.Println(<a...: >foo, bar, baz) 98288-} 98289- 98290-func kipp(foo string, bar, baz string) { 98291- fmt.Println(<a...: >foo, bar, baz) 98292-} 98293- 98294-func plex(foo, bar string, baz string) { 98295- fmt.Println(<a...: >foo, bar, baz) 98296-} 98297- 98298-func tars(foo string, bar, baz string) { 98299- fmt.Println(<a...: >foo, bar, baz) 98300-} 98301- 98302-func foobar() { 98303- var x foo 98304- x.bar(<baz: >"", <qux: >1) 98305- kase(<foo: >0, <bar: >true, <baz...: >"c", "d", "e") 98306- kipp(<foo: >"a", <bar: >"b", <baz: >"c") 98307- plex(<foo: >"a", <bar: >"b", <baz: >"c") 98308- tars(<foo: >"a", <bar: >"b", <baz: >"c") 98309- foo< string>, bar< string>, baz< string> := "a", "b", "c" 98310- kipp(foo, bar, baz) 98311- plex(<foo: >"a", bar, baz) 98312- tars(<foo: >foo+foo, <bar: >(bar), <baz: >"c") 98313- 98314-} 98315- 98316diff -urN a/gopls/internal/lsp/testdata/inlay_hint/type_params.go b/gopls/internal/lsp/testdata/inlay_hint/type_params.go 98317--- a/gopls/internal/lsp/testdata/inlay_hint/type_params.go 2000-01-01 00:00:00.000000000 -0000 98318+++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go 1970-01-01 00:00:00.000000000 +0000 98319@@ -1,45 +0,0 @@ 98320-//go:build go1.18 98321-// +build go1.18 98322- 98323-package inlayHint //@inlayHint("package") 98324- 98325-func main() { 98326- ints := map[string]int64{ 98327- "first": 34, 98328- "second": 12, 98329- } 98330- 98331- floats := map[string]float64{ 98332- "first": 35.98, 98333- "second": 26.99, 98334- } 98335- 98336- SumIntsOrFloats[string, int64](ints) 98337- SumIntsOrFloats[string, float64](floats) 98338- 98339- SumIntsOrFloats(ints) 98340- SumIntsOrFloats(floats) 98341- 98342- SumNumbers(ints) 98343- SumNumbers(floats) 98344-} 98345- 98346-type Number interface { 98347- int64 | float64 98348-} 98349- 98350-func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { 98351- var s V 98352- for _, v := range m { 98353- s += v 98354- } 98355- return s 98356-} 98357- 98358-func SumNumbers[K comparable, V Number](m map[K]V) V { 98359- var s V 98360- for _, v := range m { 98361- s += v 98362- } 98363- return s 98364-} 98365diff -urN a/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden 98366--- a/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden 2000-01-01 00:00:00.000000000 -0000 98367+++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden 1970-01-01 00:00:00.000000000 +0000 98368@@ -1,47 +0,0 @@ 98369--- inlayHint -- 98370-//go:build go1.18 98371-// +build go1.18 98372- 98373-package inlayHint //@inlayHint("package") 98374- 98375-func main() { 98376- ints< map[string]int64> := map[string]int64{ 98377- "first": 34, 98378- "second": 12, 98379- } 98380- 98381- floats< map[string]float64> := map[string]float64{ 98382- "first": 35.98, 98383- "second": 26.99, 98384- } 98385- 98386- SumIntsOrFloats[string, int64](<m: >ints) 98387- SumIntsOrFloats[string, float64](<m: >floats) 98388- 98389- SumIntsOrFloats<[string, int64]>(<m: >ints) 98390- SumIntsOrFloats<[string, float64]>(<m: >floats) 98391- 98392- SumNumbers<[string, int64]>(<m: >ints) 98393- SumNumbers<[string, float64]>(<m: >floats) 98394-} 98395- 98396-type Number interface { 98397- int64 | float64 98398-} 98399- 98400-func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { 98401- var s V 98402- for _< K>, v< V> := range m { 98403- s += v 98404- } 98405- return s 98406-} 98407- 98408-func SumNumbers[K comparable, V Number](m map[K]V) V { 98409- var s V 98410- for _< K>, v< V> := range m { 98411- s += v 98412- } 98413- return s 98414-} 98415- 98416diff -urN a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go 98417--- a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go 2000-01-01 00:00:00.000000000 -0000 98418+++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go 1970-01-01 00:00:00.000000000 +0000 98419@@ -1,20 +0,0 @@ 98420-package inlayHint //@inlayHint("package") 98421- 98422-func assignTypes() { 98423- i, j := 0, len([]string{})-1 98424- println(i, j) 98425-} 98426- 98427-func rangeTypes() { 98428- for k, v := range []string{} { 98429- println(k, v) 98430- } 98431-} 98432- 98433-func funcLitType() { 98434- myFunc := func(a string) string { return "" } 98435-} 98436- 98437-func compositeLitType() { 98438- foo := map[string]interface{}{"": ""} 98439-} 98440diff -urN a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden 98441--- a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden 2000-01-01 00:00:00.000000000 -0000 98442+++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden 1970-01-01 00:00:00.000000000 +0000 98443@@ -1,22 +0,0 @@ 98444--- inlayHint -- 98445-package inlayHint //@inlayHint("package") 98446- 98447-func assignTypes() { 98448- i< int>, j< int> := 0, len([]string{})-1 98449- println(i, j) 98450-} 98451- 98452-func rangeTypes() { 98453- for k< int>, v< string> := range []string{} { 98454- println(k, v) 98455- } 98456-} 98457- 98458-func funcLitType() { 98459- myFunc< func(a string) string> := func(a string) string { return "" } 98460-} 98461- 98462-func compositeLitType() { 98463- foo< map[string]interface{}> := map[string]interface{}{"": ""} 98464-} 98465- 98466diff -urN a/gopls/internal/lsp/testdata/interfacerank/interface_rank.go b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go 98467--- a/gopls/internal/lsp/testdata/interfacerank/interface_rank.go 2000-01-01 00:00:00.000000000 -0000 98468+++ b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go 1970-01-01 00:00:00.000000000 +0000 98469@@ -1,23 +0,0 @@ 98470-package interfacerank 98471- 98472-type foo interface { 98473- foo() 98474-} 98475- 98476-type fooImpl int 98477- 98478-func (*fooImpl) foo() {} 98479- 98480-func wantsFoo(foo) {} 98481- 98482-func _() { 98483- var ( 98484- aa string //@item(irAA, "aa", "string", "var") 98485- ab *fooImpl //@item(irAB, "ab", "*fooImpl", "var") 98486- ) 98487- 98488- wantsFoo(a) //@complete(")", irAB, irAA) 98489- 98490- var ac fooImpl //@item(irAC, "ac", "fooImpl", "var") 98491- wantsFoo(&a) //@complete(")", irAC, irAA, irAB) 98492-} 98493diff -urN a/gopls/internal/lsp/testdata/issues/issue56505.go b/gopls/internal/lsp/testdata/issues/issue56505.go 98494--- a/gopls/internal/lsp/testdata/issues/issue56505.go 2000-01-01 00:00:00.000000000 -0000 98495+++ b/gopls/internal/lsp/testdata/issues/issue56505.go 1970-01-01 00:00:00.000000000 +0000 98496@@ -1,8 +0,0 @@ 98497-package issues 98498- 98499-// Test for golang/go#56505: completion on variables of type *error should not 98500-// panic. 98501-func _() { 98502- var e *error 98503- e.x //@complete(" //") 98504-} 98505diff -urN a/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in 98506--- a/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in 2000-01-01 00:00:00.000000000 -0000 98507+++ b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in 1970-01-01 00:00:00.000000000 +0000 98508@@ -1,31 +0,0 @@ 98509-package keywords 98510- 98511-// non-matching candidate - shouldn't show up as completion 98512-var apple = "apple" 98513- 98514-func _() { 98515- foo.bar() // insert some extra statements to exercise our AST surgery 98516- variance := 123 //@item(kwVariance, "variance", "int", "var") 98517- foo.bar() 98518- println(var) //@complete(")", kwVariance) 98519-} 98520- 98521-func _() { 98522- foo.bar() 98523- var s struct { variance int } //@item(kwVarianceField, "variance", "int", "field") 98524- foo.bar() 98525- s.var //@complete(" //", kwVarianceField) 98526-} 98527- 98528-func _() { 98529- channel := 123 //@item(kwChannel, "channel", "int", "var") 98530- chan //@complete(" //", kwChannel) 98531- foo.bar() 98532-} 98533- 98534-func _() { 98535- foo.bar() 98536- var typeName string //@item(kwTypeName, "typeName", "string", "var") 98537- foo.bar() 98538- type //@complete(" //", kwTypeName) 98539-} 98540diff -urN a/gopls/internal/lsp/testdata/keywords/empty_select.go b/gopls/internal/lsp/testdata/keywords/empty_select.go 98541--- a/gopls/internal/lsp/testdata/keywords/empty_select.go 2000-01-01 00:00:00.000000000 -0000 98542+++ b/gopls/internal/lsp/testdata/keywords/empty_select.go 1970-01-01 00:00:00.000000000 +0000 98543@@ -1,7 +0,0 @@ 98544-package keywords 98545- 98546-func _() { 98547- select { 98548- c //@complete(" //", case) 98549- } 98550-} 98551diff -urN a/gopls/internal/lsp/testdata/keywords/empty_switch.go b/gopls/internal/lsp/testdata/keywords/empty_switch.go 98552--- a/gopls/internal/lsp/testdata/keywords/empty_switch.go 2000-01-01 00:00:00.000000000 -0000 98553+++ b/gopls/internal/lsp/testdata/keywords/empty_switch.go 1970-01-01 00:00:00.000000000 +0000 98554@@ -1,11 +0,0 @@ 98555-package keywords 98556- 98557-func _() { 98558- switch { 98559- //@complete("", case, default) 98560- } 98561- 98562- switch test.(type) { 98563- d //@complete(" //", default) 98564- } 98565-} 98566diff -urN a/gopls/internal/lsp/testdata/keywords/keywords.go b/gopls/internal/lsp/testdata/keywords/keywords.go 98567--- a/gopls/internal/lsp/testdata/keywords/keywords.go 2000-01-01 00:00:00.000000000 -0000 98568+++ b/gopls/internal/lsp/testdata/keywords/keywords.go 1970-01-01 00:00:00.000000000 +0000 98569@@ -1,100 +0,0 @@ 98570-package keywords 98571- 98572-//@rank("", type),rank("", func),rank("", var),rank("", const),rank("", import) 98573- 98574-func _() { 98575- var test int //@rank(" //", int, interface) 98576- var tChan chan int 98577- var _ m //@complete(" //", map) 98578- var _ f //@complete(" //", func) 98579- var _ c //@complete(" //", chan) 98580- 98581- var _ str //@rank(" //", string, struct) 98582- 98583- type _ int //@rank(" //", interface, int) 98584- 98585- type _ str //@rank(" //", struct, string) 98586- 98587- switch test { 98588- case 1: // TODO: trying to complete case here will break because the parser won't return *ast.Ident 98589- b //@complete(" //", break) 98590- case 2: 98591- f //@complete(" //", fallthrough, for) 98592- r //@complete(" //", return) 98593- d //@complete(" //", default, defer) 98594- c //@complete(" //", case, const) 98595- } 98596- 98597- switch test.(type) { 98598- case fo: //@complete(":") 98599- case int: 98600- b //@complete(" //", break) 98601- case int32: 98602- f //@complete(" //", for) 98603- d //@complete(" //", default, defer) 98604- r //@complete(" //", return) 98605- c //@complete(" //", case, const) 98606- } 98607- 98608- select { 98609- case <-tChan: 98610- b //@complete(" //", break) 98611- c //@complete(" //", case, const) 98612- } 98613- 98614- for index := 0; index < test; index++ { 98615- c //@complete(" //", const, continue) 98616- b //@complete(" //", break) 98617- } 98618- 98619- for range []int{} { 98620- c //@complete(" //", const, continue) 98621- b //@complete(" //", break) 98622- } 98623- 98624- // Test function level keywords 98625- 98626- //Using 2 characters to test because map output order is random 98627- sw //@complete(" //", switch) 98628- se //@complete(" //", select) 98629- 98630- f //@complete(" //", for) 98631- d //@complete(" //", defer) 98632- g //@rank(" //", go),rank(" //", goto) 98633- r //@complete(" //", return) 98634- i //@complete(" //", if) 98635- e //@complete(" //", else) 98636- v //@complete(" //", var) 98637- c //@complete(" //", const) 98638- 98639- for i := r //@complete(" //", range) 98640-} 98641- 98642-/* package */ //@item(package, "package", "", "keyword") 98643-/* import */ //@item(import, "import", "", "keyword") 98644-/* func */ //@item(func, "func", "", "keyword") 98645-/* type */ //@item(type, "type", "", "keyword") 98646-/* var */ //@item(var, "var", "", "keyword") 98647-/* const */ //@item(const, "const", "", "keyword") 98648-/* break */ //@item(break, "break", "", "keyword") 98649-/* default */ //@item(default, "default", "", "keyword") 98650-/* case */ //@item(case, "case", "", "keyword") 98651-/* defer */ //@item(defer, "defer", "", "keyword") 98652-/* go */ //@item(go, "go", "", "keyword") 98653-/* for */ //@item(for, "for", "", "keyword") 98654-/* if */ //@item(if, "if", "", "keyword") 98655-/* else */ //@item(else, "else", "", "keyword") 98656-/* switch */ //@item(switch, "switch", "", "keyword") 98657-/* select */ //@item(select, "select", "", "keyword") 98658-/* fallthrough */ //@item(fallthrough, "fallthrough", "", "keyword") 98659-/* continue */ //@item(continue, "continue", "", "keyword") 98660-/* return */ //@item(return, "return", "", "keyword") 98661-/* var */ //@item(var, "var", "", "keyword") 98662-/* const */ //@item(const, "const", "", "keyword") 98663-/* goto */ //@item(goto, "goto", "", "keyword") 98664-/* struct */ //@item(struct, "struct", "", "keyword") 98665-/* interface */ //@item(interface, "interface", "", "keyword") 98666-/* map */ //@item(map, "map", "", "keyword") 98667-/* func */ //@item(func, "func", "", "keyword") 98668-/* chan */ //@item(chan, "chan", "", "keyword") 98669-/* range */ //@item(range, "range", "", "keyword") 98670diff -urN a/gopls/internal/lsp/testdata/labels/labels.go b/gopls/internal/lsp/testdata/labels/labels.go 98671--- a/gopls/internal/lsp/testdata/labels/labels.go 2000-01-01 00:00:00.000000000 -0000 98672+++ b/gopls/internal/lsp/testdata/labels/labels.go 1970-01-01 00:00:00.000000000 +0000 98673@@ -1,49 +0,0 @@ 98674-package labels 98675- 98676-func _() { 98677- goto F //@complete(" //", label1, label5) 98678- 98679-Foo1: //@item(label1, "Foo1", "label", "const") 98680- for a, b := range []int{} { 98681- Foo2: //@item(label2, "Foo2", "label", "const") 98682- switch { 98683- case true: 98684- break F //@complete(" //", label2, label1) 98685- 98686- continue F //@complete(" //", label1) 98687- 98688- { 98689- FooUnjumpable: 98690- } 98691- 98692- goto F //@complete(" //", label1, label2, label4, label5) 98693- 98694- func() { 98695- goto F //@complete(" //", label3) 98696- 98697- break F //@complete(" //") 98698- 98699- continue F //@complete(" //") 98700- 98701- Foo3: //@item(label3, "Foo3", "label", "const") 98702- }() 98703- } 98704- 98705- Foo4: //@item(label4, "Foo4", "label", "const") 98706- switch interface{}(a).(type) { 98707- case int: 98708- break F //@complete(" //", label4, label1) 98709- } 98710- } 98711- 98712- break F //@complete(" //") 98713- 98714- continue F //@complete(" //") 98715- 98716-Foo5: //@item(label5, "Foo5", "label", "const") 98717- for { 98718- break F //@complete(" //", label5) 98719- } 98720- 98721- return 98722-} 98723diff -urN a/gopls/internal/lsp/testdata/links/links.go b/gopls/internal/lsp/testdata/links/links.go 98724--- a/gopls/internal/lsp/testdata/links/links.go 2000-01-01 00:00:00.000000000 -0000 98725+++ b/gopls/internal/lsp/testdata/links/links.go 1970-01-01 00:00:00.000000000 +0000 98726@@ -1,26 +0,0 @@ 98727-package links 98728- 98729-import ( 98730- "fmt" //@link(`fmt`,"https://pkg.go.dev/fmt") 98731- 98732- "golang.org/lsptests/foo" //@link(`golang.org/lsptests/foo`,`https://pkg.go.dev/golang.org/lsptests/foo`) 98733- 98734- _ "database/sql" //@link(`database/sql`, `https://pkg.go.dev/database/sql`) 98735-) 98736- 98737-var ( 98738- _ fmt.Formatter 98739- _ foo.StructFoo 98740- _ errors.Formatter 98741-) 98742- 98743-// Foo function 98744-func Foo() string { 98745- /*https://example.com/comment */ //@link("https://example.com/comment","https://example.com/comment") 98746- 98747- url := "https://example.com/string_literal" //@link("https://example.com/string_literal","https://example.com/string_literal") 98748- return url 98749- 98750- // TODO(golang/go#1234): Link the relevant issue. //@link("golang/go#1234", "https://github.com/golang/go/issues/1234") 98751- // TODO(microsoft/vscode-go#12): Another issue. //@link("microsoft/vscode-go#12", "https://github.com/microsoft/vscode-go/issues/12") 98752-} 98753diff -urN a/gopls/internal/lsp/testdata/maps/maps.go.in b/gopls/internal/lsp/testdata/maps/maps.go.in 98754--- a/gopls/internal/lsp/testdata/maps/maps.go.in 2000-01-01 00:00:00.000000000 -0000 98755+++ b/gopls/internal/lsp/testdata/maps/maps.go.in 1970-01-01 00:00:00.000000000 +0000 98756@@ -1,18 +0,0 @@ 98757-package maps 98758- 98759-func _() { 98760- var aVar int //@item(mapVar, "aVar", "int", "var") 98761- 98762- // not comparabale 98763- type aSlice []int //@item(mapSliceType, "aSlice", "[]int", "type") 98764- 98765- *aSlice //@item(mapSliceTypePtr, "*aSlice", "[]int", "type") 98766- 98767- // comparable 98768- type aStruct struct{} //@item(mapStructType, "aStruct", "struct{...}", "struct") 98769- 98770- map[]a{} //@complete("]", mapSliceType, mapStructType),snippet("]", mapSliceType, "*aSlice", "*aSlice") 98771- 98772- map[a]a{} //@complete("]", mapSliceType, mapStructType) 98773- map[a]a{} //@complete("{", mapSliceType, mapStructType) 98774-} 98775diff -urN a/gopls/internal/lsp/testdata/missingfunction/channels.go b/gopls/internal/lsp/testdata/missingfunction/channels.go 98776--- a/gopls/internal/lsp/testdata/missingfunction/channels.go 2000-01-01 00:00:00.000000000 -0000 98777+++ b/gopls/internal/lsp/testdata/missingfunction/channels.go 1970-01-01 00:00:00.000000000 +0000 98778@@ -1,9 +0,0 @@ 98779-package missingfunction 98780- 98781-func channels(s string) { 98782- undefinedChannels(c()) //@suggestedfix("undefinedChannels", "quickfix", "") 98783-} 98784- 98785-func c() (<-chan string, chan string) { 98786- return make(<-chan string), make(chan string) 98787-} 98788diff -urN a/gopls/internal/lsp/testdata/missingfunction/channels.go.golden b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden 98789--- a/gopls/internal/lsp/testdata/missingfunction/channels.go.golden 2000-01-01 00:00:00.000000000 -0000 98790+++ b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden 1970-01-01 00:00:00.000000000 +0000 98791@@ -1,15 +0,0 @@ 98792--- suggestedfix_channels_4_2 -- 98793-package missingfunction 98794- 98795-func channels(s string) { 98796- undefinedChannels(c()) //@suggestedfix("undefinedChannels", "quickfix", "") 98797-} 98798- 98799-func undefinedChannels(ch1 <-chan string, ch2 chan string) { 98800- panic("unimplemented") 98801-} 98802- 98803-func c() (<-chan string, chan string) { 98804- return make(<-chan string), make(chan string) 98805-} 98806- 98807diff -urN a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go 98808--- a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go 2000-01-01 00:00:00.000000000 -0000 98809+++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go 1970-01-01 00:00:00.000000000 +0000 98810@@ -1,6 +0,0 @@ 98811-package missingfunction 98812- 98813-func consecutiveParams() { 98814- var s string 98815- undefinedConsecutiveParams(s, s) //@suggestedfix("undefinedConsecutiveParams", "quickfix", "") 98816-} 98817diff -urN a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden 98818--- a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden 2000-01-01 00:00:00.000000000 -0000 98819+++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden 1970-01-01 00:00:00.000000000 +0000 98820@@ -1,12 +0,0 @@ 98821--- suggestedfix_consecutive_params_5_2 -- 98822-package missingfunction 98823- 98824-func consecutiveParams() { 98825- var s string 98826- undefinedConsecutiveParams(s, s) //@suggestedfix("undefinedConsecutiveParams", "quickfix", "") 98827-} 98828- 98829-func undefinedConsecutiveParams(s1, s2 string) { 98830- panic("unimplemented") 98831-} 98832- 98833diff -urN a/gopls/internal/lsp/testdata/missingfunction/error_param.go b/gopls/internal/lsp/testdata/missingfunction/error_param.go 98834--- a/gopls/internal/lsp/testdata/missingfunction/error_param.go 2000-01-01 00:00:00.000000000 -0000 98835+++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go 1970-01-01 00:00:00.000000000 +0000 98836@@ -1,6 +0,0 @@ 98837-package missingfunction 98838- 98839-func errorParam() { 98840- var err error 98841- undefinedErrorParam(err) //@suggestedfix("undefinedErrorParam", "quickfix", "") 98842-} 98843diff -urN a/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden 98844--- a/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden 2000-01-01 00:00:00.000000000 -0000 98845+++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden 1970-01-01 00:00:00.000000000 +0000 98846@@ -1,12 +0,0 @@ 98847--- suggestedfix_error_param_5_2 -- 98848-package missingfunction 98849- 98850-func errorParam() { 98851- var err error 98852- undefinedErrorParam(err) //@suggestedfix("undefinedErrorParam", "quickfix", "") 98853-} 98854- 98855-func undefinedErrorParam(err error) { 98856- panic("unimplemented") 98857-} 98858- 98859diff -urN a/gopls/internal/lsp/testdata/missingfunction/literals.go b/gopls/internal/lsp/testdata/missingfunction/literals.go 98860--- a/gopls/internal/lsp/testdata/missingfunction/literals.go 2000-01-01 00:00:00.000000000 -0000 98861+++ b/gopls/internal/lsp/testdata/missingfunction/literals.go 1970-01-01 00:00:00.000000000 +0000 98862@@ -1,7 +0,0 @@ 98863-package missingfunction 98864- 98865-type T struct{} 98866- 98867-func literals() { 98868- undefinedLiterals("hey compiler", T{}, &T{}) //@suggestedfix("undefinedLiterals", "quickfix", "") 98869-} 98870diff -urN a/gopls/internal/lsp/testdata/missingfunction/literals.go.golden b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden 98871--- a/gopls/internal/lsp/testdata/missingfunction/literals.go.golden 2000-01-01 00:00:00.000000000 -0000 98872+++ b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden 1970-01-01 00:00:00.000000000 +0000 98873@@ -1,13 +0,0 @@ 98874--- suggestedfix_literals_6_2 -- 98875-package missingfunction 98876- 98877-type T struct{} 98878- 98879-func literals() { 98880- undefinedLiterals("hey compiler", T{}, &T{}) //@suggestedfix("undefinedLiterals", "quickfix", "") 98881-} 98882- 98883-func undefinedLiterals(s string, t1 T, t2 *T) { 98884- panic("unimplemented") 98885-} 98886- 98887diff -urN a/gopls/internal/lsp/testdata/missingfunction/operation.go b/gopls/internal/lsp/testdata/missingfunction/operation.go 98888--- a/gopls/internal/lsp/testdata/missingfunction/operation.go 2000-01-01 00:00:00.000000000 -0000 98889+++ b/gopls/internal/lsp/testdata/missingfunction/operation.go 1970-01-01 00:00:00.000000000 +0000 98890@@ -1,7 +0,0 @@ 98891-package missingfunction 98892- 98893-import "time" 98894- 98895-func operation() { 98896- undefinedOperation(10 * time.Second) //@suggestedfix("undefinedOperation", "quickfix", "") 98897-} 98898diff -urN a/gopls/internal/lsp/testdata/missingfunction/operation.go.golden b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden 98899--- a/gopls/internal/lsp/testdata/missingfunction/operation.go.golden 2000-01-01 00:00:00.000000000 -0000 98900+++ b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden 1970-01-01 00:00:00.000000000 +0000 98901@@ -1,13 +0,0 @@ 98902--- suggestedfix_operation_6_2 -- 98903-package missingfunction 98904- 98905-import "time" 98906- 98907-func operation() { 98908- undefinedOperation(10 * time.Second) //@suggestedfix("undefinedOperation", "quickfix", "") 98909-} 98910- 98911-func undefinedOperation(duration time.Duration) { 98912- panic("unimplemented") 98913-} 98914- 98915diff -urN a/gopls/internal/lsp/testdata/missingfunction/selector.go b/gopls/internal/lsp/testdata/missingfunction/selector.go 98916--- a/gopls/internal/lsp/testdata/missingfunction/selector.go 2000-01-01 00:00:00.000000000 -0000 98917+++ b/gopls/internal/lsp/testdata/missingfunction/selector.go 1970-01-01 00:00:00.000000000 +0000 98918@@ -1,6 +0,0 @@ 98919-package missingfunction 98920- 98921-func selector() { 98922- m := map[int]bool{} 98923- undefinedSelector(m[1]) //@suggestedfix("undefinedSelector", "quickfix", "") 98924-} 98925diff -urN a/gopls/internal/lsp/testdata/missingfunction/selector.go.golden b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden 98926--- a/gopls/internal/lsp/testdata/missingfunction/selector.go.golden 2000-01-01 00:00:00.000000000 -0000 98927+++ b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden 1970-01-01 00:00:00.000000000 +0000 98928@@ -1,12 +0,0 @@ 98929--- suggestedfix_selector_5_2 -- 98930-package missingfunction 98931- 98932-func selector() { 98933- m := map[int]bool{} 98934- undefinedSelector(m[1]) //@suggestedfix("undefinedSelector", "quickfix", "") 98935-} 98936- 98937-func undefinedSelector(b bool) { 98938- panic("unimplemented") 98939-} 98940- 98941diff -urN a/gopls/internal/lsp/testdata/missingfunction/slice.go b/gopls/internal/lsp/testdata/missingfunction/slice.go 98942--- a/gopls/internal/lsp/testdata/missingfunction/slice.go 2000-01-01 00:00:00.000000000 -0000 98943+++ b/gopls/internal/lsp/testdata/missingfunction/slice.go 1970-01-01 00:00:00.000000000 +0000 98944@@ -1,5 +0,0 @@ 98945-package missingfunction 98946- 98947-func slice() { 98948- undefinedSlice([]int{1, 2}) //@suggestedfix("undefinedSlice", "quickfix", "") 98949-} 98950diff -urN a/gopls/internal/lsp/testdata/missingfunction/slice.go.golden b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden 98951--- a/gopls/internal/lsp/testdata/missingfunction/slice.go.golden 2000-01-01 00:00:00.000000000 -0000 98952+++ b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden 1970-01-01 00:00:00.000000000 +0000 98953@@ -1,11 +0,0 @@ 98954--- suggestedfix_slice_4_2 -- 98955-package missingfunction 98956- 98957-func slice() { 98958- undefinedSlice([]int{1, 2}) //@suggestedfix("undefinedSlice", "quickfix", "") 98959-} 98960- 98961-func undefinedSlice(i []int) { 98962- panic("unimplemented") 98963-} 98964- 98965diff -urN a/gopls/internal/lsp/testdata/missingfunction/tuple.go b/gopls/internal/lsp/testdata/missingfunction/tuple.go 98966--- a/gopls/internal/lsp/testdata/missingfunction/tuple.go 2000-01-01 00:00:00.000000000 -0000 98967+++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go 1970-01-01 00:00:00.000000000 +0000 98968@@ -1,9 +0,0 @@ 98969-package missingfunction 98970- 98971-func tuple() { 98972- undefinedTuple(b()) //@suggestedfix("undefinedTuple", "quickfix", "") 98973-} 98974- 98975-func b() (string, error) { 98976- return "", nil 98977-} 98978diff -urN a/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden 98979--- a/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden 2000-01-01 00:00:00.000000000 -0000 98980+++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden 1970-01-01 00:00:00.000000000 +0000 98981@@ -1,15 +0,0 @@ 98982--- suggestedfix_tuple_4_2 -- 98983-package missingfunction 98984- 98985-func tuple() { 98986- undefinedTuple(b()) //@suggestedfix("undefinedTuple", "quickfix", "") 98987-} 98988- 98989-func undefinedTuple(s string, err error) { 98990- panic("unimplemented") 98991-} 98992- 98993-func b() (string, error) { 98994- return "", nil 98995-} 98996- 98997diff -urN a/gopls/internal/lsp/testdata/missingfunction/unique_params.go b/gopls/internal/lsp/testdata/missingfunction/unique_params.go 98998--- a/gopls/internal/lsp/testdata/missingfunction/unique_params.go 2000-01-01 00:00:00.000000000 -0000 98999+++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go 1970-01-01 00:00:00.000000000 +0000 99000@@ -1,7 +0,0 @@ 99001-package missingfunction 99002- 99003-func uniqueArguments() { 99004- var s string 99005- var i int 99006- undefinedUniqueArguments(s, i, s) //@suggestedfix("undefinedUniqueArguments", "quickfix", "") 99007-} 99008diff -urN a/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden 99009--- a/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden 2000-01-01 00:00:00.000000000 -0000 99010+++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden 1970-01-01 00:00:00.000000000 +0000 99011@@ -1,13 +0,0 @@ 99012--- suggestedfix_unique_params_6_2 -- 99013-package missingfunction 99014- 99015-func uniqueArguments() { 99016- var s string 99017- var i int 99018- undefinedUniqueArguments(s, i, s) //@suggestedfix("undefinedUniqueArguments", "quickfix", "") 99019-} 99020- 99021-func undefinedUniqueArguments(s1 string, i int, s2 string) { 99022- panic("unimplemented") 99023-} 99024- 99025diff -urN a/gopls/internal/lsp/testdata/multireturn/multi_return.go.in b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in 99026--- a/gopls/internal/lsp/testdata/multireturn/multi_return.go.in 2000-01-01 00:00:00.000000000 -0000 99027+++ b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in 1970-01-01 00:00:00.000000000 +0000 99028@@ -1,48 +0,0 @@ 99029-package multireturn 99030- 99031-func f0() {} //@item(multiF0, "f0", "func()", "func") 99032- 99033-func f1(int) int { return 0 } //@item(multiF1, "f1", "func(int) int", "func") 99034- 99035-func f2(int, int) (int, int) { return 0, 0 } //@item(multiF2, "f2", "func(int, int) (int, int)", "func") 99036- 99037-func f2Str(string, string) (string, string) { return "", "" } //@item(multiF2Str, "f2Str", "func(string, string) (string, string)", "func") 99038- 99039-func f3(int, int, int) (int, int, int) { return 0, 0, 0 } //@item(multiF3, "f3", "func(int, int, int) (int, int, int)", "func") 99040- 99041-func _() { 99042- _ := f //@rank(" //", multiF1, multiF2) 99043- 99044- _, _ := f //@rank(" //", multiF2, multiF0),rank(" //", multiF1, multiF0) 99045- 99046- _, _ := _, f //@rank(" //", multiF1, multiF2),rank(" //", multiF1, multiF0) 99047- 99048- _, _ := f, abc //@rank(", abc", multiF1, multiF2) 99049- 99050- f1() //@rank(")", multiF1, multiF0) 99051- f1(f) //@rank(")", multiF1, multiF2) 99052- f2(f) //@rank(")", multiF2, multiF3),rank(")", multiF1, multiF3) 99053- f2(1, f) //@rank(")", multiF1, multiF2),rank(")", multiF1, multiF0) 99054- f2(1, ) //@rank(")", multiF1, multiF2),rank(")", multiF1, multiF0) 99055- f2Str() //@rank(")", multiF2Str, multiF2) 99056- 99057- var i int 99058- i, _ := f //@rank(" //", multiF2, multiF2Str) 99059- 99060- var s string 99061- _, s := f //@rank(" //", multiF2Str, multiF2) 99062- 99063- banana, s = f //@rank(" //", multiF2, multiF3) 99064- 99065- var variadic func(int, ...int) 99066- variadic() //@rank(")", multiF1, multiF0),rank(")", multiF2, multiF0),rank(")", multiF3, multiF0) 99067-} 99068- 99069-func _() { 99070- var baz func(...interface{}) 99071- 99072- var otterNap func() (int, int) //@item(multiTwo, "otterNap", "func() (int, int)", "var") 99073- var one int //@item(multiOne, "one", "int", "var") 99074- 99075- baz(on) //@rank(")", multiOne, multiTwo) 99076-} 99077diff -urN a/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in 99078--- a/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in 2000-01-01 00:00:00.000000000 -0000 99079+++ b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in 1970-01-01 00:00:00.000000000 +0000 99080@@ -1,15 +0,0 @@ 99081-package nested_complit 99082- 99083-type ncFoo struct {} //@item(structNCFoo, "ncFoo", "struct{...}", "struct") 99084- 99085-type ncBar struct { //@item(structNCBar, "ncBar", "struct{...}", "struct") 99086- baz []ncFoo 99087-} 99088- 99089-func _() { 99090- []ncFoo{} //@item(litNCFoo, "[]ncFoo{}", "", "var") 99091- _ := ncBar{ 99092- // disabled - see issue #54822 99093- baz: [] // complete(" //", structNCFoo, structNCBar) 99094- } 99095-} 99096diff -urN a/gopls/internal/lsp/testdata/nodisk/empty b/gopls/internal/lsp/testdata/nodisk/empty 99097--- a/gopls/internal/lsp/testdata/nodisk/empty 2000-01-01 00:00:00.000000000 -0000 99098+++ b/gopls/internal/lsp/testdata/nodisk/empty 1970-01-01 00:00:00.000000000 +0000 99099@@ -1 +0,0 @@ 99100-an empty file so that this directory exists 99101\ No newline at end of file 99102diff -urN a/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go 99103--- a/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go 2000-01-01 00:00:00.000000000 -0000 99104+++ b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go 1970-01-01 00:00:00.000000000 +0000 99105@@ -1,9 +0,0 @@ 99106-package nodisk 99107- 99108-import ( 99109- "golang.org/lsptests/foo" 99110-) 99111- 99112-func _() { 99113- foo.Foo() //@complete("F", Foo, IntFoo, StructFoo) 99114-} 99115diff -urN a/gopls/internal/lsp/testdata/noparse/noparse.go.in b/gopls/internal/lsp/testdata/noparse/noparse.go.in 99116--- a/gopls/internal/lsp/testdata/noparse/noparse.go.in 2000-01-01 00:00:00.000000000 -0000 99117+++ b/gopls/internal/lsp/testdata/noparse/noparse.go.in 1970-01-01 00:00:00.000000000 +0000 99118@@ -1,24 +0,0 @@ 99119-package noparse 99120- 99121-// The type error was chosen carefully to exercise a type-error analyzer. 99122-// We use the 'nonewvars' analyzer because the other candidates are tricky: 99123-// 99124-// - The 'unusedvariable' analyzer is disabled by default, so it is not 99125-// consistently enabled across Test{LSP,CommandLine} tests, which 99126-// both process this file. 99127-// - The 'undeclaredname' analyzer depends on the text of the go/types 99128-// "undeclared name" error, which changed in go1.20. 99129-// - The 'noresultvalues' analyzer produces a diagnostic containing newlines, 99130-// which breaks the parser used by TestCommandLine. 99131-// 99132-// This comment is all that remains of my afternoon. 99133- 99134-func bye(x int) { 99135- x := 123 //@diag(":=", "nonewvars", "no new variables", "warning") 99136-} 99137- 99138-func stuff() { 99139- 99140-} 99141- 99142-func .() {} //@diag(".", "syntax", "expected 'IDENT', found '.'", "error") 99143diff -urN a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden 99144--- a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden 2000-01-01 00:00:00.000000000 -0000 99145+++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden 1970-01-01 00:00:00.000000000 +0000 99146@@ -1,2 +0,0 @@ 99147--- gofmt -- 99148- 99149diff -urN a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in 99150--- a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in 2000-01-01 00:00:00.000000000 -0000 99151+++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in 1970-01-01 00:00:00.000000000 +0000 99152@@ -1,14 +0,0 @@ 99153-// +build go1.11 99154- 99155-package noparse_format //@format("package") 99156- 99157-// The nonewvars expectation asserts that the go/analysis framework ran. 99158-// See comments in badstmt. 99159- 99160-func what() { 99161- var hi func() 99162- if { hi() //@diag("{", "syntax", "missing condition in if statement", "error") 99163- } 99164- hi := nil //@diag(":=", "nonewvars", "no new variables", "warning") 99165-} 99166- 99167diff -urN a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden 99168--- a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden 2000-01-01 00:00:00.000000000 -0000 99169+++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden 1970-01-01 00:00:00.000000000 +0000 99170@@ -1,7 +0,0 @@ 99171--- gofmt -- 99172-package noparse_format //@format("package") 99173- 99174-func _() { 99175- f() 99176-} 99177- 99178diff -urN a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in 99179--- a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in 2000-01-01 00:00:00.000000000 -0000 99180+++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in 1970-01-01 00:00:00.000000000 +0000 99181@@ -1,5 +0,0 @@ 99182-package noparse_format //@format("package") 99183- 99184-func _() { 99185-f() 99186-} 99187\ No newline at end of file 99188diff -urN a/gopls/internal/lsp/testdata/%percent/perc%ent.go b/gopls/internal/lsp/testdata/%percent/perc%ent.go 99189--- a/gopls/internal/lsp/testdata/%percent/perc%ent.go 2000-01-01 00:00:00.000000000 -0000 99190+++ b/gopls/internal/lsp/testdata/%percent/perc%ent.go 1970-01-01 00:00:00.000000000 +0000 99191@@ -1 +0,0 @@ 99192-package percent 99193diff -urN a/gopls/internal/lsp/testdata/printf/printf.go b/gopls/internal/lsp/testdata/printf/printf.go 99194--- a/gopls/internal/lsp/testdata/printf/printf.go 2000-01-01 00:00:00.000000000 -0000 99195+++ b/gopls/internal/lsp/testdata/printf/printf.go 1970-01-01 00:00:00.000000000 +0000 99196@@ -1,33 +0,0 @@ 99197-package printf 99198- 99199-import "fmt" 99200- 99201-func myPrintf(string, ...interface{}) {} 99202- 99203-func _() { 99204- var ( 99205- aInt int //@item(printfInt, "aInt", "int", "var") 99206- aFloat float64 //@item(printfFloat, "aFloat", "float64", "var") 99207- aString string //@item(printfString, "aString", "string", "var") 99208- aBytes []byte //@item(printfBytes, "aBytes", "[]byte", "var") 99209- aStringer fmt.Stringer //@item(printfStringer, "aStringer", "fmt.Stringer", "var") 99210- aError error //@item(printfError, "aError", "error", "var") 99211- aBool bool //@item(printfBool, "aBool", "bool", "var") 99212- ) 99213- 99214- myPrintf("%d", a) //@rank(")", printfInt, printfFloat) 99215- myPrintf("%s", a) //@rank(")", printfString, printfInt),rank(")", printfBytes, printfInt),rank(")", printfStringer, printfInt),rank(")", printfError, printfInt) 99216- myPrintf("%w", a) //@rank(")", printfError, printfInt) 99217- myPrintf("%x %[1]b", a) //@rank(")", printfInt, printfString) 99218- 99219- fmt.Printf("%t", a) //@rank(")", printfBool, printfInt) 99220- 99221- fmt.Fprintf(nil, "%f", a) //@rank(")", printfFloat, printfInt) 99222- 99223- fmt.Sprintf("%[2]q %[1]*.[3]*[4]f", 99224- a, //@rank(",", printfInt, printfFloat) 99225- a, //@rank(",", printfString, printfFloat) 99226- a, //@rank(",", printfInt, printfFloat) 99227- a, //@rank(",", printfFloat, printfInt) 99228- ) 99229-} 99230diff -urN a/gopls/internal/lsp/testdata/rank/assign_rank.go.in b/gopls/internal/lsp/testdata/rank/assign_rank.go.in 99231--- a/gopls/internal/lsp/testdata/rank/assign_rank.go.in 2000-01-01 00:00:00.000000000 -0000 99232+++ b/gopls/internal/lsp/testdata/rank/assign_rank.go.in 1970-01-01 00:00:00.000000000 +0000 99233@@ -1,19 +0,0 @@ 99234-package rank 99235- 99236-var ( 99237- apple int = 3 //@item(apple, "apple", "int", "var") 99238- pear string = "hello" //@item(pear, "pear", "string", "var") 99239-) 99240- 99241-func _() { 99242- orange := 1 //@item(orange, "orange", "int", "var") 99243- grape := "hello" //@item(grape, "grape", "string", "var") 99244- orange, grape = 2, "hello" //@complete(" \"", grape, pear, orange, apple) 99245-} 99246- 99247-func _() { 99248- var pineapple int //@item(pineapple, "pineapple", "int", "var") 99249- pineapple = 1 //@complete(" 1", pineapple, apple, pear) 99250- 99251- y := //@complete(" /", pineapple, apple, pear) 99252-} 99253diff -urN a/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in 99254--- a/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in 2000-01-01 00:00:00.000000000 -0000 99255+++ b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in 1970-01-01 00:00:00.000000000 +0000 99256@@ -1,8 +0,0 @@ 99257-package rank 99258- 99259-func _() { 99260- _ = 5 + ; //@complete(" ;", apple, pear) 99261- y := + 5; //@complete(" +", apple, pear) 99262- 99263- if 6 == {} //@complete(" {", apple, pear) 99264-} 99265diff -urN a/gopls/internal/lsp/testdata/rank/boolexpr_rank.go b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go 99266--- a/gopls/internal/lsp/testdata/rank/boolexpr_rank.go 2000-01-01 00:00:00.000000000 -0000 99267+++ b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go 1970-01-01 00:00:00.000000000 +0000 99268@@ -1,11 +0,0 @@ 99269-package rank 99270- 99271-func _() { 99272- someRandomBoolFunc := func() bool { //@item(boolExprFunc, "someRandomBoolFunc", "func() bool", "var") 99273- return true 99274- } 99275- 99276- var foo, bar int //@item(boolExprBar, "bar", "int", "var") 99277- if foo == 123 && b { //@rank(" {", boolExprBar, boolExprFunc) 99278- } 99279-} 99280diff -urN a/gopls/internal/lsp/testdata/rank/convert_rank.go.in b/gopls/internal/lsp/testdata/rank/convert_rank.go.in 99281--- a/gopls/internal/lsp/testdata/rank/convert_rank.go.in 2000-01-01 00:00:00.000000000 -0000 99282+++ b/gopls/internal/lsp/testdata/rank/convert_rank.go.in 1970-01-01 00:00:00.000000000 +0000 99283@@ -1,54 +0,0 @@ 99284-package rank 99285- 99286-import "time" 99287- 99288-func _() { 99289- type strList []string 99290- wantsStrList := func(strList) {} 99291- 99292- var ( 99293- convA string //@item(convertA, "convA", "string", "var") 99294- convB []string //@item(convertB, "convB", "[]string", "var") 99295- ) 99296- wantsStrList(strList(conv)) //@complete("))", convertB, convertA) 99297-} 99298- 99299-func _() { 99300- type myInt int 99301- 99302- const ( 99303- convC = "hi" //@item(convertC, "convC", "string", "const") 99304- convD = 123 //@item(convertD, "convD", "int", "const") 99305- convE int = 123 //@item(convertE, "convE", "int", "const") 99306- convF string = "there" //@item(convertF, "convF", "string", "const") 99307- convG myInt = 123 //@item(convertG, "convG", "myInt", "const") 99308- ) 99309- 99310- var foo int 99311- foo = conv //@rank(" //", convertE, convertD) 99312- 99313- var mi myInt 99314- mi = conv //@rank(" //", convertG, convertD, convertE) 99315- mi + conv //@rank(" //", convertG, convertD, convertE) 99316- 99317- 1 + conv //@rank(" //", convertD, convertC),rank(" //", convertE, convertC),rank(" //", convertG, convertC) 99318- 99319- type myString string 99320- var ms myString 99321- ms = conv //@rank(" //", convertC, convertF) 99322- 99323- type myUint uint32 99324- var mu myUint 99325- mu = conv //@rank(" //", convertD, convertE) 99326- 99327- // don't downrank constants when assigning to interface{} 99328- var _ interface{} = c //@rank(" //", convertD, complex) 99329- 99330- var _ time.Duration = conv //@rank(" //", convertD, convertE),snippet(" //", convertE, "time.Duration(convE)", "time.Duration(convE)") 99331- 99332- var convP myInt //@item(convertP, "convP", "myInt", "var") 99333- var _ *int = conv //@snippet(" //", convertP, "(*int)(&convP)", "(*int)(&convP)") 99334- 99335- var ff float64 //@item(convertFloat, "ff", "float64", "var") 99336- f == convD //@snippet(" =", convertFloat, "ff", "ff") 99337-} 99338diff -urN a/gopls/internal/lsp/testdata/rank/struct/struct_rank.go b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go 99339--- a/gopls/internal/lsp/testdata/rank/struct/struct_rank.go 2000-01-01 00:00:00.000000000 -0000 99340+++ b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go 1970-01-01 00:00:00.000000000 +0000 99341@@ -1,11 +0,0 @@ 99342-package struct_rank 99343- 99344-type foo struct { 99345- c int //@item(c_rank, "c", "int", "field") 99346- b int //@item(b_rank, "b", "int", "field") 99347- a int //@item(a_rank, "a", "int", "field") 99348-} 99349- 99350-func f() { 99351- foo := foo{} //@rank("}", c_rank, b_rank, a_rank) 99352-} 99353diff -urN a/gopls/internal/lsp/testdata/rank/switch_rank.go.in b/gopls/internal/lsp/testdata/rank/switch_rank.go.in 99354--- a/gopls/internal/lsp/testdata/rank/switch_rank.go.in 2000-01-01 00:00:00.000000000 -0000 99355+++ b/gopls/internal/lsp/testdata/rank/switch_rank.go.in 1970-01-01 00:00:00.000000000 +0000 99356@@ -1,29 +0,0 @@ 99357-package rank 99358- 99359-import "time" 99360- 99361-func _() { 99362- switch pear { 99363- case _: //@rank("_", pear, apple) 99364- } 99365- 99366- time.Monday //@item(timeMonday, "time.Monday", "time.Weekday", "const"),item(monday ,"Monday", "time.Weekday", "const") 99367- time.Friday //@item(timeFriday, "time.Friday", "time.Weekday", "const"),item(friday ,"Friday", "time.Weekday", "const") 99368- 99369- now := time.Now() 99370- now.Weekday //@item(nowWeekday, "now.Weekday", "func() time.Weekday", "method") 99371- 99372- then := time.Now() 99373- then.Weekday //@item(thenWeekday, "then.Weekday", "func() time.Weekday", "method") 99374- 99375- switch time.Weekday(0) { 99376- case time.Monday, time.Tuesday: 99377- case time.Wednesday, time.Thursday: 99378- case time.Saturday, time.Sunday: 99379- case t: //@rank(":", timeFriday, timeMonday) 99380- case time.: //@rank(":", friday, monday) 99381- 99382- case now.Weekday(): 99383- case week: //@rank(":", thenWeekday, nowWeekday) 99384- } 99385-} 99386diff -urN a/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in 99387--- a/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in 2000-01-01 00:00:00.000000000 -0000 99388+++ b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in 1970-01-01 00:00:00.000000000 +0000 99389@@ -1,8 +0,0 @@ 99390-package rank 99391- 99392-func _() { 99393- type flower int //@item(flower, "flower", "int", "type") 99394- var fig string //@item(fig, "fig", "string", "var") 99395- 99396- _ = interface{}(nil).(f) //@complete(") //", flower) 99397-} 99398diff -urN a/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in 99399--- a/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in 2000-01-01 00:00:00.000000000 -0000 99400+++ b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in 1970-01-01 00:00:00.000000000 +0000 99401@@ -1,31 +0,0 @@ 99402-package rank 99403- 99404-import ( 99405- "fmt" 99406- "go/ast" 99407-) 99408- 99409-func _() { 99410- type basket int //@item(basket, "basket", "int", "type") 99411- var banana string //@item(banana, "banana", "string", "var") 99412- 99413- switch interface{}(pear).(type) { 99414- case b: //@complete(":", basket) 99415- b //@complete(" //", banana, basket) 99416- } 99417- 99418- Ident //@item(astIdent, "Ident", "struct{...}", "struct") 99419- IfStmt //@item(astIfStmt, "IfStmt", "struct{...}", "struct") 99420- 99421- switch ast.Node(nil).(type) { 99422- case *ast.Ident: 99423- case *ast.I: //@rank(":", astIfStmt, astIdent) 99424- } 99425- 99426- Stringer //@item(fmtStringer, "Stringer", "interface{...}", "interface") 99427- GoStringer //@item(fmtGoStringer, "GoStringer", "interface{...}", "interface") 99428- 99429- switch interface{}(nil).(type) { 99430- case fmt.Stringer: //@rank(":", fmtStringer, fmtGoStringer) 99431- } 99432-} 99433diff -urN a/gopls/internal/lsp/testdata/references/another/another.go b/gopls/internal/lsp/testdata/references/another/another.go 99434--- a/gopls/internal/lsp/testdata/references/another/another.go 2000-01-01 00:00:00.000000000 -0000 99435+++ b/gopls/internal/lsp/testdata/references/another/another.go 1970-01-01 00:00:00.000000000 +0000 99436@@ -1,13 +0,0 @@ 99437-// Package another has another type. 99438-package another 99439- 99440-import ( 99441- other "golang.org/lsptests/references/other" 99442-) 99443- 99444-func _() { 99445- xes := other.GetXes() 99446- for _, x := range xes { //@mark(defX, "x") 99447- _ = x.Y //@mark(useX, "x"),mark(anotherXY, "Y"),refs("Y", typeXY, anotherXY, GetXesY),refs(".", defX, useX),refs("x", defX, useX) 99448- } 99449-} 99450diff -urN a/gopls/internal/lsp/testdata/references/interfaces/interfaces.go b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go 99451--- a/gopls/internal/lsp/testdata/references/interfaces/interfaces.go 2000-01-01 00:00:00.000000000 -0000 99452+++ b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go 1970-01-01 00:00:00.000000000 +0000 99453@@ -1,34 +0,0 @@ 99454-package interfaces 99455- 99456-type first interface { 99457- common() //@mark(firCommon, "common"),refs("common", firCommon, xCommon, zCommon) 99458- firstMethod() //@mark(firMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod) 99459-} 99460- 99461-type second interface { 99462- common() //@mark(secCommon, "common"),refs("common", secCommon, yCommon, zCommon) 99463- secondMethod() //@mark(secMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod) 99464-} 99465- 99466-type s struct {} 99467- 99468-func (*s) common() {} //@mark(sCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon) 99469- 99470-func (*s) firstMethod() {} //@mark(sfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod) 99471- 99472-func (*s) secondMethod() {} //@mark(ssMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod) 99473- 99474-func main() { 99475- var x first = &s{} 99476- var y second = &s{} 99477- 99478- x.common() //@mark(xCommon, "common"),refs("common", firCommon, xCommon, zCommon) 99479- x.firstMethod() //@mark(xfMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod) 99480- y.common() //@mark(yCommon, "common"),refs("common", secCommon, yCommon, zCommon) 99481- y.secondMethod() //@mark(ysMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod) 99482- 99483- var z *s = &s{} 99484- z.firstMethod() //@mark(zfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod) 99485- z.secondMethod() //@mark(zsMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod) 99486- z.common() //@mark(zCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon) 99487-} 99488diff -urN a/gopls/internal/lsp/testdata/references/other/other.go b/gopls/internal/lsp/testdata/references/other/other.go 99489--- a/gopls/internal/lsp/testdata/references/other/other.go 2000-01-01 00:00:00.000000000 -0000 99490+++ b/gopls/internal/lsp/testdata/references/other/other.go 1970-01-01 00:00:00.000000000 +0000 99491@@ -1,19 +0,0 @@ 99492-package other 99493- 99494-import ( 99495- references "golang.org/lsptests/references" 99496-) 99497- 99498-func GetXes() []references.X { 99499- return []references.X{ 99500- { 99501- Y: 1, //@mark(GetXesY, "Y"),refs("Y", typeXY, GetXesY, anotherXY) 99502- }, 99503- } 99504-} 99505- 99506-func _() { 99507- references.Q = "hello" //@mark(assignExpQ, "Q") 99508- bob := func(_ string) {} 99509- bob(references.Q) //@mark(bobExpQ, "Q") 99510-} 99511diff -urN a/gopls/internal/lsp/testdata/references/refs.go b/gopls/internal/lsp/testdata/references/refs.go 99512--- a/gopls/internal/lsp/testdata/references/refs.go 2000-01-01 00:00:00.000000000 -0000 99513+++ b/gopls/internal/lsp/testdata/references/refs.go 1970-01-01 00:00:00.000000000 +0000 99514@@ -1,53 +0,0 @@ 99515-// Package refs is a package used to test find references. 99516-package refs 99517- 99518-import "os" //@mark(osDecl, `"os"`),refs("os", osDecl, osUse) 99519- 99520-type i int //@mark(typeI, "i"),refs("i", typeI, argI, returnI, embeddedI) 99521- 99522-type X struct { 99523- Y int //@mark(typeXY, "Y") 99524-} 99525- 99526-func _(_ i) []bool { //@mark(argI, "i") 99527- return nil 99528-} 99529- 99530-func _(_ []byte) i { //@mark(returnI, "i") 99531- return 0 99532-} 99533- 99534-var q string //@mark(declQ, "q"),refs("q", declQ, assignQ, bobQ) 99535- 99536-var Q string //@mark(declExpQ, "Q"),refs("Q", declExpQ, assignExpQ, bobExpQ) 99537- 99538-func _() { 99539- q = "hello" //@mark(assignQ, "q") 99540- bob := func(_ string) {} 99541- bob(q) //@mark(bobQ, "q") 99542-} 99543- 99544-type e struct { 99545- i //@mark(embeddedI, "i"),refs("i", embeddedI, embeddedIUse) 99546-} 99547- 99548-func _() { 99549- _ = e{}.i //@mark(embeddedIUse, "i") 99550-} 99551- 99552-const ( 99553- foo = iota //@refs("iota") 99554-) 99555- 99556-func _(x interface{}) { 99557- // We use the _ prefix because the markers inhabit a single 99558- // namespace and yDecl is already used in ../highlights/highlights.go. 99559- switch _y := x.(type) { //@mark(_yDecl, "_y"),refs("_y", _yDecl, _yInt, _yDefault) 99560- case int: 99561- println(_y) //@mark(_yInt, "_y"),refs("_y", _yDecl, _yInt, _yDefault) 99562- default: 99563- println(_y) //@mark(_yDefault, "_y") 99564- } 99565- 99566- os.Getwd() //@mark(osUse, "os") 99567-} 99568diff -urN a/gopls/internal/lsp/testdata/references/refs_test.go b/gopls/internal/lsp/testdata/references/refs_test.go 99569--- a/gopls/internal/lsp/testdata/references/refs_test.go 2000-01-01 00:00:00.000000000 -0000 99570+++ b/gopls/internal/lsp/testdata/references/refs_test.go 1970-01-01 00:00:00.000000000 +0000 99571@@ -1,10 +0,0 @@ 99572-package references 99573- 99574-import ( 99575- "testing" 99576-) 99577- 99578-// This test exists to bring the test package into existence. 99579- 99580-func TestReferences(t *testing.T) { 99581-} 99582diff -urN a/gopls/internal/lsp/testdata/rename/a/random.go.golden b/gopls/internal/lsp/testdata/rename/a/random.go.golden 99583--- a/gopls/internal/lsp/testdata/rename/a/random.go.golden 2000-01-01 00:00:00.000000000 -0000 99584+++ b/gopls/internal/lsp/testdata/rename/a/random.go.golden 1970-01-01 00:00:00.000000000 +0000 99585@@ -1,616 +0,0 @@ 99586--- GetSum-rename -- 99587-package a 99588- 99589-import ( 99590- lg "log" 99591- "fmt" //@rename("fmt", "fmty") 99592- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99593-) 99594- 99595-func Random() int { 99596- y := 6 + 7 99597- return y 99598-} 99599- 99600-func Random2(y int) int { //@rename("y", "z") 99601- return y 99602-} 99603- 99604-type Pos struct { 99605- x, y int 99606-} 99607- 99608-func (p *Pos) GetSum() int { 99609- return p.x + p.y //@rename("x", "myX") 99610-} 99611- 99612-func _() { 99613- var p Pos //@rename("p", "pos") 99614- _ = p.GetSum() //@rename("Sum", "GetSum") 99615-} 99616- 99617-func sw() { 99618- var x interface{} 99619- 99620- switch y := x.(type) { //@rename("y", "y0") 99621- case int: 99622- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99623- case string: 99624- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99625- default: 99626- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99627- } 99628-} 99629- 99630--- f2name-rename -- 99631-package a 99632- 99633-import ( 99634- lg "log" 99635- "fmt" //@rename("fmt", "fmty") 99636- f2name "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99637-) 99638- 99639-func Random() int { 99640- y := 6 + 7 99641- return y 99642-} 99643- 99644-func Random2(y int) int { //@rename("y", "z") 99645- return y 99646-} 99647- 99648-type Pos struct { 99649- x, y int 99650-} 99651- 99652-func (p *Pos) Sum() int { 99653- return p.x + p.y //@rename("x", "myX") 99654-} 99655- 99656-func _() { 99657- var p Pos //@rename("p", "pos") 99658- _ = p.Sum() //@rename("Sum", "GetSum") 99659-} 99660- 99661-func sw() { 99662- var x interface{} 99663- 99664- switch y := x.(type) { //@rename("y", "y0") 99665- case int: 99666- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99667- case string: 99668- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99669- default: 99670- f2name.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99671- } 99672-} 99673- 99674--- f2y-rename -- 99675-package a 99676- 99677-import ( 99678- lg "log" 99679- "fmt" //@rename("fmt", "fmty") 99680- f2y "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99681-) 99682- 99683-func Random() int { 99684- y := 6 + 7 99685- return y 99686-} 99687- 99688-func Random2(y int) int { //@rename("y", "z") 99689- return y 99690-} 99691- 99692-type Pos struct { 99693- x, y int 99694-} 99695- 99696-func (p *Pos) Sum() int { 99697- return p.x + p.y //@rename("x", "myX") 99698-} 99699- 99700-func _() { 99701- var p Pos //@rename("p", "pos") 99702- _ = p.Sum() //@rename("Sum", "GetSum") 99703-} 99704- 99705-func sw() { 99706- var x interface{} 99707- 99708- switch y := x.(type) { //@rename("y", "y0") 99709- case int: 99710- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99711- case string: 99712- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99713- default: 99714- f2y.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99715- } 99716-} 99717- 99718--- fmt2-rename -- 99719-package a 99720- 99721-import ( 99722- lg "log" 99723- "fmt" //@rename("fmt", "fmty") 99724- fmt2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99725-) 99726- 99727-func Random() int { 99728- y := 6 + 7 99729- return y 99730-} 99731- 99732-func Random2(y int) int { //@rename("y", "z") 99733- return y 99734-} 99735- 99736-type Pos struct { 99737- x, y int 99738-} 99739- 99740-func (p *Pos) Sum() int { 99741- return p.x + p.y //@rename("x", "myX") 99742-} 99743- 99744-func _() { 99745- var p Pos //@rename("p", "pos") 99746- _ = p.Sum() //@rename("Sum", "GetSum") 99747-} 99748- 99749-func sw() { 99750- var x interface{} 99751- 99752- switch y := x.(type) { //@rename("y", "y0") 99753- case int: 99754- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99755- case string: 99756- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99757- default: 99758- fmt2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99759- } 99760-} 99761- 99762--- fmty-rename -- 99763-package a 99764- 99765-import ( 99766- lg "log" 99767- fmty "fmt" //@rename("fmt", "fmty") 99768- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99769-) 99770- 99771-func Random() int { 99772- y := 6 + 7 99773- return y 99774-} 99775- 99776-func Random2(y int) int { //@rename("y", "z") 99777- return y 99778-} 99779- 99780-type Pos struct { 99781- x, y int 99782-} 99783- 99784-func (p *Pos) Sum() int { 99785- return p.x + p.y //@rename("x", "myX") 99786-} 99787- 99788-func _() { 99789- var p Pos //@rename("p", "pos") 99790- _ = p.Sum() //@rename("Sum", "GetSum") 99791-} 99792- 99793-func sw() { 99794- var x interface{} 99795- 99796- switch y := x.(type) { //@rename("y", "y0") 99797- case int: 99798- fmty.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99799- case string: 99800- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99801- default: 99802- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99803- } 99804-} 99805- 99806--- format-rename -- 99807-package a 99808- 99809-import ( 99810- lg "log" 99811- format "fmt" //@rename("fmt", "fmty") 99812- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99813-) 99814- 99815-func Random() int { 99816- y := 6 + 7 99817- return y 99818-} 99819- 99820-func Random2(y int) int { //@rename("y", "z") 99821- return y 99822-} 99823- 99824-type Pos struct { 99825- x, y int 99826-} 99827- 99828-func (p *Pos) Sum() int { 99829- return p.x + p.y //@rename("x", "myX") 99830-} 99831- 99832-func _() { 99833- var p Pos //@rename("p", "pos") 99834- _ = p.Sum() //@rename("Sum", "GetSum") 99835-} 99836- 99837-func sw() { 99838- var x interface{} 99839- 99840- switch y := x.(type) { //@rename("y", "y0") 99841- case int: 99842- format.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99843- case string: 99844- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99845- default: 99846- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99847- } 99848-} 99849- 99850--- log-rename -- 99851-package a 99852- 99853-import ( 99854- "log" 99855- "fmt" //@rename("fmt", "fmty") 99856- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99857-) 99858- 99859-func Random() int { 99860- y := 6 + 7 99861- return y 99862-} 99863- 99864-func Random2(y int) int { //@rename("y", "z") 99865- return y 99866-} 99867- 99868-type Pos struct { 99869- x, y int 99870-} 99871- 99872-func (p *Pos) Sum() int { 99873- return p.x + p.y //@rename("x", "myX") 99874-} 99875- 99876-func _() { 99877- var p Pos //@rename("p", "pos") 99878- _ = p.Sum() //@rename("Sum", "GetSum") 99879-} 99880- 99881-func sw() { 99882- var x interface{} 99883- 99884- switch y := x.(type) { //@rename("y", "y0") 99885- case int: 99886- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99887- case string: 99888- log.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99889- default: 99890- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99891- } 99892-} 99893- 99894--- myX-rename -- 99895-package a 99896- 99897-import ( 99898- lg "log" 99899- "fmt" //@rename("fmt", "fmty") 99900- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99901-) 99902- 99903-func Random() int { 99904- y := 6 + 7 99905- return y 99906-} 99907- 99908-func Random2(y int) int { //@rename("y", "z") 99909- return y 99910-} 99911- 99912-type Pos struct { 99913- myX, y int 99914-} 99915- 99916-func (p *Pos) Sum() int { 99917- return p.myX + p.y //@rename("x", "myX") 99918-} 99919- 99920-func _() { 99921- var p Pos //@rename("p", "pos") 99922- _ = p.Sum() //@rename("Sum", "GetSum") 99923-} 99924- 99925-func sw() { 99926- var x interface{} 99927- 99928- switch y := x.(type) { //@rename("y", "y0") 99929- case int: 99930- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99931- case string: 99932- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99933- default: 99934- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99935- } 99936-} 99937- 99938--- pos-rename -- 99939-package a 99940- 99941-import ( 99942- lg "log" 99943- "fmt" //@rename("fmt", "fmty") 99944- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99945-) 99946- 99947-func Random() int { 99948- y := 6 + 7 99949- return y 99950-} 99951- 99952-func Random2(y int) int { //@rename("y", "z") 99953- return y 99954-} 99955- 99956-type Pos struct { 99957- x, y int 99958-} 99959- 99960-func (p *Pos) Sum() int { 99961- return p.x + p.y //@rename("x", "myX") 99962-} 99963- 99964-func _() { 99965- var pos Pos //@rename("p", "pos") 99966- _ = pos.Sum() //@rename("Sum", "GetSum") 99967-} 99968- 99969-func sw() { 99970- var x interface{} 99971- 99972- switch y := x.(type) { //@rename("y", "y0") 99973- case int: 99974- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 99975- case string: 99976- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 99977- default: 99978- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 99979- } 99980-} 99981- 99982--- y0-rename -- 99983-package a 99984- 99985-import ( 99986- lg "log" 99987- "fmt" //@rename("fmt", "fmty") 99988- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 99989-) 99990- 99991-func Random() int { 99992- y := 6 + 7 99993- return y 99994-} 99995- 99996-func Random2(y int) int { //@rename("y", "z") 99997- return y 99998-} 99999- 100000-type Pos struct { 100001- x, y int 100002-} 100003- 100004-func (p *Pos) Sum() int { 100005- return p.x + p.y //@rename("x", "myX") 100006-} 100007- 100008-func _() { 100009- var p Pos //@rename("p", "pos") 100010- _ = p.Sum() //@rename("Sum", "GetSum") 100011-} 100012- 100013-func sw() { 100014- var x interface{} 100015- 100016- switch y0 := x.(type) { //@rename("y", "y0") 100017- case int: 100018- fmt.Printf("%d", y0) //@rename("y", "y1"),rename("fmt", "format") 100019- case string: 100020- lg.Printf("%s", y0) //@rename("y", "y2"),rename("lg","log") 100021- default: 100022- f2.Printf("%v", y0) //@rename("y", "y3"),rename("f2","fmt2") 100023- } 100024-} 100025- 100026--- y1-rename -- 100027-package a 100028- 100029-import ( 100030- lg "log" 100031- "fmt" //@rename("fmt", "fmty") 100032- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 100033-) 100034- 100035-func Random() int { 100036- y := 6 + 7 100037- return y 100038-} 100039- 100040-func Random2(y int) int { //@rename("y", "z") 100041- return y 100042-} 100043- 100044-type Pos struct { 100045- x, y int 100046-} 100047- 100048-func (p *Pos) Sum() int { 100049- return p.x + p.y //@rename("x", "myX") 100050-} 100051- 100052-func _() { 100053- var p Pos //@rename("p", "pos") 100054- _ = p.Sum() //@rename("Sum", "GetSum") 100055-} 100056- 100057-func sw() { 100058- var x interface{} 100059- 100060- switch y1 := x.(type) { //@rename("y", "y0") 100061- case int: 100062- fmt.Printf("%d", y1) //@rename("y", "y1"),rename("fmt", "format") 100063- case string: 100064- lg.Printf("%s", y1) //@rename("y", "y2"),rename("lg","log") 100065- default: 100066- f2.Printf("%v", y1) //@rename("y", "y3"),rename("f2","fmt2") 100067- } 100068-} 100069- 100070--- y2-rename -- 100071-package a 100072- 100073-import ( 100074- lg "log" 100075- "fmt" //@rename("fmt", "fmty") 100076- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 100077-) 100078- 100079-func Random() int { 100080- y := 6 + 7 100081- return y 100082-} 100083- 100084-func Random2(y int) int { //@rename("y", "z") 100085- return y 100086-} 100087- 100088-type Pos struct { 100089- x, y int 100090-} 100091- 100092-func (p *Pos) Sum() int { 100093- return p.x + p.y //@rename("x", "myX") 100094-} 100095- 100096-func _() { 100097- var p Pos //@rename("p", "pos") 100098- _ = p.Sum() //@rename("Sum", "GetSum") 100099-} 100100- 100101-func sw() { 100102- var x interface{} 100103- 100104- switch y2 := x.(type) { //@rename("y", "y0") 100105- case int: 100106- fmt.Printf("%d", y2) //@rename("y", "y1"),rename("fmt", "format") 100107- case string: 100108- lg.Printf("%s", y2) //@rename("y", "y2"),rename("lg","log") 100109- default: 100110- f2.Printf("%v", y2) //@rename("y", "y3"),rename("f2","fmt2") 100111- } 100112-} 100113- 100114--- y3-rename -- 100115-package a 100116- 100117-import ( 100118- lg "log" 100119- "fmt" //@rename("fmt", "fmty") 100120- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 100121-) 100122- 100123-func Random() int { 100124- y := 6 + 7 100125- return y 100126-} 100127- 100128-func Random2(y int) int { //@rename("y", "z") 100129- return y 100130-} 100131- 100132-type Pos struct { 100133- x, y int 100134-} 100135- 100136-func (p *Pos) Sum() int { 100137- return p.x + p.y //@rename("x", "myX") 100138-} 100139- 100140-func _() { 100141- var p Pos //@rename("p", "pos") 100142- _ = p.Sum() //@rename("Sum", "GetSum") 100143-} 100144- 100145-func sw() { 100146- var x interface{} 100147- 100148- switch y3 := x.(type) { //@rename("y", "y0") 100149- case int: 100150- fmt.Printf("%d", y3) //@rename("y", "y1"),rename("fmt", "format") 100151- case string: 100152- lg.Printf("%s", y3) //@rename("y", "y2"),rename("lg","log") 100153- default: 100154- f2.Printf("%v", y3) //@rename("y", "y3"),rename("f2","fmt2") 100155- } 100156-} 100157- 100158--- z-rename -- 100159-package a 100160- 100161-import ( 100162- lg "log" 100163- "fmt" //@rename("fmt", "fmty") 100164- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 100165-) 100166- 100167-func Random() int { 100168- y := 6 + 7 100169- return y 100170-} 100171- 100172-func Random2(z int) int { //@rename("y", "z") 100173- return z 100174-} 100175- 100176-type Pos struct { 100177- x, y int 100178-} 100179- 100180-func (p *Pos) Sum() int { 100181- return p.x + p.y //@rename("x", "myX") 100182-} 100183- 100184-func _() { 100185- var p Pos //@rename("p", "pos") 100186- _ = p.Sum() //@rename("Sum", "GetSum") 100187-} 100188- 100189-func sw() { 100190- var x interface{} 100191- 100192- switch y := x.(type) { //@rename("y", "y0") 100193- case int: 100194- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 100195- case string: 100196- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 100197- default: 100198- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 100199- } 100200-} 100201- 100202diff -urN a/gopls/internal/lsp/testdata/rename/a/random.go.in b/gopls/internal/lsp/testdata/rename/a/random.go.in 100203--- a/gopls/internal/lsp/testdata/rename/a/random.go.in 2000-01-01 00:00:00.000000000 -0000 100204+++ b/gopls/internal/lsp/testdata/rename/a/random.go.in 1970-01-01 00:00:00.000000000 +0000 100205@@ -1,42 +0,0 @@ 100206-package a 100207- 100208-import ( 100209- lg "log" 100210- "fmt" //@rename("fmt", "fmty") 100211- f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") 100212-) 100213- 100214-func Random() int { 100215- y := 6 + 7 100216- return y 100217-} 100218- 100219-func Random2(y int) int { //@rename("y", "z") 100220- return y 100221-} 100222- 100223-type Pos struct { 100224- x, y int 100225-} 100226- 100227-func (p *Pos) Sum() int { 100228- return p.x + p.y //@rename("x", "myX") 100229-} 100230- 100231-func _() { 100232- var p Pos //@rename("p", "pos") 100233- _ = p.Sum() //@rename("Sum", "GetSum") 100234-} 100235- 100236-func sw() { 100237- var x interface{} 100238- 100239- switch y := x.(type) { //@rename("y", "y0") 100240- case int: 100241- fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") 100242- case string: 100243- lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") 100244- default: 100245- f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") 100246- } 100247-} 100248diff -urN a/gopls/internal/lsp/testdata/rename/b/b.go b/gopls/internal/lsp/testdata/rename/b/b.go 100249--- a/gopls/internal/lsp/testdata/rename/b/b.go 2000-01-01 00:00:00.000000000 -0000 100250+++ b/gopls/internal/lsp/testdata/rename/b/b.go 1970-01-01 00:00:00.000000000 +0000 100251@@ -1,20 +0,0 @@ 100252-package b 100253- 100254-var c int //@rename("int", "uint") 100255- 100256-func _() { 100257- a := 1 //@rename("a", "error") 100258- a = 2 100259- _ = a 100260-} 100261- 100262-var ( 100263- // Hello there. 100264- // Foo does the thing. 100265- Foo int //@rename("Foo", "Bob") 100266-) 100267- 100268-/* 100269-Hello description 100270-*/ 100271-func Hello() {} //@rename("Hello", "Goodbye") 100272diff -urN a/gopls/internal/lsp/testdata/rename/b/b.go.golden b/gopls/internal/lsp/testdata/rename/b/b.go.golden 100273--- a/gopls/internal/lsp/testdata/rename/b/b.go.golden 2000-01-01 00:00:00.000000000 -0000 100274+++ b/gopls/internal/lsp/testdata/rename/b/b.go.golden 1970-01-01 00:00:00.000000000 +0000 100275@@ -1,78 +0,0 @@ 100276--- Bob-rename -- 100277-package b 100278- 100279-var c int //@rename("int", "uint") 100280- 100281-func _() { 100282- a := 1 //@rename("a", "error") 100283- a = 2 100284- _ = a 100285-} 100286- 100287-var ( 100288- // Hello there. 100289- // Bob does the thing. 100290- Bob int //@rename("Foo", "Bob") 100291-) 100292- 100293-/* 100294-Hello description 100295-*/ 100296-func Hello() {} //@rename("Hello", "Goodbye") 100297- 100298--- Goodbye-rename -- 100299-b.go: 100300-package b 100301- 100302-var c int //@rename("int", "uint") 100303- 100304-func _() { 100305- a := 1 //@rename("a", "error") 100306- a = 2 100307- _ = a 100308-} 100309- 100310-var ( 100311- // Hello there. 100312- // Foo does the thing. 100313- Foo int //@rename("Foo", "Bob") 100314-) 100315- 100316-/* 100317-Goodbye description 100318-*/ 100319-func Goodbye() {} //@rename("Hello", "Goodbye") 100320- 100321-c.go: 100322-package c 100323- 100324-import "golang.org/lsptests/rename/b" 100325- 100326-func _() { 100327- b.Goodbye() //@rename("Hello", "Goodbye") 100328-} 100329- 100330--- error-rename -- 100331-package b 100332- 100333-var c int //@rename("int", "uint") 100334- 100335-func _() { 100336- error := 1 //@rename("a", "error") 100337- error = 2 100338- _ = error 100339-} 100340- 100341-var ( 100342- // Hello there. 100343- // Foo does the thing. 100344- Foo int //@rename("Foo", "Bob") 100345-) 100346- 100347-/* 100348-Hello description 100349-*/ 100350-func Hello() {} //@rename("Hello", "Goodbye") 100351- 100352--- uint-rename -- 100353-int is built in and cannot be renamed 100354diff -urN a/gopls/internal/lsp/testdata/rename/bad/bad.go.golden b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden 100355--- a/gopls/internal/lsp/testdata/rename/bad/bad.go.golden 2000-01-01 00:00:00.000000000 -0000 100356+++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden 1970-01-01 00:00:00.000000000 +0000 100357@@ -1,2 +0,0 @@ 100358--- rFunc-rename -- 100359-renaming "sFunc" to "rFunc" not possible because "golang.org/lsptests/rename/bad" has errors 100360diff -urN a/gopls/internal/lsp/testdata/rename/bad/bad.go.in b/gopls/internal/lsp/testdata/rename/bad/bad.go.in 100361--- a/gopls/internal/lsp/testdata/rename/bad/bad.go.in 2000-01-01 00:00:00.000000000 -0000 100362+++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.in 1970-01-01 00:00:00.000000000 +0000 100363@@ -1,8 +0,0 @@ 100364-package bad 100365- 100366-type myStruct struct { 100367-} 100368- 100369-func (s *myStruct) sFunc() bool { //@rename("sFunc", "rFunc") 100370- return s.Bad 100371-} 100372diff -urN a/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in 100373--- a/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in 2000-01-01 00:00:00.000000000 -0000 100374+++ b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in 1970-01-01 00:00:00.000000000 +0000 100375@@ -1 +0,0 @@ 100376-package bad 100377\ No newline at end of file 100378diff -urN a/gopls/internal/lsp/testdata/rename/c/c2.go b/gopls/internal/lsp/testdata/rename/c/c2.go 100379--- a/gopls/internal/lsp/testdata/rename/c/c2.go 2000-01-01 00:00:00.000000000 -0000 100380+++ b/gopls/internal/lsp/testdata/rename/c/c2.go 1970-01-01 00:00:00.000000000 +0000 100381@@ -1,4 +0,0 @@ 100382-package c 100383- 100384-//go:embed Static/* 100385-var Static embed.FS //@rename("Static", "static") 100386\ No newline at end of file 100387diff -urN a/gopls/internal/lsp/testdata/rename/c/c2.go.golden b/gopls/internal/lsp/testdata/rename/c/c2.go.golden 100388--- a/gopls/internal/lsp/testdata/rename/c/c2.go.golden 2000-01-01 00:00:00.000000000 -0000 100389+++ b/gopls/internal/lsp/testdata/rename/c/c2.go.golden 1970-01-01 00:00:00.000000000 +0000 100390@@ -1,5 +0,0 @@ 100391--- static-rename -- 100392-package c 100393- 100394-//go:embed Static/* 100395-var static embed.FS //@rename("Static", "static") 100396diff -urN a/gopls/internal/lsp/testdata/rename/c/c.go b/gopls/internal/lsp/testdata/rename/c/c.go 100397--- a/gopls/internal/lsp/testdata/rename/c/c.go 2000-01-01 00:00:00.000000000 -0000 100398+++ b/gopls/internal/lsp/testdata/rename/c/c.go 1970-01-01 00:00:00.000000000 +0000 100399@@ -1,7 +0,0 @@ 100400-package c 100401- 100402-import "golang.org/lsptests/rename/b" 100403- 100404-func _() { 100405- b.Hello() //@rename("Hello", "Goodbye") 100406-} 100407diff -urN a/gopls/internal/lsp/testdata/rename/c/c.go.golden b/gopls/internal/lsp/testdata/rename/c/c.go.golden 100408--- a/gopls/internal/lsp/testdata/rename/c/c.go.golden 2000-01-01 00:00:00.000000000 -0000 100409+++ b/gopls/internal/lsp/testdata/rename/c/c.go.golden 1970-01-01 00:00:00.000000000 +0000 100410@@ -1,32 +0,0 @@ 100411--- Goodbye-rename -- 100412-b.go: 100413-package b 100414- 100415-var c int //@rename("int", "uint") 100416- 100417-func _() { 100418- a := 1 //@rename("a", "error") 100419- a = 2 100420- _ = a 100421-} 100422- 100423-var ( 100424- // Hello there. 100425- // Foo does the thing. 100426- Foo int //@rename("Foo", "Bob") 100427-) 100428- 100429-/* 100430-Goodbye description 100431-*/ 100432-func Goodbye() {} //@rename("Hello", "Goodbye") 100433- 100434-c.go: 100435-package c 100436- 100437-import "golang.org/lsptests/rename/b" 100438- 100439-func _() { 100440- b.Goodbye() //@rename("Hello", "Goodbye") 100441-} 100442- 100443diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go 100444--- a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go 2000-01-01 00:00:00.000000000 -0000 100445+++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go 1970-01-01 00:00:00.000000000 +0000 100446@@ -1,13 +0,0 @@ 100447-package another 100448- 100449-type ( 100450- I interface{ F() } 100451- C struct{ I } 100452-) 100453- 100454-func (C) g() 100455- 100456-func _() { 100457- var x I = C{} 100458- x.F() //@rename("F", "G") 100459-} 100460diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden 100461--- a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden 2000-01-01 00:00:00.000000000 -0000 100462+++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden 1970-01-01 00:00:00.000000000 +0000 100463@@ -1,15 +0,0 @@ 100464--- G-rename -- 100465-package another 100466- 100467-type ( 100468- I interface{ G() } 100469- C struct{ I } 100470-) 100471- 100472-func (C) g() 100473- 100474-func _() { 100475- var x I = C{} 100476- x.G() //@rename("F", "G") 100477-} 100478- 100479diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go 100480--- a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go 2000-01-01 00:00:00.000000000 -0000 100481+++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go 1970-01-01 00:00:00.000000000 +0000 100482@@ -1,7 +0,0 @@ 100483-package crosspkg 100484- 100485-func Foo() { //@rename("Foo", "Dolphin") 100486- 100487-} 100488- 100489-var Bar int //@rename("Bar", "Tomato") 100490diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden 100491--- a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden 2000-01-01 00:00:00.000000000 -0000 100492+++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden 1970-01-01 00:00:00.000000000 +0000 100493@@ -1,40 +0,0 @@ 100494--- Dolphin-rename -- 100495-crosspkg.go: 100496-package crosspkg 100497- 100498-func Dolphin() { //@rename("Foo", "Dolphin") 100499- 100500-} 100501- 100502-var Bar int //@rename("Bar", "Tomato") 100503- 100504-other.go: 100505-package other 100506- 100507-import "golang.org/lsptests/rename/crosspkg" 100508- 100509-func Other() { 100510- crosspkg.Bar 100511- crosspkg.Dolphin() //@rename("Foo", "Flamingo") 100512-} 100513- 100514--- Tomato-rename -- 100515-crosspkg.go: 100516-package crosspkg 100517- 100518-func Foo() { //@rename("Foo", "Dolphin") 100519- 100520-} 100521- 100522-var Tomato int //@rename("Bar", "Tomato") 100523- 100524-other.go: 100525-package other 100526- 100527-import "golang.org/lsptests/rename/crosspkg" 100528- 100529-func Other() { 100530- crosspkg.Tomato 100531- crosspkg.Foo() //@rename("Foo", "Flamingo") 100532-} 100533- 100534diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go 100535--- a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go 2000-01-01 00:00:00.000000000 -0000 100536+++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go 1970-01-01 00:00:00.000000000 +0000 100537@@ -1,8 +0,0 @@ 100538-package other 100539- 100540-import "golang.org/lsptests/rename/crosspkg" 100541- 100542-func Other() { 100543- crosspkg.Bar 100544- crosspkg.Foo() //@rename("Foo", "Flamingo") 100545-} 100546diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden 100547--- a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden 2000-01-01 00:00:00.000000000 -0000 100548+++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden 1970-01-01 00:00:00.000000000 +0000 100549@@ -1,20 +0,0 @@ 100550--- Flamingo-rename -- 100551-crosspkg.go: 100552-package crosspkg 100553- 100554-func Flamingo() { //@rename("Foo", "Dolphin") 100555- 100556-} 100557- 100558-var Bar int //@rename("Bar", "Tomato") 100559- 100560-other.go: 100561-package other 100562- 100563-import "golang.org/lsptests/rename/crosspkg" 100564- 100565-func Other() { 100566- crosspkg.Bar 100567- crosspkg.Flamingo() //@rename("Foo", "Flamingo") 100568-} 100569- 100570diff -urN a/gopls/internal/lsp/testdata/rename/generics/embedded.go b/gopls/internal/lsp/testdata/rename/generics/embedded.go 100571--- a/gopls/internal/lsp/testdata/rename/generics/embedded.go 2000-01-01 00:00:00.000000000 -0000 100572+++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go 1970-01-01 00:00:00.000000000 +0000 100573@@ -1,10 +0,0 @@ 100574-//go:build go1.18 100575-// +build go1.18 100576- 100577-package generics 100578- 100579-type foo[P any] int //@rename("foo","bar") 100580- 100581-var x struct{ foo[int] } 100582- 100583-var _ = x.foo 100584diff -urN a/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden 100585--- a/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden 2000-01-01 00:00:00.000000000 -0000 100586+++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden 1970-01-01 00:00:00.000000000 +0000 100587@@ -1,12 +0,0 @@ 100588--- bar-rename -- 100589-//go:build go1.18 100590-// +build go1.18 100591- 100592-package generics 100593- 100594-type bar[P any] int //@rename("foo","bar") 100595- 100596-var x struct{ bar[int] } 100597- 100598-var _ = x.bar 100599- 100600diff -urN a/gopls/internal/lsp/testdata/rename/generics/generics.go b/gopls/internal/lsp/testdata/rename/generics/generics.go 100601--- a/gopls/internal/lsp/testdata/rename/generics/generics.go 2000-01-01 00:00:00.000000000 -0000 100602+++ b/gopls/internal/lsp/testdata/rename/generics/generics.go 1970-01-01 00:00:00.000000000 +0000 100603@@ -1,25 +0,0 @@ 100604-//go:build go1.18 100605-// +build go1.18 100606- 100607-package generics 100608- 100609-type G[P any] struct { 100610- F int 100611-} 100612- 100613-func (G[_]) M() {} 100614- 100615-func F[P any](P) { 100616- var p P //@rename("P", "Q") 100617- _ = p 100618-} 100619- 100620-func _() { 100621- var x G[int] //@rename("G", "H") 100622- _ = x.F //@rename("F", "K") 100623- x.M() //@rename("M", "N") 100624- 100625- var y G[string] 100626- _ = y.F 100627- y.M() 100628-} 100629diff -urN a/gopls/internal/lsp/testdata/rename/generics/generics.go.golden b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden 100630--- a/gopls/internal/lsp/testdata/rename/generics/generics.go.golden 2000-01-01 00:00:00.000000000 -0000 100631+++ b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden 1970-01-01 00:00:00.000000000 +0000 100632@@ -1,108 +0,0 @@ 100633--- H-rename -- 100634-//go:build go1.18 100635-// +build go1.18 100636- 100637-package generics 100638- 100639-type H[P any] struct { 100640- F int 100641-} 100642- 100643-func (H[_]) M() {} 100644- 100645-func F[P any](P) { 100646- var p P //@rename("P", "Q") 100647- _ = p 100648-} 100649- 100650-func _() { 100651- var x H[int] //@rename("G", "H") 100652- _ = x.F //@rename("F", "K") 100653- x.M() //@rename("M", "N") 100654- 100655- var y H[string] 100656- _ = y.F 100657- y.M() 100658-} 100659- 100660--- K-rename -- 100661-//go:build go1.18 100662-// +build go1.18 100663- 100664-package generics 100665- 100666-type G[P any] struct { 100667- K int 100668-} 100669- 100670-func (G[_]) M() {} 100671- 100672-func F[P any](P) { 100673- var p P //@rename("P", "Q") 100674- _ = p 100675-} 100676- 100677-func _() { 100678- var x G[int] //@rename("G", "H") 100679- _ = x.K //@rename("F", "K") 100680- x.M() //@rename("M", "N") 100681- 100682- var y G[string] 100683- _ = y.K 100684- y.M() 100685-} 100686- 100687--- N-rename -- 100688-//go:build go1.18 100689-// +build go1.18 100690- 100691-package generics 100692- 100693-type G[P any] struct { 100694- F int 100695-} 100696- 100697-func (G[_]) N() {} 100698- 100699-func F[P any](P) { 100700- var p P //@rename("P", "Q") 100701- _ = p 100702-} 100703- 100704-func _() { 100705- var x G[int] //@rename("G", "H") 100706- _ = x.F //@rename("F", "K") 100707- x.N() //@rename("M", "N") 100708- 100709- var y G[string] 100710- _ = y.F 100711- y.N() 100712-} 100713- 100714--- Q-rename -- 100715-//go:build go1.18 100716-// +build go1.18 100717- 100718-package generics 100719- 100720-type G[P any] struct { 100721- F int 100722-} 100723- 100724-func (G[_]) M() {} 100725- 100726-func F[Q any](Q) { 100727- var p Q //@rename("P", "Q") 100728- _ = p 100729-} 100730- 100731-func _() { 100732- var x G[int] //@rename("G", "H") 100733- _ = x.F //@rename("F", "K") 100734- x.M() //@rename("M", "N") 100735- 100736- var y G[string] 100737- _ = y.F 100738- y.M() 100739-} 100740- 100741diff -urN a/gopls/internal/lsp/testdata/rename/generics/unions.go b/gopls/internal/lsp/testdata/rename/generics/unions.go 100742--- a/gopls/internal/lsp/testdata/rename/generics/unions.go 2000-01-01 00:00:00.000000000 -0000 100743+++ b/gopls/internal/lsp/testdata/rename/generics/unions.go 1970-01-01 00:00:00.000000000 +0000 100744@@ -1,10 +0,0 @@ 100745-//go:build go1.18 100746-// +build go1.18 100747- 100748-package generics 100749- 100750-type T string //@rename("T", "R") 100751- 100752-type C interface { 100753- T | ~int //@rename("T", "S") 100754-} 100755diff -urN a/gopls/internal/lsp/testdata/rename/generics/unions.go.golden b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden 100756--- a/gopls/internal/lsp/testdata/rename/generics/unions.go.golden 2000-01-01 00:00:00.000000000 -0000 100757+++ b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden 1970-01-01 00:00:00.000000000 +0000 100758@@ -1,24 +0,0 @@ 100759--- R-rename -- 100760-//go:build go1.18 100761-// +build go1.18 100762- 100763-package generics 100764- 100765-type R string //@rename("T", "R") 100766- 100767-type C interface { 100768- R | ~int //@rename("T", "S") 100769-} 100770- 100771--- S-rename -- 100772-//go:build go1.18 100773-// +build go1.18 100774- 100775-package generics 100776- 100777-type S string //@rename("T", "R") 100778- 100779-type C interface { 100780- S | ~int //@rename("T", "S") 100781-} 100782- 100783diff -urN a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden 100784--- a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden 2000-01-01 00:00:00.000000000 -0000 100785+++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden 1970-01-01 00:00:00.000000000 +0000 100786@@ -1,10 +0,0 @@ 100787--- bar-rename -- 100788-package issue39614 100789- 100790-func fn() { 100791- var bar bool //@rename("foo","bar") 100792- make(map[string]bool 100793- if true { 100794- } 100795-} 100796- 100797diff -urN a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in 100798--- a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in 2000-01-01 00:00:00.000000000 -0000 100799+++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in 1970-01-01 00:00:00.000000000 +0000 100800@@ -1,8 +0,0 @@ 100801-package issue39614 100802- 100803-func fn() { 100804- var foo bool //@rename("foo","bar") 100805- make(map[string]bool 100806- if true { 100807- } 100808-} 100809diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/1.go b/gopls/internal/lsp/testdata/rename/issue42134/1.go 100810--- a/gopls/internal/lsp/testdata/rename/issue42134/1.go 2000-01-01 00:00:00.000000000 -0000 100811+++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go 1970-01-01 00:00:00.000000000 +0000 100812@@ -1,8 +0,0 @@ 100813-package issue42134 100814- 100815-func _() { 100816- // foo computes things. 100817- foo := func() {} 100818- 100819- foo() //@rename("foo", "bar") 100820-} 100821diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden 100822--- a/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden 2000-01-01 00:00:00.000000000 -0000 100823+++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden 1970-01-01 00:00:00.000000000 +0000 100824@@ -1,10 +0,0 @@ 100825--- bar-rename -- 100826-package issue42134 100827- 100828-func _() { 100829- // bar computes things. 100830- bar := func() {} 100831- 100832- bar() //@rename("foo", "bar") 100833-} 100834- 100835diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/2.go b/gopls/internal/lsp/testdata/rename/issue42134/2.go 100836--- a/gopls/internal/lsp/testdata/rename/issue42134/2.go 2000-01-01 00:00:00.000000000 -0000 100837+++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go 1970-01-01 00:00:00.000000000 +0000 100838@@ -1,12 +0,0 @@ 100839-package issue42134 100840- 100841-import "fmt" 100842- 100843-func _() { 100844- // minNumber is a min number. 100845- // Second line. 100846- minNumber := min(1, 2) 100847- fmt.Println(minNumber) //@rename("minNumber", "res") 100848-} 100849- 100850-func min(a, b int) int { return a } 100851diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden 100852--- a/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden 2000-01-01 00:00:00.000000000 -0000 100853+++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden 1970-01-01 00:00:00.000000000 +0000 100854@@ -1,14 +0,0 @@ 100855--- res-rename -- 100856-package issue42134 100857- 100858-import "fmt" 100859- 100860-func _() { 100861- // res is a min number. 100862- // Second line. 100863- res := min(1, 2) 100864- fmt.Println(res) //@rename("minNumber", "res") 100865-} 100866- 100867-func min(a, b int) int { return a } 100868- 100869diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/3.go b/gopls/internal/lsp/testdata/rename/issue42134/3.go 100870--- a/gopls/internal/lsp/testdata/rename/issue42134/3.go 2000-01-01 00:00:00.000000000 -0000 100871+++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go 1970-01-01 00:00:00.000000000 +0000 100872@@ -1,11 +0,0 @@ 100873-package issue42134 100874- 100875-func _() { 100876- /* 100877- tests contains test cases 100878- */ 100879- tests := []struct { //@rename("tests", "testCases") 100880- in, out string 100881- }{} 100882- _ = tests 100883-} 100884diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden 100885--- a/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden 2000-01-01 00:00:00.000000000 -0000 100886+++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden 1970-01-01 00:00:00.000000000 +0000 100887@@ -1,13 +0,0 @@ 100888--- testCases-rename -- 100889-package issue42134 100890- 100891-func _() { 100892- /* 100893- testCases contains test cases 100894- */ 100895- testCases := []struct { //@rename("tests", "testCases") 100896- in, out string 100897- }{} 100898- _ = testCases 100899-} 100900- 100901diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/4.go b/gopls/internal/lsp/testdata/rename/issue42134/4.go 100902--- a/gopls/internal/lsp/testdata/rename/issue42134/4.go 2000-01-01 00:00:00.000000000 -0000 100903+++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go 1970-01-01 00:00:00.000000000 +0000 100904@@ -1,8 +0,0 @@ 100905-package issue42134 100906- 100907-func _() { 100908- // a is equal to 5. Comment must stay the same 100909- 100910- a := 5 100911- _ = a //@rename("a", "b") 100912-} 100913diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden 100914--- a/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden 2000-01-01 00:00:00.000000000 -0000 100915+++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden 1970-01-01 00:00:00.000000000 +0000 100916@@ -1,10 +0,0 @@ 100917--- b-rename -- 100918-package issue42134 100919- 100920-func _() { 100921- // a is equal to 5. Comment must stay the same 100922- 100923- b := 5 100924- _ = b //@rename("a", "b") 100925-} 100926- 100927diff -urN a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden 100928--- a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden 2000-01-01 00:00:00.000000000 -0000 100929+++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden 1970-01-01 00:00:00.000000000 +0000 100930@@ -1,13 +0,0 @@ 100931--- bar-rename -- 100932-package issue43616 100933- 100934-type bar int //@rename("foo","bar"),prepare("oo","foo","foo") 100935- 100936-var x struct{ bar } //@rename("foo","baz") 100937- 100938-var _ = x.bar //@rename("foo","quux") 100939- 100940--- baz-rename -- 100941-can't rename embedded fields: rename the type directly or name the field 100942--- quux-rename -- 100943-can't rename embedded fields: rename the type directly or name the field 100944diff -urN a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in 100945--- a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in 2000-01-01 00:00:00.000000000 -0000 100946+++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in 1970-01-01 00:00:00.000000000 +0000 100947@@ -1,7 +0,0 @@ 100948-package issue43616 100949- 100950-type foo int //@rename("foo","bar"),prepare("oo","foo","foo") 100951- 100952-var x struct{ foo } //@rename("foo","baz") 100953- 100954-var _ = x.foo //@rename("foo","quux") 100955diff -urN a/gopls/internal/lsp/testdata/rename/shadow/shadow.go b/gopls/internal/lsp/testdata/rename/shadow/shadow.go 100956--- a/gopls/internal/lsp/testdata/rename/shadow/shadow.go 2000-01-01 00:00:00.000000000 -0000 100957+++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go 1970-01-01 00:00:00.000000000 +0000 100958@@ -1,20 +0,0 @@ 100959-package shadow 100960- 100961-func _() { 100962- a := true 100963- b, c, _ := A(), B(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d") 100964- d := false 100965- _, _, _, _ = a, b, c, d 100966-} 100967- 100968-func A() int { 100969- return 0 100970-} 100971- 100972-func B() int { 100973- return 0 100974-} 100975- 100976-func D() int { 100977- return 0 100978-} 100979diff -urN a/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden 100980--- a/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden 2000-01-01 00:00:00.000000000 -0000 100981+++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden 1970-01-01 00:00:00.000000000 +0000 100982@@ -1,51 +0,0 @@ 100983--- a-rename -- 100984-shadow/shadow.go:10:6: renaming this func "A" to "a" 100985-shadow/shadow.go:5:13: would cause this reference to become shadowed 100986-shadow/shadow.go:4:2: by this intervening var definition 100987--- b-rename -- 100988-package shadow 100989- 100990-func _() { 100991- a := true 100992- b, c, _ := A(), b(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d") 100993- d := false 100994- _, _, _, _ = a, b, c, d 100995-} 100996- 100997-func A() int { 100998- return 0 100999-} 101000- 101001-func b() int { 101002- return 0 101003-} 101004- 101005-func D() int { 101006- return 0 101007-} 101008- 101009--- c-rename -- 101010-shadow/shadow.go:5:2: renaming this var "b" to "c" 101011-shadow/shadow.go:5:5: conflicts with var in same block 101012--- d-rename -- 101013-package shadow 101014- 101015-func _() { 101016- a := true 101017- b, c, _ := A(), B(), d() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d") 101018- d := false 101019- _, _, _, _ = a, b, c, d 101020-} 101021- 101022-func A() int { 101023- return 0 101024-} 101025- 101026-func B() int { 101027- return 0 101028-} 101029- 101030-func d() int { 101031- return 0 101032-} 101033- 101034diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy.go b/gopls/internal/lsp/testdata/rename/testy/testy.go 101035--- a/gopls/internal/lsp/testdata/rename/testy/testy.go 2000-01-01 00:00:00.000000000 -0000 101036+++ b/gopls/internal/lsp/testdata/rename/testy/testy.go 1970-01-01 00:00:00.000000000 +0000 101037@@ -1,7 +0,0 @@ 101038-package testy 101039- 101040-type tt int //@rename("tt", "testyType") 101041- 101042-func a() { 101043- foo := 42 //@rename("foo", "bar") 101044-} 101045diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden 101046--- a/gopls/internal/lsp/testdata/rename/testy/testy.go.golden 2000-01-01 00:00:00.000000000 -0000 101047+++ b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden 1970-01-01 00:00:00.000000000 +0000 101048@@ -1,18 +0,0 @@ 101049--- bar-rename -- 101050-package testy 101051- 101052-type tt int //@rename("tt", "testyType") 101053- 101054-func a() { 101055- bar := 42 //@rename("foo", "bar") 101056-} 101057- 101058--- testyType-rename -- 101059-package testy 101060- 101061-type testyType int //@rename("tt", "testyType") 101062- 101063-func a() { 101064- foo := 42 //@rename("foo", "bar") 101065-} 101066- 101067diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy_test.go b/gopls/internal/lsp/testdata/rename/testy/testy_test.go 101068--- a/gopls/internal/lsp/testdata/rename/testy/testy_test.go 2000-01-01 00:00:00.000000000 -0000 101069+++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go 1970-01-01 00:00:00.000000000 +0000 101070@@ -1,8 +0,0 @@ 101071-package testy 101072- 101073-import "testing" 101074- 101075-func TestSomething(t *testing.T) { 101076- var x int //@rename("x", "testyX") 101077- a() //@rename("a", "b") 101078-} 101079diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden 101080--- a/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden 2000-01-01 00:00:00.000000000 -0000 101081+++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden 1970-01-01 00:00:00.000000000 +0000 101082@@ -1,30 +0,0 @@ 101083--- b-rename -- 101084-testy.go: 101085-package testy 101086- 101087-type tt int //@rename("tt", "testyType") 101088- 101089-func b() { 101090- foo := 42 //@rename("foo", "bar") 101091-} 101092- 101093-testy_test.go: 101094-package testy 101095- 101096-import "testing" 101097- 101098-func TestSomething(t *testing.T) { 101099- var x int //@rename("x", "testyX") 101100- b() //@rename("a", "b") 101101-} 101102- 101103--- testyX-rename -- 101104-package testy 101105- 101106-import "testing" 101107- 101108-func TestSomething(t *testing.T) { 101109- var testyX int //@rename("x", "testyX") 101110- a() //@rename("a", "b") 101111-} 101112- 101113diff -urN a/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go 101114--- a/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go 2000-01-01 00:00:00.000000000 -0000 101115+++ b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go 1970-01-01 00:00:00.000000000 +0000 101116@@ -1,14 +0,0 @@ 101117-package rundespiteerrors 101118- 101119-// This test verifies that analyzers without RunDespiteErrors are not 101120-// executed on a package containing type errors (see issue #54762). 101121-func _() { 101122- // A type error. 101123- _ = 1 + "" //@diag("1", "compiler", "mismatched types|cannot convert", "error") 101124- 101125- // A violation of an analyzer for which RunDespiteErrors=false: 101126- // no diagnostic is produced; the diag comment is merely illustrative. 101127- for _ = range "" { //diag("for _", "simplifyrange", "simplify range expression", "warning") 101128- 101129- } 101130-} 101131diff -urN a/gopls/internal/lsp/testdata/selectionrange/foo.go b/gopls/internal/lsp/testdata/selectionrange/foo.go 101132--- a/gopls/internal/lsp/testdata/selectionrange/foo.go 2000-01-01 00:00:00.000000000 -0000 101133+++ b/gopls/internal/lsp/testdata/selectionrange/foo.go 1970-01-01 00:00:00.000000000 +0000 101134@@ -1,13 +0,0 @@ 101135-package foo 101136- 101137-import "time" 101138- 101139-func Bar(x, y int, t time.Time) int { 101140- zs := []int{1, 2, 3} //@selectionrange("1") 101141- 101142- for _, z := range zs { 101143- x = x + z + y + zs[1] //@selectionrange("1") 101144- } 101145- 101146- return x + y //@selectionrange("+") 101147-} 101148diff -urN a/gopls/internal/lsp/testdata/selectionrange/foo.go.golden b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden 101149--- a/gopls/internal/lsp/testdata/selectionrange/foo.go.golden 2000-01-01 00:00:00.000000000 -0000 101150+++ b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden 1970-01-01 00:00:00.000000000 +0000 101151@@ -1,29 +0,0 @@ 101152--- selectionrange_foo_12_11 -- 101153-Ranges 0: 101154- 11:8-11:13 "x + y" 101155- 11:1-11:13 "return x + y" 101156- 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}" 101157- 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}" 101158- 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}" 101159- 101160--- selectionrange_foo_6_14 -- 101161-Ranges 0: 101162- 5:13-5:14 "1" 101163- 5:7-5:21 "[]int{1, 2, 3}" 101164- 5:1-5:21 "zs := []int{1, 2, 3}" 101165- 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}" 101166- 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}" 101167- 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}" 101168- 101169--- selectionrange_foo_9_22 -- 101170-Ranges 0: 101171- 8:21-8:22 "1" 101172- 8:18-8:23 "zs[1]" 101173- 8:6-8:23 "x + z + y + zs[1]" 101174- 8:2-8:23 "x = x + z + y + zs[1]" 101175- 7:22-9:2 "{\\n\t\tx = x + z +...onrange(\"1\")\\n\t}" 101176- 7:1-9:2 "for _, z := ran...onrange(\"1\")\\n\t}" 101177- 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}" 101178- 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}" 101179- 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}" 101180- 101181diff -urN a/gopls/internal/lsp/testdata/selector/selector.go.in b/gopls/internal/lsp/testdata/selector/selector.go.in 101182--- a/gopls/internal/lsp/testdata/selector/selector.go.in 2000-01-01 00:00:00.000000000 -0000 101183+++ b/gopls/internal/lsp/testdata/selector/selector.go.in 1970-01-01 00:00:00.000000000 +0000 101184@@ -1,66 +0,0 @@ 101185-// +build go1.11 101186- 101187-package selector 101188- 101189-import ( 101190- "golang.org/lsptests/bar" 101191-) 101192- 101193-type S struct { 101194- B, A, C int //@item(Bf, "B", "int", "field"),item(Af, "A", "int", "field"),item(Cf, "C", "int", "field") 101195-} 101196- 101197-func _() { 101198- _ = S{}.; //@complete(";", Af, Bf, Cf) 101199-} 101200- 101201-type bob struct { a int } //@item(a, "a", "int", "field") 101202-type george struct { b int } 101203-type jack struct { c int } //@item(c, "c", "int", "field") 101204-type jill struct { d int } 101205- 101206-func (b *bob) george() *george {} //@item(george, "george", "func() *george", "method") 101207-func (g *george) jack() *jack {} 101208-func (j *jack) jill() *jill {} //@item(jill, "jill", "func() *jill", "method") 101209- 101210-func _() { 101211- b := &bob{} 101212- y := b.george(). 101213- jack(); 101214- y.; //@complete(";", c, jill) 101215-} 101216- 101217-func _() { 101218- bar. //@complete(" /", Bar) 101219- x := 5 101220- 101221- var b *bob 101222- b. //@complete(" /", a, george) 101223- y, z := 5, 6 101224- 101225- b. //@complete(" /", a, george) 101226- y, z, a, b, c := 5, 6 101227-} 101228- 101229-func _() { 101230- bar. //@complete(" /", Bar) 101231- bar.Bar() 101232- 101233- bar. //@complete(" /", Bar) 101234- go f() 101235-} 101236- 101237-func _() { 101238- var b *bob 101239- if y != b. //@complete(" /", a, george) 101240- z := 5 101241- 101242- if z + y + 1 + b. //@complete(" /", a, george) 101243- r, s, t := 4, 5 101244- 101245- if y != b. //@complete(" /", a, george) 101246- z = 5 101247- 101248- if z + y + 1 + b. //@complete(" /", a, george) 101249- r = 4 101250-} 101251diff -urN a/gopls/internal/lsp/testdata/semantic/a.go b/gopls/internal/lsp/testdata/semantic/a.go 101252--- a/gopls/internal/lsp/testdata/semantic/a.go 2000-01-01 00:00:00.000000000 -0000 101253+++ b/gopls/internal/lsp/testdata/semantic/a.go 1970-01-01 00:00:00.000000000 +0000 101254@@ -1,81 +0,0 @@ 101255-package semantictokens //@ semantic("") 101256- 101257-import ( 101258- _ "encoding/utf8" 101259- utf "encoding/utf8" 101260- "fmt" //@ semantic("fmt") 101261- . "fmt" 101262- "unicode/utf8" 101263-) 101264- 101265-var ( 101266- a = fmt.Print 101267- b []string = []string{"foo"} 101268- c1 chan int 101269- c2 <-chan int 101270- c3 = make([]chan<- int) 101271- b = A{X: 23} 101272- m map[bool][3]*float64 101273-) 101274- 101275-const ( 101276- xx F = iota 101277- yy = xx + 3 101278- zz = "" 101279- ww = "not " + zz 101280-) 101281- 101282-type A struct { 101283- X int `foof` 101284-} 101285-type B interface { 101286- A 101287- sad(int) bool 101288-} 101289- 101290-type F int 101291- 101292-func (a *A) f() bool { 101293- var z string 101294- x := "foo" 101295- a(x) 101296- y := "bar" + x 101297- switch z { 101298- case "xx": 101299- default: 101300- } 101301- select { 101302- case z := <-c3[0]: 101303- default: 101304- } 101305- for k, v := range m { 101306- return (!k) && v[0] == nil 101307- } 101308- c2 <- A.X 101309- w := b[4:] 101310- j := len(x) 101311- j-- 101312- q := []interface{}{j, 23i, &y} 101313- g(q...) 101314- return true 101315-} 101316- 101317-func g(vv ...interface{}) { 101318- ff := func() {} 101319- defer ff() 101320- go utf.RuneCount("") 101321- go utf8.RuneCount(vv.(string)) 101322- if true { 101323- } else { 101324- } 101325-Never: 101326- for i := 0; i < 10; { 101327- break Never 101328- } 101329- _, ok := vv[0].(A) 101330- if !ok { 101331- switch x := vv[0].(type) { 101332- } 101333- goto Never 101334- } 101335-} 101336diff -urN a/gopls/internal/lsp/testdata/semantic/a.go.golden b/gopls/internal/lsp/testdata/semantic/a.go.golden 101337--- a/gopls/internal/lsp/testdata/semantic/a.go.golden 2000-01-01 00:00:00.000000000 -0000 101338+++ b/gopls/internal/lsp/testdata/semantic/a.go.golden 1970-01-01 00:00:00.000000000 +0000 101339@@ -1,83 +0,0 @@ 101340--- semantic -- 101341-/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("") 101342- 101343-/*⇒6,keyword,[]*/import ( 101344- _ "encoding/utf8" 101345- /*⇒3,namespace,[]*/utf "encoding/utf8" 101346- "fmt"/*⇐3,namespace,[]*/ /*⇒19,comment,[]*///@ semantic("fmt") 101347- . "fmt" 101348- "unicode/utf8"/*⇐4,namespace,[]*/ 101349-) 101350- 101351-/*⇒3,keyword,[]*/var ( 101352- /*⇒1,variable,[definition]*/a = /*⇒3,namespace,[]*/fmt./*⇒5,function,[]*/Print 101353- /*⇒1,variable,[definition]*/b []/*⇒6,type,[defaultLibrary]*/string = []/*⇒6,type,[defaultLibrary]*/string{/*⇒5,string,[]*/"foo"} 101354- /*⇒2,variable,[definition]*/c1 /*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int 101355- /*⇒2,variable,[definition]*/c2 /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int 101356- /*⇒2,variable,[definition]*/c3 = /*⇒4,function,[defaultLibrary]*/make([]/*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒3,type,[defaultLibrary]*/int) 101357- /*⇒1,variable,[definition]*/b = /*⇒1,type,[]*/A{/*⇒1,variable,[]*/X: /*⇒2,number,[]*/23} 101358- /*⇒1,variable,[definition]*/m /*⇒3,keyword,[]*/map[/*⇒4,type,[defaultLibrary]*/bool][/*⇒1,number,[]*/3]/*⇒1,operator,[]*/*/*⇒7,type,[defaultLibrary]*/float64 101359-) 101360- 101361-/*⇒5,keyword,[]*/const ( 101362- /*⇒2,variable,[definition readonly]*/xx /*⇒1,type,[]*/F = /*⇒4,variable,[readonly]*/iota 101363- /*⇒2,variable,[definition readonly]*/yy = /*⇒2,variable,[readonly]*/xx /*⇒1,operator,[]*/+ /*⇒1,number,[]*/3 101364- /*⇒2,variable,[definition readonly]*/zz = /*⇒2,string,[]*/"" 101365- /*⇒2,variable,[definition readonly]*/ww = /*⇒6,string,[]*/"not " /*⇒1,operator,[]*/+ /*⇒2,variable,[readonly]*/zz 101366-) 101367- 101368-/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/A /*⇒6,keyword,[]*/struct { 101369- /*⇒1,variable,[definition]*/X /*⇒3,type,[defaultLibrary]*/int /*⇒6,string,[]*/`foof` 101370-} 101371-/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/B /*⇒9,keyword,[]*/interface { 101372- /*⇒1,type,[]*/A 101373- /*⇒3,method,[definition]*/sad(/*⇒3,type,[defaultLibrary]*/int) /*⇒4,type,[defaultLibrary]*/bool 101374-} 101375- 101376-/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/F /*⇒3,type,[defaultLibrary]*/int 101377- 101378-/*⇒4,keyword,[]*/func (/*⇒1,variable,[]*/a /*⇒1,operator,[]*/*/*⇒1,type,[]*/A) /*⇒1,method,[definition]*/f() /*⇒4,type,[defaultLibrary]*/bool { 101379- /*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/z /*⇒6,type,[defaultLibrary]*/string 101380- /*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"foo" 101381- /*⇒1,variable,[]*/a(/*⇒1,variable,[]*/x) 101382- /*⇒1,variable,[definition]*/y /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"bar" /*⇒1,operator,[]*/+ /*⇒1,variable,[]*/x 101383- /*⇒6,keyword,[]*/switch /*⇒1,variable,[]*/z { 101384- /*⇒4,keyword,[]*/case /*⇒4,string,[]*/"xx": 101385- /*⇒7,keyword,[]*/default: 101386- } 101387- /*⇒6,keyword,[]*/select { 101388- /*⇒4,keyword,[]*/case /*⇒1,variable,[definition]*/z /*⇒2,operator,[]*/:= /*⇒2,operator,[]*/<-/*⇒2,variable,[]*/c3[/*⇒1,number,[]*/0]: 101389- /*⇒7,keyword,[]*/default: 101390- } 101391- /*⇒3,keyword,[]*/for /*⇒1,variable,[definition]*/k, /*⇒1,variable,[definition]*/v := /*⇒5,keyword,[]*/range /*⇒1,variable,[]*/m { 101392- /*⇒6,keyword,[]*/return (/*⇒1,operator,[]*/!/*⇒1,variable,[]*/k) /*⇒2,operator,[]*/&& /*⇒1,variable,[]*/v[/*⇒1,number,[]*/0] /*⇒2,operator,[]*/== /*⇒3,variable,[readonly defaultLibrary]*/nil 101393- } 101394- /*⇒2,variable,[]*/c2 /*⇒2,operator,[]*/<- /*⇒1,type,[]*/A./*⇒1,variable,[]*/X 101395- /*⇒1,variable,[definition]*/w /*⇒2,operator,[]*/:= /*⇒1,variable,[]*/b[/*⇒1,number,[]*/4:] 101396- /*⇒1,variable,[definition]*/j /*⇒2,operator,[]*/:= /*⇒3,function,[defaultLibrary]*/len(/*⇒1,variable,[]*/x) 101397- /*⇒1,variable,[]*/j/*⇒2,operator,[]*/-- 101398- /*⇒1,variable,[definition]*/q /*⇒2,operator,[]*/:= []/*⇒9,keyword,[]*/interface{}{/*⇒1,variable,[]*/j, /*⇒3,number,[]*/23i, /*⇒1,operator,[]*/&/*⇒1,variable,[]*/y} 101399- /*⇒1,function,[]*/g(/*⇒1,variable,[]*/q/*⇒3,operator,[]*/...) 101400- /*⇒6,keyword,[]*/return /*⇒4,variable,[readonly]*/true 101401-} 101402- 101403-/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/g(/*⇒2,parameter,[definition]*/vv /*⇒3,operator,[]*/.../*⇒9,keyword,[]*/interface{}) { 101404- /*⇒2,variable,[definition]*/ff /*⇒2,operator,[]*/:= /*⇒4,keyword,[]*/func() {} 101405- /*⇒5,keyword,[]*/defer /*⇒2,function,[]*/ff() 101406- /*⇒2,keyword,[]*/go /*⇒3,namespace,[]*/utf./*⇒9,function,[]*/RuneCount(/*⇒2,string,[]*/"") 101407- /*⇒2,keyword,[]*/go /*⇒4,namespace,[]*/utf8./*⇒9,function,[]*/RuneCount(/*⇒2,parameter,[]*/vv.(/*⇒6,type,[]*/string)) 101408- /*⇒2,keyword,[]*/if /*⇒4,variable,[readonly]*/true { 101409- } /*⇒4,keyword,[]*/else { 101410- } 101411-/*⇒5,parameter,[definition]*/Never: 101412- /*⇒3,keyword,[]*/for /*⇒1,variable,[definition]*/i /*⇒2,operator,[]*/:= /*⇒1,number,[]*/0; /*⇒1,variable,[]*/i /*⇒1,operator,[]*/< /*⇒2,number,[]*/10; { 101413- /*⇒5,keyword,[]*/break Never 101414- } 101415- _, /*⇒2,variable,[definition]*/ok /*⇒2,operator,[]*/:= /*⇒2,parameter,[]*/vv[/*⇒1,number,[]*/0].(/*⇒1,type,[]*/A) 101416- /*⇒2,keyword,[]*/if /*⇒1,operator,[]*/!/*⇒2,variable,[]*/ok { 101417- /*⇒6,keyword,[]*/switch /*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒2,parameter,[]*/vv[/*⇒1,number,[]*/0].(/*⇒4,keyword,[]*/type) { 101418- } 101419- /*⇒4,keyword,[]*/goto Never 101420- } 101421-} 101422- 101423diff -urN a/gopls/internal/lsp/testdata/semantic/b.go b/gopls/internal/lsp/testdata/semantic/b.go 101424--- a/gopls/internal/lsp/testdata/semantic/b.go 2000-01-01 00:00:00.000000000 -0000 101425+++ b/gopls/internal/lsp/testdata/semantic/b.go 1970-01-01 00:00:00.000000000 +0000 101426@@ -1,38 +0,0 @@ 101427-package semantictokens //@ semantic("") 101428- 101429-func f(x ...interface{}) { 101430-} 101431- 101432-func weirⰀd() { /**/ // comment 101433- const ( 101434- snil = nil 101435- nil = true 101436- true = false 101437- false = snil 101438- cmd = `foof` 101439- double = iota 101440- iota = copy 101441- four = (len(cmd)/2 < 5) 101442- five = four 101443- ) 101444- f(cmd, nil, double, iota) 101445-} 101446- 101447-/* 101448- 101449-multiline */ /* 101450-multiline 101451-*/ 101452-type AA int 101453-type BB struct { 101454- AA 101455-} 101456-type CC struct { 101457- AA int 101458-} 101459-type D func(aa AA) (BB error) 101460-type E func(AA) BB 101461- 101462-var a chan<- chan int 101463-var b chan<- <-chan int 101464-var c <-chan <-chan int 101465diff -urN a/gopls/internal/lsp/testdata/semantic/b.go.golden b/gopls/internal/lsp/testdata/semantic/b.go.golden 101466--- a/gopls/internal/lsp/testdata/semantic/b.go.golden 2000-01-01 00:00:00.000000000 -0000 101467+++ b/gopls/internal/lsp/testdata/semantic/b.go.golden 1970-01-01 00:00:00.000000000 +0000 101468@@ -1,40 +0,0 @@ 101469--- semantic -- 101470-/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("") 101471- 101472-/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/f(/*⇒1,parameter,[definition]*/x /*⇒3,operator,[]*/.../*⇒9,keyword,[]*/interface{}) { 101473-} 101474- 101475-/*⇒4,keyword,[]*/func /*⇒6,function,[definition]*/weirⰀd() { /*⇒5,comment,[]*//**/ /*⇒10,comment,[]*/// comment 101476- /*⇒5,keyword,[]*/const ( 101477- /*⇒4,variable,[definition readonly]*/snil = /*⇒3,variable,[readonly defaultLibrary]*/nil 101478- /*⇒3,variable,[definition readonly]*/nil = /*⇒4,variable,[readonly]*/true 101479- /*⇒4,variable,[definition readonly]*/true = /*⇒5,variable,[readonly]*/false 101480- /*⇒5,variable,[definition readonly]*/false = /*⇒4,variable,[readonly]*/snil 101481- /*⇒3,variable,[definition readonly]*/cmd = /*⇒6,string,[]*/`foof` 101482- /*⇒6,variable,[definition readonly]*/double = /*⇒4,variable,[readonly]*/iota 101483- /*⇒4,variable,[definition readonly]*/iota = /*⇒4,function,[defaultLibrary]*/copy 101484- /*⇒4,variable,[definition readonly]*/four = (/*⇒3,function,[defaultLibrary]*/len(/*⇒3,variable,[readonly]*/cmd)/*⇒1,operator,[]*// /*⇒1,number,[]*/2 /*⇒1,operator,[]*/< /*⇒1,number,[]*/5) 101485- /*⇒4,variable,[definition readonly]*/five = /*⇒4,variable,[readonly]*/four 101486- ) 101487- /*⇒1,function,[]*/f(/*⇒3,variable,[readonly]*/cmd, /*⇒3,variable,[readonly]*/nil, /*⇒6,variable,[readonly]*/double, /*⇒4,variable,[readonly]*/iota) 101488-} 101489- 101490-/*⇒2,comment,[]*//* 101491-/*⇒0,comment,[]*/ 101492-/*⇒12,comment,[]*/multiline */ /*⇒2,comment,[]*//* 101493-/*⇒9,comment,[]*/multiline 101494-/*⇒2,comment,[]*/*/ 101495-/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int 101496-/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/BB /*⇒6,keyword,[]*/struct { 101497- /*⇒2,type,[]*/AA 101498-} 101499-/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/CC /*⇒6,keyword,[]*/struct { 101500- /*⇒2,variable,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int 101501-} 101502-/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/D /*⇒4,keyword,[]*/func(/*⇒2,parameter,[definition]*/aa /*⇒2,type,[]*/AA) (/*⇒2,parameter,[definition]*/BB /*⇒5,type,[]*/error) 101503-/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/E /*⇒4,keyword,[]*/func(/*⇒2,type,[]*/AA) /*⇒2,type,[]*/BB 101504- 101505-/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/a /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int 101506-/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/b /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int 101507-/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/c /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int 101508- 101509diff -urN a/gopls/internal/lsp/testdata/semantic/README.md b/gopls/internal/lsp/testdata/semantic/README.md 101510--- a/gopls/internal/lsp/testdata/semantic/README.md 2000-01-01 00:00:00.000000000 -0000 101511+++ b/gopls/internal/lsp/testdata/semantic/README.md 1970-01-01 00:00:00.000000000 +0000 101512@@ -1,2 +0,0 @@ 101513-The golden files are the output of `gopls semtok <src-file>`, with `-- semantic --` 101514-inserted as the first line (the spaces are mandatory) and an extra newline at the end. 101515diff -urN a/gopls/internal/lsp/testdata/semantic/semantic_test.go b/gopls/internal/lsp/testdata/semantic/semantic_test.go 101516--- a/gopls/internal/lsp/testdata/semantic/semantic_test.go 2000-01-01 00:00:00.000000000 -0000 101517+++ b/gopls/internal/lsp/testdata/semantic/semantic_test.go 1970-01-01 00:00:00.000000000 +0000 101518@@ -1,13 +0,0 @@ 101519-package semantictokens 101520- 101521-import ( 101522- "os" 101523- "testing" 101524-) 101525- 101526-func TestSemanticTokens(t *testing.T) { 101527- a, _ := os.Getwd() 101528- // climb up to find internal/lsp 101529- // find all the .go files 101530- 101531-} 101532diff -urN a/gopls/internal/lsp/testdata/signature/signature2.go.golden b/gopls/internal/lsp/testdata/signature/signature2.go.golden 101533--- a/gopls/internal/lsp/testdata/signature/signature2.go.golden 2000-01-01 00:00:00.000000000 -0000 101534+++ b/gopls/internal/lsp/testdata/signature/signature2.go.golden 1970-01-01 00:00:00.000000000 +0000 101535@@ -1,3 +0,0 @@ 101536--- Foo(a string, b int) (c bool)-signature -- 101537-Foo(a string, b int) (c bool) 101538- 101539diff -urN a/gopls/internal/lsp/testdata/signature/signature2.go.in b/gopls/internal/lsp/testdata/signature/signature2.go.in 101540--- a/gopls/internal/lsp/testdata/signature/signature2.go.in 2000-01-01 00:00:00.000000000 -0000 101541+++ b/gopls/internal/lsp/testdata/signature/signature2.go.in 1970-01-01 00:00:00.000000000 +0000 101542@@ -1,5 +0,0 @@ 101543-package signature 101544- 101545-func _() { 101546- Foo(//@signature("//", "Foo(a string, b int) (c bool)", 0) 101547-} 101548diff -urN a/gopls/internal/lsp/testdata/signature/signature3.go.golden b/gopls/internal/lsp/testdata/signature/signature3.go.golden 101549--- a/gopls/internal/lsp/testdata/signature/signature3.go.golden 2000-01-01 00:00:00.000000000 -0000 101550+++ b/gopls/internal/lsp/testdata/signature/signature3.go.golden 1970-01-01 00:00:00.000000000 +0000 101551@@ -1,3 +0,0 @@ 101552--- Foo(a string, b int) (c bool)-signature -- 101553-Foo(a string, b int) (c bool) 101554- 101555diff -urN a/gopls/internal/lsp/testdata/signature/signature3.go.in b/gopls/internal/lsp/testdata/signature/signature3.go.in 101556--- a/gopls/internal/lsp/testdata/signature/signature3.go.in 2000-01-01 00:00:00.000000000 -0000 101557+++ b/gopls/internal/lsp/testdata/signature/signature3.go.in 1970-01-01 00:00:00.000000000 +0000 101558@@ -1,5 +0,0 @@ 101559-package signature 101560- 101561-func _() { 101562- Foo("hello",//@signature("//", "Foo(a string, b int) (c bool)", 1) 101563-} 101564\ No newline at end of file 101565diff -urN a/gopls/internal/lsp/testdata/signature/signature.go b/gopls/internal/lsp/testdata/signature/signature.go 101566--- a/gopls/internal/lsp/testdata/signature/signature.go 2000-01-01 00:00:00.000000000 -0000 101567+++ b/gopls/internal/lsp/testdata/signature/signature.go 1970-01-01 00:00:00.000000000 +0000 101568@@ -1,85 +0,0 @@ 101569-// Package signature has tests for signature help. 101570-package signature 101571- 101572-import ( 101573- "bytes" 101574- "encoding/json" 101575- "math/big" 101576-) 101577- 101578-func Foo(a string, b int) (c bool) { 101579- return 101580-} 101581- 101582-func Bar(float64, ...byte) { 101583-} 101584- 101585-type myStruct struct{} 101586- 101587-func (*myStruct) foo(e *json.Decoder) (*big.Int, error) { 101588- return nil, nil 101589-} 101590- 101591-type MyType struct{} 101592- 101593-type MyFunc func(foo int) string 101594- 101595-type Alias = int 101596-type OtherAlias = int 101597-type StringAlias = string 101598- 101599-func AliasSlice(a []*Alias) (b Alias) { return 0 } 101600-func AliasMap(a map[*Alias]StringAlias) (b, c map[*Alias]StringAlias) { return nil, nil } 101601-func OtherAliasMap(a, b map[Alias]OtherAlias) map[Alias]OtherAlias { return nil } 101602- 101603-func Qux() { 101604- Foo("foo", 123) //@signature("(", "Foo(a string, b int) (c bool)", 0) 101605- Foo("foo", 123) //@signature("123", "Foo(a string, b int) (c bool)", 1) 101606- Foo("foo", 123) //@signature(",", "Foo(a string, b int) (c bool)", 0) 101607- Foo("foo", 123) //@signature(" 1", "Foo(a string, b int) (c bool)", 1) 101608- Foo("foo", 123) //@signature(")", "Foo(a string, b int) (c bool)", 1) 101609- 101610- Bar(13.37, 0x13) //@signature("13.37", "Bar(float64, ...byte)", 0) 101611- Bar(13.37, 0x37) //@signature("0x37", "Bar(float64, ...byte)", 1) 101612- Bar(13.37, 1, 2, 3, 4) //@signature("4", "Bar(float64, ...byte)", 1) 101613- 101614- fn := func(hi, there string) func(i int) rune { 101615- return func(int) rune { return 0 } 101616- } 101617- 101618- fn("hi", "there") //@signature("hi", "", 0) 101619- fn("hi", "there") //@signature(",", "fn(hi string, there string) func(i int) rune", 0) 101620- fn("hi", "there")(1) //@signature("1", "func(i int) rune", 0) 101621- 101622- fnPtr := &fn 101623- (*fnPtr)("hi", "there") //@signature(",", "func(hi string, there string) func(i int) rune", 0) 101624- 101625- var fnIntf interface{} = Foo 101626- fnIntf.(func(string, int) bool)("hi", 123) //@signature("123", "func(string, int) bool", 1) 101627- 101628- (&bytes.Buffer{}).Next(2) //@signature("2", "Next(n int) []byte", 0) 101629- 101630- myFunc := MyFunc(func(n int) string { return "" }) 101631- myFunc(123) //@signature("123", "myFunc(foo int) string", 0) 101632- 101633- var ms myStruct 101634- ms.foo(nil) //@signature("nil", "foo(e *json.Decoder) (*big.Int, error)", 0) 101635- 101636- _ = make([]int, 1, 2) //@signature("2", "make(t Type, size ...int) Type", 1) 101637- 101638- Foo(myFunc(123), 456) //@signature("myFunc", "Foo(a string, b int) (c bool)", 0) 101639- Foo(myFunc(123), 456) //@signature("123", "myFunc(foo int) string", 0) 101640- 101641- panic("oops!") //@signature(")", "panic(v interface{})", 0) 101642- println("hello", "world") //@signature(",", "println(args ...Type)", 0) 101643- 101644- Hello(func() { 101645- //@signature("//", "", 0) 101646- }) 101647- 101648- AliasSlice() //@signature(")", "AliasSlice(a []*Alias) (b Alias)", 0) 101649- AliasMap() //@signature(")", "AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)", 0) 101650- OtherAliasMap() //@signature(")", "OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias", 0) 101651-} 101652- 101653-func Hello(func()) {} 101654diff -urN a/gopls/internal/lsp/testdata/signature/signature.go.golden b/gopls/internal/lsp/testdata/signature/signature.go.golden 101655--- a/gopls/internal/lsp/testdata/signature/signature.go.golden 2000-01-01 00:00:00.000000000 -0000 101656+++ b/gopls/internal/lsp/testdata/signature/signature.go.golden 1970-01-01 00:00:00.000000000 +0000 101657@@ -1,53 +0,0 @@ 101658--- AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)-signature -- 101659-AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias) 101660- 101661--- AliasSlice(a []*Alias) (b Alias)-signature -- 101662-AliasSlice(a []*Alias) (b Alias) 101663- 101664--- Bar(float64, ...byte)-signature -- 101665-Bar(float64, ...byte) 101666- 101667--- Foo(a string, b int) (c bool)-signature -- 101668-Foo(a string, b int) (c bool) 101669- 101670--- Next(n int) []byte-signature -- 101671-Next(n int) []byte 101672- 101673-Next returns a slice containing the next n bytes from the buffer, advancing the buffer as if the bytes had been returned by Read. 101674- 101675--- OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias-signature -- 101676-OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias 101677- 101678--- fn(hi string, there string) func(i int) rune-signature -- 101679-fn(hi string, there string) func(i int) rune 101680- 101681--- foo(e *json.Decoder) (*big.Int, error)-signature -- 101682-foo(e *json.Decoder) (*big.Int, error) 101683- 101684--- func(hi string, there string) func(i int) rune-signature -- 101685-func(hi string, there string) func(i int) rune 101686- 101687--- func(i int) rune-signature -- 101688-func(i int) rune 101689- 101690--- func(string, int) bool-signature -- 101691-func(string, int) bool 101692- 101693--- make(t Type, size ...int) Type-signature -- 101694-make(t Type, size ...int) Type 101695- 101696-The make built-in function allocates and initializes an object of type slice, map, or chan (only). 101697- 101698--- myFunc(foo int) string-signature -- 101699-myFunc(foo int) string 101700- 101701--- panic(v interface{})-signature -- 101702-panic(v any) 101703- 101704-The panic built-in function stops normal execution of the current goroutine. 101705- 101706--- println(args ...Type)-signature -- 101707-println(args ...Type) 101708- 101709-The println built-in function formats its arguments in an implementation-specific way and writes the result to standard error. 101710- 101711diff -urN a/gopls/internal/lsp/testdata/signature/signature_test.go b/gopls/internal/lsp/testdata/signature/signature_test.go 101712--- a/gopls/internal/lsp/testdata/signature/signature_test.go 2000-01-01 00:00:00.000000000 -0000 101713+++ b/gopls/internal/lsp/testdata/signature/signature_test.go 1970-01-01 00:00:00.000000000 +0000 101714@@ -1,13 +0,0 @@ 101715-package signature_test 101716- 101717-import ( 101718- "testing" 101719- 101720- sig "golang.org/lsptests/signature" 101721-) 101722- 101723-func TestSignature(t *testing.T) { 101724- sig.AliasSlice() //@signature(")", "AliasSlice(a []*sig.Alias) (b sig.Alias)", 0) 101725- sig.AliasMap() //@signature(")", "AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)", 0) 101726- sig.OtherAliasMap() //@signature(")", "OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias", 0) 101727-} 101728diff -urN a/gopls/internal/lsp/testdata/signature/signature_test.go.golden b/gopls/internal/lsp/testdata/signature/signature_test.go.golden 101729--- a/gopls/internal/lsp/testdata/signature/signature_test.go.golden 2000-01-01 00:00:00.000000000 -0000 101730+++ b/gopls/internal/lsp/testdata/signature/signature_test.go.golden 1970-01-01 00:00:00.000000000 +0000 101731@@ -1,9 +0,0 @@ 101732--- AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)-signature -- 101733-AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias) 101734- 101735--- AliasSlice(a []*sig.Alias) (b sig.Alias)-signature -- 101736-AliasSlice(a []*sig.Alias) (b sig.Alias) 101737- 101738--- OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias-signature -- 101739-OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias 101740- 101741diff -urN a/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in 101742--- a/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in 2000-01-01 00:00:00.000000000 -0000 101743+++ b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in 1970-01-01 00:00:00.000000000 +0000 101744@@ -1,19 +0,0 @@ 101745-// +build go1.18 101746-//go:build go1.18 101747- 101748-package snippets 101749- 101750-type SyncMap[K comparable, V any] struct{} 101751- 101752-func NewSyncMap[K comparable, V any]() (result *SyncMap[K, V]) { //@item(NewSyncMap, "NewSyncMap", "", "") 101753- return 101754-} 101755- 101756-func Identity[P ~int](p P) P { //@item(Identity, "Identity", "", "") 101757- return p 101758-} 101759- 101760-func _() { 101761- _ = NewSyncM //@snippet(" //", NewSyncMap, "NewSyncMap[${1:}]()", "NewSyncMap[${1:K comparable}, ${2:V any}]()") 101762- _ = Identi //@snippet(" //", Identity, "Identity[${1:}](${2:})", "Identity[${1:P ~int}](${2:p P})") 101763-} 101764diff -urN a/gopls/internal/lsp/testdata/snippets/literal.go b/gopls/internal/lsp/testdata/snippets/literal.go 101765--- a/gopls/internal/lsp/testdata/snippets/literal.go 2000-01-01 00:00:00.000000000 -0000 101766+++ b/gopls/internal/lsp/testdata/snippets/literal.go 1970-01-01 00:00:00.000000000 +0000 101767@@ -1,22 +0,0 @@ 101768-package snippets 101769- 101770-import ( 101771- "golang.org/lsptests/signature" 101772- t "golang.org/lsptests/types" 101773-) 101774- 101775-type structy struct { 101776- x signature.MyType 101777-} 101778- 101779-func X(_ map[signature.Alias]t.CoolAlias) (map[signature.Alias]t.CoolAlias) { 101780- return nil 101781-} 101782- 101783-func _() { 101784- X() //@signature(")", "X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias", 0) 101785- _ = signature.MyType{} //@item(literalMyType, "signature.MyType{}", "", "var") 101786- s := structy{ 101787- x: //@snippet(" //", literalMyType, "signature.MyType{\\}", "signature.MyType{\\}") 101788- } 101789-} 101790\ No newline at end of file 101791diff -urN a/gopls/internal/lsp/testdata/snippets/literal.go.golden b/gopls/internal/lsp/testdata/snippets/literal.go.golden 101792--- a/gopls/internal/lsp/testdata/snippets/literal.go.golden 2000-01-01 00:00:00.000000000 -0000 101793+++ b/gopls/internal/lsp/testdata/snippets/literal.go.golden 1970-01-01 00:00:00.000000000 +0000 101794@@ -1,3 +0,0 @@ 101795--- X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias-signature -- 101796-X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias 101797- 101798diff -urN a/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in 101799--- a/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in 2000-01-01 00:00:00.000000000 -0000 101800+++ b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in 1970-01-01 00:00:00.000000000 +0000 101801@@ -1,14 +0,0 @@ 101802-// +build go1.18 101803-//go:build go1.18 101804- 101805-package snippets 101806- 101807-type Tree[T any] struct{} 101808- 101809-func (tree Tree[T]) Do(f func(s T)) {} 101810- 101811-func _() { 101812- _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var") 101813- var t Tree[string] 101814- t.Do(fun) //@complete(")", litFunc),snippet(")", litFunc, "func(s string) {$0\\}", "func(s string) {$0\\}") 101815-} 101816diff -urN a/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in 101817--- a/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in 2000-01-01 00:00:00.000000000 -0000 101818+++ b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in 1970-01-01 00:00:00.000000000 +0000 101819@@ -1,233 +0,0 @@ 101820-package snippets 101821- 101822-import ( 101823- "bytes" 101824- "context" 101825- "go/ast" 101826- "net/http" 101827- "sort" 101828- 101829- "golang.org/lsptests/foo" 101830-) 101831- 101832-func _() { 101833- []int{} //@item(litIntSlice, "[]int{}", "", "var") 101834- &[]int{} //@item(litIntSliceAddr, "&[]int{}", "", "var") 101835- make([]int, 0) //@item(makeIntSlice, "make([]int, 0)", "", "func") 101836- 101837- var _ *[]int = in //@snippet(" //", litIntSliceAddr, "&[]int{$0\\}", "&[]int{$0\\}") 101838- var _ **[]int = in //@complete(" //") 101839- 101840- var slice []int 101841- slice = i //@snippet(" //", litIntSlice, "[]int{$0\\}", "[]int{$0\\}") 101842- slice = m //@snippet(" //", makeIntSlice, "make([]int, ${1:})", "make([]int, ${1:0})") 101843-} 101844- 101845-func _() { 101846- type namedInt []int 101847- 101848- namedInt{} //@item(litNamedSlice, "namedInt{}", "", "var") 101849- make(namedInt, 0) //@item(makeNamedSlice, "make(namedInt, 0)", "", "func") 101850- 101851- var namedSlice namedInt 101852- namedSlice = n //@snippet(" //", litNamedSlice, "namedInt{$0\\}", "namedInt{$0\\}") 101853- namedSlice = m //@snippet(" //", makeNamedSlice, "make(namedInt, ${1:})", "make(namedInt, ${1:0})") 101854-} 101855- 101856-func _() { 101857- make(chan int) //@item(makeChan, "make(chan int)", "", "func") 101858- 101859- var ch chan int 101860- ch = m //@snippet(" //", makeChan, "make(chan int)", "make(chan int)") 101861-} 101862- 101863-func _() { 101864- map[string]struct{}{} //@item(litMap, "map[string]struct{}{}", "", "var") 101865- make(map[string]struct{}) //@item(makeMap, "make(map[string]struct{})", "", "func") 101866- 101867- var m map[string]struct{} 101868- m = m //@snippet(" //", litMap, "map[string]struct{\\}{$0\\}", "map[string]struct{\\}{$0\\}") 101869- m = m //@snippet(" //", makeMap, "make(map[string]struct{\\})", "make(map[string]struct{\\})") 101870- 101871- struct{}{} //@item(litEmptyStruct, "struct{}{}", "", "var") 101872- 101873- m["hi"] = s //@snippet(" //", litEmptyStruct, "struct{\\}{\\}", "struct{\\}{\\}") 101874-} 101875- 101876-func _() { 101877- type myStruct struct{ i int } //@item(myStructType, "myStruct", "struct{...}", "struct") 101878- 101879- myStruct{} //@item(litStruct, "myStruct{}", "", "var") 101880- &myStruct{} //@item(litStructPtr, "&myStruct{}", "", "var") 101881- 101882- var ms myStruct 101883- ms = m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}") 101884- 101885- var msPtr *myStruct 101886- msPtr = m //@snippet(" //", litStructPtr, "&myStruct{$0\\}", "&myStruct{$0\\}") 101887- 101888- msPtr = &m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}") 101889- 101890- type myStructCopy struct { i int } //@item(myStructCopyType, "myStructCopy", "struct{...}", "struct") 101891- 101892- // Don't offer literal completion for convertible structs. 101893- ms = myStruct //@complete(" //", litStruct, myStructType, myStructCopyType) 101894-} 101895- 101896-type myImpl struct{} 101897- 101898-func (myImpl) foo() {} 101899- 101900-func (*myImpl) bar() {} 101901- 101902-type myBasicImpl string 101903- 101904-func (myBasicImpl) foo() {} 101905- 101906-func _() { 101907- type myIntf interface { 101908- foo() 101909- } 101910- 101911- myImpl{} //@item(litImpl, "myImpl{}", "", "var") 101912- 101913- var mi myIntf 101914- mi = m //@snippet(" //", litImpl, "myImpl{\\}", "myImpl{\\}") 101915- 101916- myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var") 101917- 101918- mi = m //@snippet(" //", litBasicImpl, "myBasicImpl($0)", "myBasicImpl($0)") 101919- 101920- // only satisfied by pointer to myImpl 101921- type myPtrIntf interface { 101922- bar() 101923- } 101924- 101925- &myImpl{} //@item(litImplPtr, "&myImpl{}", "", "var") 101926- 101927- var mpi myPtrIntf 101928- mpi = m //@snippet(" //", litImplPtr, "&myImpl{\\}", "&myImpl{\\}") 101929-} 101930- 101931-func _() { 101932- var s struct{ i []int } //@item(litSliceField, "i", "[]int", "field") 101933- var foo []int 101934- // no literal completions after selector 101935- foo = s.i //@complete(" //", litSliceField) 101936-} 101937- 101938-func _() { 101939- type myStruct struct{ i int } //@item(litMyStructType, "myStruct", "struct{...}", "struct") 101940- myStruct{} //@item(litMyStruct, "myStruct{}", "", "var") 101941- 101942- foo := func(s string, args ...myStruct) {} 101943- // Don't give literal slice candidate for variadic arg. 101944- // Do give literal candidates for variadic element. 101945- foo("", myStruct) //@complete(")", litMyStruct, litMyStructType) 101946-} 101947- 101948-func _() { 101949- Buffer{} //@item(litBuffer, "Buffer{}", "", "var") 101950- 101951- var b *bytes.Buffer 101952- b = bytes.Bu //@snippet(" //", litBuffer, "Buffer{\\}", "Buffer{\\}") 101953-} 101954- 101955-func _() { 101956- _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var") 101957- 101958- sort.Slice(nil, fun) //@complete(")", litFunc),snippet(")", litFunc, "func(i, j int) bool {$0\\}", "func(i, j int) bool {$0\\}") 101959- 101960- http.HandleFunc("", f) //@snippet(")", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}") 101961- 101962- // no literal "func" completions 101963- http.Handle("", fun) //@complete(")") 101964- 101965- http.HandlerFunc() //@item(handlerFunc, "http.HandlerFunc()", "", "var") 101966- http.Handle("", h) //@snippet(")", handlerFunc, "http.HandlerFunc($0)", "http.HandlerFunc($0)") 101967- http.Handle("", http.HandlerFunc()) //@snippet("))", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}") 101968- 101969- var namedReturn func(s string) (b bool) 101970- namedReturn = f //@snippet(" //", litFunc, "func(s string) (b bool) {$0\\}", "func(s string) (b bool) {$0\\}") 101971- 101972- var multiReturn func() (bool, int) 101973- multiReturn = f //@snippet(" //", litFunc, "func() (bool, int) {$0\\}", "func() (bool, int) {$0\\}") 101974- 101975- var multiNamedReturn func() (b bool, i int) 101976- multiNamedReturn = f //@snippet(" //", litFunc, "func() (b bool, i int) {$0\\}", "func() (b bool, i int) {$0\\}") 101977- 101978- var duplicateParams func(myImpl, int, myImpl) 101979- duplicateParams = f //@snippet(" //", litFunc, "func(mi1 myImpl, i int, mi2 myImpl) {$0\\}", "func(${1:mi1} myImpl, ${2:i} int, ${3:mi2} myImpl) {$0\\}") 101980- 101981- type aliasImpl = myImpl 101982- var aliasParams func(aliasImpl) aliasImpl 101983- aliasParams = f //@snippet(" //", litFunc, "func(ai aliasImpl) aliasImpl {$0\\}", "func(${1:ai} aliasImpl) aliasImpl {$0\\}") 101984- 101985- const two = 2 101986- var builtinTypes func([]int, [two]bool, map[string]string, struct{ i int }, interface{ foo() }, <-chan int) 101987- builtinTypes = f //@snippet(" //", litFunc, "func(i1 []int, b [two]bool, m map[string]string, s struct{ i int \\}, i2 interface{ foo() \\}, c <-chan int) {$0\\}", "func(${1:i1} []int, ${2:b} [two]bool, ${3:m} map[string]string, ${4:s} struct{ i int \\}, ${5:i2} interface{ foo() \\}, ${6:c} <-chan int) {$0\\}") 101988- 101989- var _ func(ast.Node) = f //@snippet(" //", litFunc, "func(n ast.Node) {$0\\}", "func(${1:n} ast.Node) {$0\\}") 101990- var _ func(error) = f //@snippet(" //", litFunc, "func(err error) {$0\\}", "func(${1:err} error) {$0\\}") 101991- var _ func(context.Context) = f //@snippet(" //", litFunc, "func(ctx context.Context) {$0\\}", "func(${1:ctx} context.Context) {$0\\}") 101992- 101993- type context struct {} 101994- var _ func(context) = f //@snippet(" //", litFunc, "func(ctx context) {$0\\}", "func(${1:ctx} context) {$0\\}") 101995-} 101996- 101997-func _() { 101998- StructFoo{} //@item(litStructFoo, "StructFoo{}", "struct{...}", "struct") 101999- 102000- var sfp *foo.StructFoo 102001- // Don't insert the "&" before "StructFoo{}". 102002- sfp = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") 102003- 102004- var sf foo.StructFoo 102005- sf = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") 102006- sf = foo. //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") 102007-} 102008- 102009-func _() { 102010- float64() //@item(litFloat64, "float64()", "float64", "var") 102011- 102012- // don't complete to "&float64()" 102013- var _ *float64 = float64 //@complete(" //") 102014- 102015- var f float64 102016- f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)", "float64($0)") 102017- 102018- type myInt int 102019- myInt() //@item(litMyInt, "myInt()", "", "var") 102020- 102021- var mi myInt 102022- mi = my //@snippet(" //", litMyInt, "myInt($0)", "myInt($0)") 102023-} 102024- 102025-func _() { 102026- type ptrStruct struct { 102027- p *ptrStruct 102028- } 102029- 102030- ptrStruct{} //@item(litPtrStruct, "ptrStruct{}", "", "var") 102031- 102032- ptrStruct{ 102033- p: &ptrSt, //@rank(",", litPtrStruct) 102034- } 102035- 102036- &ptrStruct{} //@item(litPtrStructPtr, "&ptrStruct{}", "", "var") 102037- 102038- &ptrStruct{ 102039- p: ptrSt, //@rank(",", litPtrStructPtr) 102040- } 102041-} 102042- 102043-func _() { 102044- f := func(...[]int) {} 102045- f() //@snippet(")", litIntSlice, "[]int{$0\\}", "[]int{$0\\}") 102046-} 102047- 102048- 102049-func _() { 102050- // don't complete to "untyped int()" 102051- []int{}[untyped] //@complete("] //") 102052-} 102053diff -urN a/gopls/internal/lsp/testdata/snippets/postfix.go b/gopls/internal/lsp/testdata/snippets/postfix.go 102054--- a/gopls/internal/lsp/testdata/snippets/postfix.go 2000-01-01 00:00:00.000000000 -0000 102055+++ b/gopls/internal/lsp/testdata/snippets/postfix.go 1970-01-01 00:00:00.000000000 +0000 102056@@ -1,42 +0,0 @@ 102057-package snippets 102058- 102059-// These tests check that postfix completions do and do not show up in 102060-// certain cases. Tests for the postfix completion contents are under 102061-// regtest. 102062- 102063-func _() { 102064- /* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet") 102065- var foo []int 102066- foo.append //@rank(" //", postfixAppend) 102067- 102068- []int{}.append //@complete(" //") 102069- 102070- []int{}.last //@complete(" //") 102071- 102072- /* copy! */ //@item(postfixCopy, "copy!", "duplicate slice", "snippet") 102073- 102074- foo.copy //@rank(" //", postfixCopy) 102075- 102076- var s struct{ i []int } 102077- s.i.copy //@rank(" //", postfixCopy) 102078- 102079- var _ []int = s.i.copy //@complete(" //") 102080- 102081- var blah func() []int 102082- blah().append //@complete(" //") 102083-} 102084- 102085-func _() { 102086- /* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet") 102087- /* last! */ //@item(postfixLast, "last!", "s[len(s)-1]", "snippet") 102088- /* print! */ //@item(postfixPrint, "print!", "print to stdout", "snippet") 102089- /* range! */ //@item(postfixRange, "range!", "range over slice", "snippet") 102090- /* reverse! */ //@item(postfixReverse, "reverse!", "reverse slice", "snippet") 102091- /* sort! */ //@item(postfixSort, "sort!", "sort.Slice()", "snippet") 102092- /* var! */ //@item(postfixVar, "var!", "assign to variable", "snippet") 102093- 102094- var foo []int 102095- foo. //@complete(" //", postfixAppend, postfixCopy, postfixLast, postfixPrint, postfixRange, postfixReverse, postfixSort, postfixVar) 102096- 102097- foo = nil 102098-} 102099diff -urN a/gopls/internal/lsp/testdata/snippets/snippets.go.golden b/gopls/internal/lsp/testdata/snippets/snippets.go.golden 102100--- a/gopls/internal/lsp/testdata/snippets/snippets.go.golden 2000-01-01 00:00:00.000000000 -0000 102101+++ b/gopls/internal/lsp/testdata/snippets/snippets.go.golden 1970-01-01 00:00:00.000000000 +0000 102102@@ -1,3 +0,0 @@ 102103--- baz(at AliasType, b bool)-signature -- 102104-baz(at AliasType, b bool) 102105- 102106diff -urN a/gopls/internal/lsp/testdata/snippets/snippets.go.in b/gopls/internal/lsp/testdata/snippets/snippets.go.in 102107--- a/gopls/internal/lsp/testdata/snippets/snippets.go.in 2000-01-01 00:00:00.000000000 -0000 102108+++ b/gopls/internal/lsp/testdata/snippets/snippets.go.in 1970-01-01 00:00:00.000000000 +0000 102109@@ -1,61 +0,0 @@ 102110-package snippets 102111- 102112-type AliasType = int //@item(sigAliasType, "AliasType", "AliasType", "type") 102113- 102114-func foo(i int, b bool) {} //@item(snipFoo, "foo", "func(i int, b bool)", "func") 102115-func bar(fn func()) func() {} //@item(snipBar, "bar", "func(fn func())", "func") 102116-func baz(at AliasType, b bool) {} //@item(snipBaz, "baz", "func(at AliasType, b bool)", "func") 102117- 102118-type Foo struct { 102119- Bar int //@item(snipFieldBar, "Bar", "int", "field") 102120- Func func(at AliasType) error //@item(snipFieldFunc, "Func", "func(at AliasType) error", "field") 102121-} 102122- 102123-func (Foo) Baz() func() {} //@item(snipMethodBaz, "Baz", "func() func()", "method") 102124-func (Foo) BazBar() func() {} //@item(snipMethodBazBar, "BazBar", "func() func()", "method") 102125-func (Foo) BazBaz(at AliasType) func() {} //@item(snipMethodBazBaz, "BazBaz", "func(at AliasType) func()", "method") 102126- 102127-func _() { 102128- f //@snippet(" //", snipFoo, "foo(${1:})", "foo(${1:i int}, ${2:b bool})") 102129- 102130- bar //@snippet(" //", snipBar, "bar(${1:})", "bar(${1:fn func()})") 102131- 102132- baz //@snippet(" //", snipBaz, "baz(${1:})", "baz(${1:at AliasType}, ${2:b bool})") 102133- baz() //@signature("(", "baz(at AliasType, b bool)", 0) 102134- 102135- bar(nil) //@snippet("(", snipBar, "bar", "bar") 102136- bar(ba) //@snippet(")", snipBar, "bar(${1:})", "bar(${1:fn func()})") 102137- var f Foo 102138- bar(f.Ba) //@snippet(")", snipMethodBaz, "Baz()", "Baz()") 102139- (bar)(nil) //@snippet(")", snipBar, "bar(${1:})", "bar(${1:fn func()})") 102140- (f.Ba)() //@snippet(")", snipMethodBaz, "Baz()", "Baz()") 102141- 102142- Foo{ 102143- B //@snippet(" //", snipFieldBar, "Bar: ${1:},", "Bar: ${1:int},") 102144- } 102145- 102146- Foo{ 102147- F //@snippet(" //", snipFieldFunc, "Func: ${1:},", "Func: ${1:func(at AliasType) error},") 102148- } 102149- 102150- Foo{B} //@snippet("}", snipFieldBar, "Bar: ${1:}", "Bar: ${1:int}") 102151- Foo{} //@snippet("}", snipFieldBar, "Bar: ${1:}", "Bar: ${1:int}") 102152- 102153- Foo{Foo{}.B} //@snippet("} ", snipFieldBar, "Bar", "Bar") 102154- 102155- var err error 102156- err.Error() //@snippet("E", Error, "Error()", "Error()") 102157- f.Baz() //@snippet("B", snipMethodBaz, "Baz()", "Baz()") 102158- 102159- f.Baz() //@snippet("(", snipMethodBazBar, "BazBar", "BazBar") 102160- 102161- f.Baz() //@snippet("B", snipMethodBazBaz, "BazBaz(${1:})", "BazBaz(${1:at AliasType})") 102162-} 102163- 102164-func _() { 102165- type bar struct { 102166- a int 102167- b float64 //@item(snipBarB, "b", "float64", "field") 102168- } 102169- bar{b} //@snippet("}", snipBarB, "b: ${1:}", "b: ${1:float64}") 102170-} 102171diff -urN a/gopls/internal/lsp/testdata/statements/append.go b/gopls/internal/lsp/testdata/statements/append.go 102172--- a/gopls/internal/lsp/testdata/statements/append.go 2000-01-01 00:00:00.000000000 -0000 102173+++ b/gopls/internal/lsp/testdata/statements/append.go 1970-01-01 00:00:00.000000000 +0000 102174@@ -1,42 +0,0 @@ 102175-package statements 102176- 102177-func _() { 102178- type mySlice []int 102179- 102180- var ( 102181- abc []int //@item(stmtABC, "abc", "[]int", "var") 102182- abcdef mySlice //@item(stmtABCDEF, "abcdef", "mySlice", "var") 102183- ) 102184- 102185- /* abcdef = append(abcdef, ) */ //@item(stmtABCDEFAssignAppend, "abcdef = append(abcdef, )", "", "func") 102186- 102187- // don't offer "abc = append(abc, )" because "abc" isn't necessarily 102188- // better than "abcdef". 102189- abc //@complete(" //", stmtABC, stmtABCDEF) 102190- 102191- abcdef //@complete(" //", stmtABCDEF, stmtABCDEFAssignAppend) 102192- 102193- /* append(abc, ) */ //@item(stmtABCAppend, "append(abc, )", "", "func") 102194- 102195- abc = app //@snippet(" //", stmtABCAppend, "append(abc, ${1:})", "append(abc, ${1:})") 102196-} 102197- 102198-func _() { 102199- var s struct{ xyz []int } 102200- 102201- /* xyz = append(s.xyz, ) */ //@item(stmtXYZAppend, "xyz = append(s.xyz, )", "", "func") 102202- 102203- s.x //@snippet(" //", stmtXYZAppend, "xyz = append(s.xyz, ${1:})", "xyz = append(s.xyz, ${1:})") 102204- 102205- /* s.xyz = append(s.xyz, ) */ //@item(stmtDeepXYZAppend, "s.xyz = append(s.xyz, )", "", "func") 102206- 102207- sx //@snippet(" //", stmtDeepXYZAppend, "s.xyz = append(s.xyz, ${1:})", "s.xyz = append(s.xyz, ${1:})") 102208-} 102209- 102210-func _() { 102211- var foo [][]int 102212- 102213- /* append(foo[0], ) */ //@item(stmtFooAppend, "append(foo[0], )", "", "func") 102214- 102215- foo[0] = app //@complete(" //"),snippet(" //", stmtFooAppend, "append(foo[0], ${1:})", "append(foo[0], ${1:})") 102216-} 102217diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go 102218--- a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go 2000-01-01 00:00:00.000000000 -0000 102219+++ b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go 1970-01-01 00:00:00.000000000 +0000 102220@@ -1,12 +0,0 @@ 102221-package statements 102222- 102223-import "os" 102224- 102225-func two() error { 102226- var s struct{ err error } 102227- 102228- /* if s.err != nil { return s.err } */ //@item(stmtTwoIfErrReturn, "if s.err != nil { return s.err }", "", "") 102229- 102230- _, s.err = os.Open("foo") 102231- //@snippet("", stmtTwoIfErrReturn, "", "if s.err != nil {\n\treturn ${1:s.err}\n\\}") 102232-} 102233diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_return.go b/gopls/internal/lsp/testdata/statements/if_err_check_return.go 102234--- a/gopls/internal/lsp/testdata/statements/if_err_check_return.go 2000-01-01 00:00:00.000000000 -0000 102235+++ b/gopls/internal/lsp/testdata/statements/if_err_check_return.go 1970-01-01 00:00:00.000000000 +0000 102236@@ -1,27 +0,0 @@ 102237-package statements 102238- 102239-import ( 102240- "bytes" 102241- "io" 102242- "os" 102243-) 102244- 102245-func one() (int, float32, io.Writer, *int, []int, bytes.Buffer, error) { 102246- /* if err != nil { return err } */ //@item(stmtOneIfErrReturn, "if err != nil { return err }", "", "") 102247- /* err != nil { return err } */ //@item(stmtOneErrReturn, "err != nil { return err }", "", "") 102248- 102249- _, err := os.Open("foo") 102250- //@snippet("", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") 102251- 102252- _, err = os.Open("foo") 102253- i //@snippet(" //", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") 102254- 102255- _, err = os.Open("foo") 102256- if er //@snippet(" //", stmtOneErrReturn, "", "err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") 102257- 102258- _, err = os.Open("foo") 102259- if //@snippet(" //", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") 102260- 102261- _, err = os.Open("foo") 102262- if //@snippet("//", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") 102263-} 102264diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_test.go b/gopls/internal/lsp/testdata/statements/if_err_check_test.go 102265--- a/gopls/internal/lsp/testdata/statements/if_err_check_test.go 2000-01-01 00:00:00.000000000 -0000 102266+++ b/gopls/internal/lsp/testdata/statements/if_err_check_test.go 1970-01-01 00:00:00.000000000 +0000 102267@@ -1,20 +0,0 @@ 102268-package statements 102269- 102270-import ( 102271- "os" 102272- "testing" 102273-) 102274- 102275-func TestErr(t *testing.T) { 102276- /* if err != nil { t.Fatal(err) } */ //@item(stmtOneIfErrTFatal, "if err != nil { t.Fatal(err) }", "", "") 102277- 102278- _, err := os.Open("foo") 102279- //@snippet("", stmtOneIfErrTFatal, "", "if err != nil {\n\tt.Fatal(err)\n\\}") 102280-} 102281- 102282-func BenchmarkErr(b *testing.B) { 102283- /* if err != nil { b.Fatal(err) } */ //@item(stmtOneIfErrBFatal, "if err != nil { b.Fatal(err) }", "", "") 102284- 102285- _, err := os.Open("foo") 102286- //@snippet("", stmtOneIfErrBFatal, "", "if err != nil {\n\tb.Fatal(err)\n\\}") 102287-} 102288diff -urN a/gopls/internal/lsp/testdata/stub/other/other.go b/gopls/internal/lsp/testdata/stub/other/other.go 102289--- a/gopls/internal/lsp/testdata/stub/other/other.go 2000-01-01 00:00:00.000000000 -0000 102290+++ b/gopls/internal/lsp/testdata/stub/other/other.go 1970-01-01 00:00:00.000000000 +0000 102291@@ -1,10 +0,0 @@ 102292-package other 102293- 102294-import ( 102295- "bytes" 102296- renamed_context "context" 102297-) 102298- 102299-type Interface interface { 102300- Get(renamed_context.Context) *bytes.Buffer 102301-} 102302diff -urN a/gopls/internal/lsp/testdata/stub/stub_add_selector.go b/gopls/internal/lsp/testdata/stub/stub_add_selector.go 102303--- a/gopls/internal/lsp/testdata/stub/stub_add_selector.go 2000-01-01 00:00:00.000000000 -0000 102304+++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go 1970-01-01 00:00:00.000000000 +0000 102305@@ -1,12 +0,0 @@ 102306-package stub 102307- 102308-import "io" 102309- 102310-// This file tests that if an interface 102311-// method references a type from its own package 102312-// then our implementation must add the import/package selector 102313-// in the concrete method if the concrete type is outside of the interface 102314-// package 102315-var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "") 102316- 102317-type readerFrom struct{} 102318diff -urN a/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden 102319--- a/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden 2000-01-01 00:00:00.000000000 -0000 102320+++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden 1970-01-01 00:00:00.000000000 +0000 102321@@ -1,19 +0,0 @@ 102322--- suggestedfix_stub_add_selector_10_23 -- 102323-package stub 102324- 102325-import "io" 102326- 102327-// This file tests that if an interface 102328-// method references a type from its own package 102329-// then our implementation must add the import/package selector 102330-// in the concrete method if the concrete type is outside of the interface 102331-// package 102332-var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "") 102333- 102334-type readerFrom struct{} 102335- 102336-// ReadFrom implements io.ReaderFrom 102337-func (*readerFrom) ReadFrom(r io.Reader) (n int64, err error) { 102338- panic("unimplemented") 102339-} 102340- 102341diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign.go b/gopls/internal/lsp/testdata/stub/stub_assign.go 102342--- a/gopls/internal/lsp/testdata/stub/stub_assign.go 2000-01-01 00:00:00.000000000 -0000 102343+++ b/gopls/internal/lsp/testdata/stub/stub_assign.go 1970-01-01 00:00:00.000000000 +0000 102344@@ -1,10 +0,0 @@ 102345-package stub 102346- 102347-import "io" 102348- 102349-func main() { 102350- var br io.ByteWriter 102351- br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "") 102352-} 102353- 102354-type byteWriter struct{} 102355diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden 102356--- a/gopls/internal/lsp/testdata/stub/stub_assign.go.golden 2000-01-01 00:00:00.000000000 -0000 102357+++ b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden 1970-01-01 00:00:00.000000000 +0000 102358@@ -1,17 +0,0 @@ 102359--- suggestedfix_stub_assign_7_7 -- 102360-package stub 102361- 102362-import "io" 102363- 102364-func main() { 102365- var br io.ByteWriter 102366- br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "") 102367-} 102368- 102369-type byteWriter struct{} 102370- 102371-// WriteByte implements io.ByteWriter 102372-func (*byteWriter) WriteByte(c byte) error { 102373- panic("unimplemented") 102374-} 102375- 102376diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go 102377--- a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go 2000-01-01 00:00:00.000000000 -0000 102378+++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go 1970-01-01 00:00:00.000000000 +0000 102379@@ -1,11 +0,0 @@ 102380-package stub 102381- 102382-import "io" 102383- 102384-func main() { 102385- var br io.ByteWriter 102386- var i int 102387- i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "") 102388-} 102389- 102390-type multiByteWriter struct{} 102391diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden 102392--- a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden 2000-01-01 00:00:00.000000000 -0000 102393+++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden 1970-01-01 00:00:00.000000000 +0000 102394@@ -1,18 +0,0 @@ 102395--- suggestedfix_stub_assign_multivars_8_13 -- 102396-package stub 102397- 102398-import "io" 102399- 102400-func main() { 102401- var br io.ByteWriter 102402- var i int 102403- i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "") 102404-} 102405- 102406-type multiByteWriter struct{} 102407- 102408-// WriteByte implements io.ByteWriter 102409-func (*multiByteWriter) WriteByte(c byte) error { 102410- panic("unimplemented") 102411-} 102412- 102413diff -urN a/gopls/internal/lsp/testdata/stub/stub_call_expr.go b/gopls/internal/lsp/testdata/stub/stub_call_expr.go 102414--- a/gopls/internal/lsp/testdata/stub/stub_call_expr.go 2000-01-01 00:00:00.000000000 -0000 102415+++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go 1970-01-01 00:00:00.000000000 +0000 102416@@ -1,13 +0,0 @@ 102417-package stub 102418- 102419-func main() { 102420- check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "") 102421-} 102422- 102423-func check(err error) { 102424- if err != nil { 102425- panic(err) 102426- } 102427-} 102428- 102429-type callExpr struct{} 102430diff -urN a/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden 102431--- a/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden 2000-01-01 00:00:00.000000000 -0000 102432+++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden 1970-01-01 00:00:00.000000000 +0000 102433@@ -1,20 +0,0 @@ 102434--- suggestedfix_stub_call_expr_4_8 -- 102435-package stub 102436- 102437-func main() { 102438- check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "") 102439-} 102440- 102441-func check(err error) { 102442- if err != nil { 102443- panic(err) 102444- } 102445-} 102446- 102447-type callExpr struct{} 102448- 102449-// Error implements error 102450-func (*callExpr) Error() string { 102451- panic("unimplemented") 102452-} 102453- 102454diff -urN a/gopls/internal/lsp/testdata/stub/stub_embedded.go b/gopls/internal/lsp/testdata/stub/stub_embedded.go 102455--- a/gopls/internal/lsp/testdata/stub/stub_embedded.go 2000-01-01 00:00:00.000000000 -0000 102456+++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go 1970-01-01 00:00:00.000000000 +0000 102457@@ -1,15 +0,0 @@ 102458-package stub 102459- 102460-import ( 102461- "io" 102462- "sort" 102463-) 102464- 102465-var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "") 102466- 102467-type embeddedConcrete struct{} 102468- 102469-type embeddedInterface interface { 102470- sort.Interface 102471- io.Reader 102472-} 102473diff -urN a/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden 102474--- a/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden 2000-01-01 00:00:00.000000000 -0000 102475+++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden 1970-01-01 00:00:00.000000000 +0000 102476@@ -1,37 +0,0 @@ 102477--- suggestedfix_stub_embedded_8_27 -- 102478-package stub 102479- 102480-import ( 102481- "io" 102482- "sort" 102483-) 102484- 102485-var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "") 102486- 102487-type embeddedConcrete struct{} 102488- 102489-// Len implements embeddedInterface 102490-func (*embeddedConcrete) Len() int { 102491- panic("unimplemented") 102492-} 102493- 102494-// Less implements embeddedInterface 102495-func (*embeddedConcrete) Less(i int, j int) bool { 102496- panic("unimplemented") 102497-} 102498- 102499-// Read implements embeddedInterface 102500-func (*embeddedConcrete) Read(p []byte) (n int, err error) { 102501- panic("unimplemented") 102502-} 102503- 102504-// Swap implements embeddedInterface 102505-func (*embeddedConcrete) Swap(i int, j int) { 102506- panic("unimplemented") 102507-} 102508- 102509-type embeddedInterface interface { 102510- sort.Interface 102511- io.Reader 102512-} 102513- 102514diff -urN a/gopls/internal/lsp/testdata/stub/stub_err.go b/gopls/internal/lsp/testdata/stub/stub_err.go 102515--- a/gopls/internal/lsp/testdata/stub/stub_err.go 2000-01-01 00:00:00.000000000 -0000 102516+++ b/gopls/internal/lsp/testdata/stub/stub_err.go 1970-01-01 00:00:00.000000000 +0000 102517@@ -1,7 +0,0 @@ 102518-package stub 102519- 102520-func main() { 102521- var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "") 102522-} 102523- 102524-type customErr struct{} 102525diff -urN a/gopls/internal/lsp/testdata/stub/stub_err.go.golden b/gopls/internal/lsp/testdata/stub/stub_err.go.golden 102526--- a/gopls/internal/lsp/testdata/stub/stub_err.go.golden 2000-01-01 00:00:00.000000000 -0000 102527+++ b/gopls/internal/lsp/testdata/stub/stub_err.go.golden 1970-01-01 00:00:00.000000000 +0000 102528@@ -1,14 +0,0 @@ 102529--- suggestedfix_stub_err_4_17 -- 102530-package stub 102531- 102532-func main() { 102533- var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "") 102534-} 102535- 102536-type customErr struct{} 102537- 102538-// Error implements error 102539-func (*customErr) Error() string { 102540- panic("unimplemented") 102541-} 102542- 102543diff -urN a/gopls/internal/lsp/testdata/stub/stub_function_return.go b/gopls/internal/lsp/testdata/stub/stub_function_return.go 102544--- a/gopls/internal/lsp/testdata/stub/stub_function_return.go 2000-01-01 00:00:00.000000000 -0000 102545+++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go 1970-01-01 00:00:00.000000000 +0000 102546@@ -1,11 +0,0 @@ 102547-package stub 102548- 102549-import ( 102550- "io" 102551-) 102552- 102553-func newCloser() io.Closer { 102554- return closer{} //@suggestedfix("c", "refactor.rewrite", "") 102555-} 102556- 102557-type closer struct{} 102558diff -urN a/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden 102559--- a/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden 2000-01-01 00:00:00.000000000 -0000 102560+++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden 1970-01-01 00:00:00.000000000 +0000 102561@@ -1,18 +0,0 @@ 102562--- suggestedfix_stub_function_return_8_9 -- 102563-package stub 102564- 102565-import ( 102566- "io" 102567-) 102568- 102569-func newCloser() io.Closer { 102570- return closer{} //@suggestedfix("c", "refactor.rewrite", "") 102571-} 102572- 102573-type closer struct{} 102574- 102575-// Close implements io.Closer 102576-func (closer) Close() error { 102577- panic("unimplemented") 102578-} 102579- 102580diff -urN a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go 102581--- a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go 2000-01-01 00:00:00.000000000 -0000 102582+++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go 1970-01-01 00:00:00.000000000 +0000 102583@@ -1,15 +0,0 @@ 102584-//go:build go1.18 102585-// +build go1.18 102586- 102587-package stub 102588- 102589-import "io" 102590- 102591-// This file tests that that the stub method generator accounts for concrete 102592-// types that have type parameters defined. 102593-var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom") 102594- 102595-type genReader[T, Y any] struct { 102596- T T 102597- Y Y 102598-} 102599diff -urN a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden 102600--- a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden 2000-01-01 00:00:00.000000000 -0000 102601+++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden 1970-01-01 00:00:00.000000000 +0000 102602@@ -1,22 +0,0 @@ 102603--- suggestedfix_stub_generic_receiver_10_23 -- 102604-//go:build go1.18 102605-// +build go1.18 102606- 102607-package stub 102608- 102609-import "io" 102610- 102611-// This file tests that that the stub method generator accounts for concrete 102612-// types that have type parameters defined. 102613-var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom") 102614- 102615-type genReader[T, Y any] struct { 102616- T T 102617- Y Y 102618-} 102619- 102620-// ReadFrom implements io.ReaderFrom 102621-func (*genReader[T, Y]) ReadFrom(r io.Reader) (n int64, err error) { 102622- panic("unimplemented") 102623-} 102624- 102625diff -urN a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go 102626--- a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go 2000-01-01 00:00:00.000000000 -0000 102627+++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go 1970-01-01 00:00:00.000000000 +0000 102628@@ -1,18 +0,0 @@ 102629-package stub 102630- 102631-import ( 102632- "compress/zlib" 102633- . "io" 102634- _ "io" 102635-) 102636- 102637-// This file tests that dot-imports and underscore imports 102638-// are properly ignored and that a new import is added to 102639-// reference method types 102640- 102641-var ( 102642- _ Reader 102643- _ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "") 102644-) 102645- 102646-type ignoredResetter struct{} 102647diff -urN a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden 102648--- a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden 2000-01-01 00:00:00.000000000 -0000 102649+++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden 1970-01-01 00:00:00.000000000 +0000 102650@@ -1,25 +0,0 @@ 102651--- suggestedfix_stub_ignored_imports_15_20 -- 102652-package stub 102653- 102654-import ( 102655- "compress/zlib" 102656- . "io" 102657- _ "io" 102658-) 102659- 102660-// This file tests that dot-imports and underscore imports 102661-// are properly ignored and that a new import is added to 102662-// reference method types 102663- 102664-var ( 102665- _ Reader 102666- _ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "") 102667-) 102668- 102669-type ignoredResetter struct{} 102670- 102671-// Reset implements zlib.Resetter 102672-func (*ignoredResetter) Reset(r Reader, dict []byte) error { 102673- panic("unimplemented") 102674-} 102675- 102676diff -urN a/gopls/internal/lsp/testdata/stub/stub_issue2606.go b/gopls/internal/lsp/testdata/stub/stub_issue2606.go 102677--- a/gopls/internal/lsp/testdata/stub/stub_issue2606.go 2000-01-01 00:00:00.000000000 -0000 102678+++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go 1970-01-01 00:00:00.000000000 +0000 102679@@ -1,7 +0,0 @@ 102680-package stub 102681- 102682-type I interface{ error } 102683- 102684-type C int 102685- 102686-var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "") 102687diff -urN a/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden 102688--- a/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden 2000-01-01 00:00:00.000000000 -0000 102689+++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden 1970-01-01 00:00:00.000000000 +0000 102690@@ -1,14 +0,0 @@ 102691--- suggestedfix_stub_issue2606_7_11 -- 102692-package stub 102693- 102694-type I interface{ error } 102695- 102696-type C int 102697- 102698-// Error implements I 102699-func (C) Error() string { 102700- panic("unimplemented") 102701-} 102702- 102703-var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "") 102704- 102705diff -urN a/gopls/internal/lsp/testdata/stub/stub_multi_var.go b/gopls/internal/lsp/testdata/stub/stub_multi_var.go 102706--- a/gopls/internal/lsp/testdata/stub/stub_multi_var.go 2000-01-01 00:00:00.000000000 -0000 102707+++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go 1970-01-01 00:00:00.000000000 +0000 102708@@ -1,11 +0,0 @@ 102709-package stub 102710- 102711-import "io" 102712- 102713-// This test ensures that a variable declaration that 102714-// has multiple values on the same line can still be 102715-// analyzed correctly to target the interface implementation 102716-// diagnostic. 102717-var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "") 102718- 102719-type multiVar struct{} 102720diff -urN a/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden 102721--- a/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden 2000-01-01 00:00:00.000000000 -0000 102722+++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden 1970-01-01 00:00:00.000000000 +0000 102723@@ -1,18 +0,0 @@ 102724--- suggestedfix_stub_multi_var_9_38 -- 102725-package stub 102726- 102727-import "io" 102728- 102729-// This test ensures that a variable declaration that 102730-// has multiple values on the same line can still be 102731-// analyzed correctly to target the interface implementation 102732-// diagnostic. 102733-var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "") 102734- 102735-type multiVar struct{} 102736- 102737-// Read implements io.Reader 102738-func (*multiVar) Read(p []byte) (n int, err error) { 102739- panic("unimplemented") 102740-} 102741- 102742diff -urN a/gopls/internal/lsp/testdata/stub/stub_pointer.go b/gopls/internal/lsp/testdata/stub/stub_pointer.go 102743--- a/gopls/internal/lsp/testdata/stub/stub_pointer.go 2000-01-01 00:00:00.000000000 -0000 102744+++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go 1970-01-01 00:00:00.000000000 +0000 102745@@ -1,9 +0,0 @@ 102746-package stub 102747- 102748-import "io" 102749- 102750-func getReaderFrom() io.ReaderFrom { 102751- return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "") 102752-} 102753- 102754-type pointerImpl struct{} 102755diff -urN a/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden 102756--- a/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden 2000-01-01 00:00:00.000000000 -0000 102757+++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden 1970-01-01 00:00:00.000000000 +0000 102758@@ -1,16 +0,0 @@ 102759--- suggestedfix_stub_pointer_6_9 -- 102760-package stub 102761- 102762-import "io" 102763- 102764-func getReaderFrom() io.ReaderFrom { 102765- return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "") 102766-} 102767- 102768-type pointerImpl struct{} 102769- 102770-// ReadFrom implements io.ReaderFrom 102771-func (*pointerImpl) ReadFrom(r io.Reader) (n int64, err error) { 102772- panic("unimplemented") 102773-} 102774- 102775diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go 102776--- a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go 2000-01-01 00:00:00.000000000 -0000 102777+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go 1970-01-01 00:00:00.000000000 +0000 102778@@ -1,11 +0,0 @@ 102779-package stub 102780- 102781-import ( 102782- "compress/zlib" 102783- myio "io" 102784-) 102785- 102786-var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "") 102787-var _ myio.Reader 102788- 102789-type myIO struct{} 102790diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden 102791--- a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden 2000-01-01 00:00:00.000000000 -0000 102792+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden 1970-01-01 00:00:00.000000000 +0000 102793@@ -1,18 +0,0 @@ 102794--- suggestedfix_stub_renamed_import_8_23 -- 102795-package stub 102796- 102797-import ( 102798- "compress/zlib" 102799- myio "io" 102800-) 102801- 102802-var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "") 102803-var _ myio.Reader 102804- 102805-type myIO struct{} 102806- 102807-// Reset implements zlib.Resetter 102808-func (*myIO) Reset(r myio.Reader, dict []byte) error { 102809- panic("unimplemented") 102810-} 102811- 102812diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go 102813--- a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go 2000-01-01 00:00:00.000000000 -0000 102814+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go 1970-01-01 00:00:00.000000000 +0000 102815@@ -1,13 +0,0 @@ 102816-package stub 102817- 102818-import ( 102819- "golang.org/lsptests/stub/other" 102820-) 102821- 102822-// This file tests that if an interface 102823-// method references an import from its own package 102824-// that the concrete type does not yet import, and that import happens 102825-// to be renamed, then we prefer the renaming of the interface. 102826-var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "") 102827- 102828-type otherInterfaceImpl struct{} 102829diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden 102830--- a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden 2000-01-01 00:00:00.000000000 -0000 102831+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden 1970-01-01 00:00:00.000000000 +0000 102832@@ -1,22 +0,0 @@ 102833--- suggestedfix_stub_renamed_import_iface_11_25 -- 102834-package stub 102835- 102836-import ( 102837- "bytes" 102838- "context" 102839- "golang.org/lsptests/stub/other" 102840-) 102841- 102842-// This file tests that if an interface 102843-// method references an import from its own package 102844-// that the concrete type does not yet import, and that import happens 102845-// to be renamed, then we prefer the renaming of the interface. 102846-var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "") 102847- 102848-type otherInterfaceImpl struct{} 102849- 102850-// Get implements other.Interface 102851-func (*otherInterfaceImpl) Get(context.Context) *bytes.Buffer { 102852- panic("unimplemented") 102853-} 102854- 102855diff -urN a/gopls/internal/lsp/testdata/stub/stub_stdlib.go b/gopls/internal/lsp/testdata/stub/stub_stdlib.go 102856--- a/gopls/internal/lsp/testdata/stub/stub_stdlib.go 2000-01-01 00:00:00.000000000 -0000 102857+++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go 1970-01-01 00:00:00.000000000 +0000 102858@@ -1,9 +0,0 @@ 102859-package stub 102860- 102861-import ( 102862- "io" 102863-) 102864- 102865-var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "") 102866- 102867-type writer struct{} 102868diff -urN a/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden 102869--- a/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden 2000-01-01 00:00:00.000000000 -0000 102870+++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden 1970-01-01 00:00:00.000000000 +0000 102871@@ -1,16 +0,0 @@ 102872--- suggestedfix_stub_stdlib_7_19 -- 102873-package stub 102874- 102875-import ( 102876- "io" 102877-) 102878- 102879-var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "") 102880- 102881-type writer struct{} 102882- 102883-// Write implements io.Writer 102884-func (writer) Write(p []byte) (n int, err error) { 102885- panic("unimplemented") 102886-} 102887- 102888diff -urN a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go 102889--- a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go 2000-01-01 00:00:00.000000000 -0000 102890+++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go 1970-01-01 00:00:00.000000000 +0000 102891@@ -1,27 +0,0 @@ 102892-package stub 102893- 102894-// Regression test for Issue #56825: file corrupted by insertion of 102895-// methods after TypeSpec in a parenthesized TypeDecl. 102896- 102897-import "io" 102898- 102899-func newReadCloser() io.ReadCloser { 102900- return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "") 102901-} 102902- 102903-type ( 102904- A int 102905- rdcloser struct{} 102906- B int 102907-) 102908- 102909-func _() { 102910- // Local types can't be stubbed as there's nowhere to put the methods. 102911- // The suggestedfix assertion can't express this yet. TODO(adonovan): support it. 102912- type local struct{} 102913- var _ io.ReadCloser = local{} // want error: `local type "local" cannot be stubbed` 102914-} 102915- 102916-type ( 102917- C int 102918-) 102919diff -urN a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden 102920--- a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden 2000-01-01 00:00:00.000000000 -0000 102921+++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden 1970-01-01 00:00:00.000000000 +0000 102922@@ -1,39 +0,0 @@ 102923--- suggestedfix_stub_typedecl_group_9_9 -- 102924-package stub 102925- 102926-// Regression test for Issue #56825: file corrupted by insertion of 102927-// methods after TypeSpec in a parenthesized TypeDecl. 102928- 102929-import "io" 102930- 102931-func newReadCloser() io.ReadCloser { 102932- return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "") 102933-} 102934- 102935-type ( 102936- A int 102937- rdcloser struct{} 102938- B int 102939-) 102940- 102941-// Close implements io.ReadCloser 102942-func (rdcloser) Close() error { 102943- panic("unimplemented") 102944-} 102945- 102946-// Read implements io.ReadCloser 102947-func (rdcloser) Read(p []byte) (n int, err error) { 102948- panic("unimplemented") 102949-} 102950- 102951-func _() { 102952- // Local types can't be stubbed as there's nowhere to put the methods. 102953- // The suggestedfix assertion can't express this yet. TODO(adonovan): support it. 102954- type local struct{} 102955- var _ io.ReadCloser = local{} // want error: `local type "local" cannot be stubbed` 102956-} 102957- 102958-type ( 102959- C int 102960-) 102961- 102962diff -urN a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go 102963--- a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go 2000-01-01 00:00:00.000000000 -0000 102964+++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go 1970-01-01 00:00:00.000000000 +0000 102965@@ -1,11 +0,0 @@ 102966-package suggestedfix 102967- 102968-import ( 102969- "log" 102970-) 102971- 102972-func goodbye() { 102973- s := "hiiiiiii" 102974- s = s //@suggestedfix("s = s", "quickfix", "") 102975- log.Print(s) 102976-} 102977diff -urN a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden 102978--- a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden 2000-01-01 00:00:00.000000000 -0000 102979+++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden 1970-01-01 00:00:00.000000000 +0000 102980@@ -1,13 +0,0 @@ 102981--- suggestedfix_has_suggested_fix_9_2 -- 102982-package suggestedfix 102983- 102984-import ( 102985- "log" 102986-) 102987- 102988-func goodbye() { 102989- s := "hiiiiiii" 102990- //@suggestedfix("s = s", "quickfix", "") 102991- log.Print(s) 102992-} 102993- 102994diff -urN a/gopls/internal/lsp/testdata/summary_go1.18.txt.golden b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden 102995--- a/gopls/internal/lsp/testdata/summary_go1.18.txt.golden 2000-01-01 00:00:00.000000000 -0000 102996+++ b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden 1970-01-01 00:00:00.000000000 +0000 102997@@ -1,32 +0,0 @@ 102998--- summary -- 102999-CallHierarchyCount = 2 103000-CodeLensCount = 5 103001-CompletionsCount = 264 103002-CompletionSnippetCount = 115 103003-UnimportedCompletionsCount = 5 103004-DeepCompletionsCount = 5 103005-FuzzyCompletionsCount = 8 103006-RankedCompletionsCount = 174 103007-CaseSensitiveCompletionsCount = 4 103008-DiagnosticsCount = 42 103009-FoldingRangesCount = 2 103010-FormatCount = 6 103011-ImportCount = 8 103012-SemanticTokenCount = 3 103013-SuggestedFixCount = 71 103014-FunctionExtractionCount = 27 103015-MethodExtractionCount = 6 103016-DefinitionsCount = 47 103017-TypeDefinitionsCount = 18 103018-HighlightsCount = 69 103019-InlayHintsCount = 5 103020-ReferencesCount = 30 103021-RenamesCount = 48 103022-PrepareRenamesCount = 7 103023-SymbolsCount = 2 103024-WorkspaceSymbolsCount = 20 103025-SignaturesCount = 33 103026-LinksCount = 7 103027-ImplementationsCount = 26 103028-SelectionRangesCount = 3 103029- 103030diff -urN a/gopls/internal/lsp/testdata/summary.txt.golden b/gopls/internal/lsp/testdata/summary.txt.golden 103031--- a/gopls/internal/lsp/testdata/summary.txt.golden 2000-01-01 00:00:00.000000000 -0000 103032+++ b/gopls/internal/lsp/testdata/summary.txt.golden 1970-01-01 00:00:00.000000000 +0000 103033@@ -1,32 +0,0 @@ 103034--- summary -- 103035-CallHierarchyCount = 2 103036-CodeLensCount = 5 103037-CompletionsCount = 263 103038-CompletionSnippetCount = 106 103039-UnimportedCompletionsCount = 5 103040-DeepCompletionsCount = 5 103041-FuzzyCompletionsCount = 8 103042-RankedCompletionsCount = 164 103043-CaseSensitiveCompletionsCount = 4 103044-DiagnosticsCount = 42 103045-FoldingRangesCount = 2 103046-FormatCount = 6 103047-ImportCount = 8 103048-SemanticTokenCount = 3 103049-SuggestedFixCount = 65 103050-FunctionExtractionCount = 27 103051-MethodExtractionCount = 6 103052-DefinitionsCount = 47 103053-TypeDefinitionsCount = 18 103054-HighlightsCount = 69 103055-InlayHintsCount = 4 103056-ReferencesCount = 30 103057-RenamesCount = 41 103058-PrepareRenamesCount = 7 103059-SymbolsCount = 1 103060-WorkspaceSymbolsCount = 20 103061-SignaturesCount = 33 103062-LinksCount = 7 103063-ImplementationsCount = 16 103064-SelectionRangesCount = 3 103065- 103066diff -urN a/gopls/internal/lsp/testdata/symbols/go1.18.go b/gopls/internal/lsp/testdata/symbols/go1.18.go 103067--- a/gopls/internal/lsp/testdata/symbols/go1.18.go 2000-01-01 00:00:00.000000000 -0000 103068+++ b/gopls/internal/lsp/testdata/symbols/go1.18.go 1970-01-01 00:00:00.000000000 +0000 103069@@ -1,16 +0,0 @@ 103070-//go:build go1.18 103071-// +build go1.18 103072- 103073-package main 103074- 103075-type T[P any] struct { //@symbol("T", "T", "Struct", "struct{...}", "T", "") 103076- F P //@symbol("F", "F", "Field", "P", "", "T") 103077-} 103078- 103079-type Constraint interface { //@symbol("Constraint", "Constraint", "Interface", "interface{...}", "Constraint", "") 103080- ~int | struct{ int } //@symbol("~int | struct{int}", "~int | struct{ int }", "Field", "", "", "Constraint") 103081- 103082- // TODO(rfindley): the selection range below is the entire interface field. 103083- // Can we reduce it? 103084- interface{ M() } //@symbol("interface{...}", "interface{ M() }", "Field", "", "iFaceField", "Constraint"), symbol("M", "M", "Method", "func()", "", "iFaceField") 103085-} 103086diff -urN a/gopls/internal/lsp/testdata/symbols/go1.18.go.golden b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden 103087--- a/gopls/internal/lsp/testdata/symbols/go1.18.go.golden 2000-01-01 00:00:00.000000000 -0000 103088+++ b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden 1970-01-01 00:00:00.000000000 +0000 103089@@ -1,7 +0,0 @@ 103090--- symbols -- 103091-T Struct 6:6-6:7 103092- F Field 7:2-7:3 103093-Constraint Interface 10:6-10:16 103094- interface{...} Field 15:2-15:18 103095- ~int | struct{int} Field 11:2-11:22 103096- 103097diff -urN a/gopls/internal/lsp/testdata/symbols/main.go b/gopls/internal/lsp/testdata/symbols/main.go 103098--- a/gopls/internal/lsp/testdata/symbols/main.go 2000-01-01 00:00:00.000000000 -0000 103099+++ b/gopls/internal/lsp/testdata/symbols/main.go 1970-01-01 00:00:00.000000000 +0000 103100@@ -1,91 +0,0 @@ 103101-package main 103102- 103103-import ( 103104- "io" 103105-) 103106- 103107-// Each symbol marker in this file defines the following information: 103108-// symbol(name, selectionSpan, kind, detail, id, parentID) 103109-// - name: DocumentSymbol.Name 103110-// - selectionSpan: DocumentSymbol.SelectionRange 103111-// - kind: DocumentSymbol.Kind 103112-// - detail: DocumentSymbol.Detail 103113-// - id: if non-empty, a unique identifier for this symbol 103114-// - parentID: if non-empty, the id of the parent of this symbol 103115-// 103116-// This data in aggregate defines a set of document symbols and their 103117-// parent-child relationships, which is compared against the DocummentSymbols 103118-// response from gopls for the current file. 103119-// 103120-// TODO(rfindley): the symbol annotations here are complicated and difficult to 103121-// maintain. It would be simpler to just write out the full expected response 103122-// in the golden file, perhaps as raw JSON. 103123- 103124-var _ = 1 103125- 103126-var x = 42 //@symbol("x", "x", "Variable", "", "", "") 103127- 103128-var nested struct { //@symbol("nested", "nested", "Variable", "struct{...}", "nested", "") 103129- nestedField struct { //@symbol("nestedField", "nestedField", "Field", "struct{...}", "nestedField", "nested") 103130- f int //@symbol("f", "f", "Field", "int", "", "nestedField") 103131- } 103132-} 103133- 103134-const y = 43 //@symbol("y", "y", "Constant", "", "", "") 103135- 103136-type Number int //@symbol("Number", "Number", "Class", "int", "", "") 103137- 103138-type Alias = string //@symbol("Alias", "Alias", "Class", "string", "", "") 103139- 103140-type NumberAlias = Number //@symbol("NumberAlias", "NumberAlias", "Class", "Number", "", "") 103141- 103142-type ( 103143- Boolean bool //@symbol("Boolean", "Boolean", "Class", "bool", "", "") 103144- BoolAlias = bool //@symbol("BoolAlias", "BoolAlias", "Class", "bool", "", "") 103145-) 103146- 103147-type Foo struct { //@symbol("Foo", "Foo", "Struct", "struct{...}", "Foo", "") 103148- Quux //@symbol("Quux", "Quux", "Field", "Quux", "", "Foo") 103149- W io.Writer //@symbol("W", "W", "Field", "io.Writer", "", "Foo") 103150- Bar int //@symbol("Bar", "Bar", "Field", "int", "", "Foo") 103151- baz string //@symbol("baz", "baz", "Field", "string", "", "Foo") 103152- funcField func(int) int //@symbol("funcField", "funcField", "Field", "func(int) int", "", "Foo") 103153-} 103154- 103155-type Quux struct { //@symbol("Quux", "Quux", "Struct", "struct{...}", "Quux", "") 103156- X, Y float64 //@symbol("X", "X", "Field", "float64", "", "Quux"), symbol("Y", "Y", "Field", "float64", "", "Quux") 103157-} 103158- 103159-type EmptyStruct struct{} //@symbol("EmptyStruct", "EmptyStruct", "Struct", "struct{}", "", "") 103160- 103161-func (f Foo) Baz() string { //@symbol("(Foo).Baz", "Baz", "Method", "func() string", "", "") 103162- return f.baz 103163-} 103164- 103165-func _() {} 103166- 103167-func (q *Quux) Do() {} //@symbol("(*Quux).Do", "Do", "Method", "func()", "", "") 103168- 103169-func main() { //@symbol("main", "main", "Function", "func()", "", "") 103170-} 103171- 103172-type Stringer interface { //@symbol("Stringer", "Stringer", "Interface", "interface{...}", "Stringer", "") 103173- String() string //@symbol("String", "String", "Method", "func() string", "", "Stringer") 103174-} 103175- 103176-type ABer interface { //@symbol("ABer", "ABer", "Interface", "interface{...}", "ABer", "") 103177- B() //@symbol("B", "B", "Method", "func()", "", "ABer") 103178- A() string //@symbol("A", "A", "Method", "func() string", "", "ABer") 103179-} 103180- 103181-type WithEmbeddeds interface { //@symbol("WithEmbeddeds", "WithEmbeddeds", "Interface", "interface{...}", "WithEmbeddeds", "") 103182- Do() //@symbol("Do", "Do", "Method", "func()", "", "WithEmbeddeds") 103183- ABer //@symbol("ABer", "ABer", "Field", "ABer", "", "WithEmbeddeds") 103184- io.Writer //@symbol("Writer", "Writer", "Field", "io.Writer", "", "WithEmbeddeds") 103185-} 103186- 103187-type EmptyInterface interface{} //@symbol("EmptyInterface", "EmptyInterface", "Interface", "interface{}", "", "") 103188- 103189-func Dunk() int { return 0 } //@symbol("Dunk", "Dunk", "Function", "func() int", "", "") 103190- 103191-func dunk() {} //@symbol("dunk", "dunk", "Function", "func()", "", "") 103192diff -urN a/gopls/internal/lsp/testdata/symbols/main.go.golden b/gopls/internal/lsp/testdata/symbols/main.go.golden 103193--- a/gopls/internal/lsp/testdata/symbols/main.go.golden 2000-01-01 00:00:00.000000000 -0000 103194+++ b/gopls/internal/lsp/testdata/symbols/main.go.golden 1970-01-01 00:00:00.000000000 +0000 103195@@ -1,36 +0,0 @@ 103196--- symbols -- 103197-x Variable 26:5-26:6 103198-nested Variable 28:5-28:11 103199- nestedField Field 29:2-29:13 103200-y Constant 34:7-34:8 103201-Number Class 36:6-36:12 103202-Alias Class 38:6-38:11 103203-NumberAlias Class 40:6-40:17 103204-Boolean Class 43:2-43:9 103205-BoolAlias Class 44:2-44:11 103206-Foo Struct 47:6-47:9 103207- Bar Field 50:2-50:5 103208- Quux Field 48:2-48:6 103209- W Field 49:2-49:3 103210- baz Field 51:2-51:5 103211- funcField Field 52:2-52:11 103212-Quux Struct 55:6-55:10 103213- X Field 56:2-56:3 103214- Y Field 56:5-56:6 103215-EmptyStruct Struct 59:6-59:17 103216-(Foo).Baz Method 61:14-61:17 103217-(*Quux).Do Method 67:16-67:18 103218-main Function 69:6-69:10 103219-Stringer Interface 72:6-72:14 103220- String Method 73:2-73:8 103221-ABer Interface 76:6-76:10 103222- A Method 78:2-78:3 103223- B Method 77:2-77:3 103224-WithEmbeddeds Interface 81:6-81:19 103225- ABer Field 83:2-83:6 103226- Do Method 82:2-82:4 103227- Writer Field 84:5-84:11 103228-EmptyInterface Interface 87:6-87:20 103229-Dunk Function 89:6-89:10 103230-dunk Function 91:6-91:10 103231- 103232diff -urN a/gopls/internal/lsp/testdata/testy/testy.go b/gopls/internal/lsp/testdata/testy/testy.go 103233--- a/gopls/internal/lsp/testdata/testy/testy.go 2000-01-01 00:00:00.000000000 -0000 103234+++ b/gopls/internal/lsp/testdata/testy/testy.go 1970-01-01 00:00:00.000000000 +0000 103235@@ -1,5 +0,0 @@ 103236-package testy 103237- 103238-func a() { //@mark(identA, "a"),item(funcA, "a", "func()", "func"),refs("a", identA, testyA) 103239- //@complete("", funcA) 103240-} 103241diff -urN a/gopls/internal/lsp/testdata/testy/testy_test.go b/gopls/internal/lsp/testdata/testy/testy_test.go 103242--- a/gopls/internal/lsp/testdata/testy/testy_test.go 2000-01-01 00:00:00.000000000 -0000 103243+++ b/gopls/internal/lsp/testdata/testy/testy_test.go 1970-01-01 00:00:00.000000000 +0000 103244@@ -1,18 +0,0 @@ 103245-package testy 103246- 103247-import ( 103248- "testing" 103249- 103250- sig "golang.org/lsptests/signature" 103251- "golang.org/lsptests/snippets" 103252-) 103253- 103254-func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func") 103255- var x int //@mark(testyX, "x"),diag("x", "compiler", "x declared (and|but) not used", "error"),refs("x", testyX) 103256- a() //@mark(testyA, "a") 103257-} 103258- 103259-func _() { 103260- _ = snippets.X(nil) //@signature("nil", "X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias", 0) 103261- var _ sig.Alias 103262-} 103263diff -urN a/gopls/internal/lsp/testdata/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/testy/testy_test.go.golden 103264--- a/gopls/internal/lsp/testdata/testy/testy_test.go.golden 2000-01-01 00:00:00.000000000 -0000 103265+++ b/gopls/internal/lsp/testdata/testy/testy_test.go.golden 1970-01-01 00:00:00.000000000 +0000 103266@@ -1,3 +0,0 @@ 103267--- X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias-signature -- 103268-X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias 103269- 103270diff -urN a/gopls/internal/lsp/testdata/typdef/typdef.go b/gopls/internal/lsp/testdata/typdef/typdef.go 103271--- a/gopls/internal/lsp/testdata/typdef/typdef.go 2000-01-01 00:00:00.000000000 -0000 103272+++ b/gopls/internal/lsp/testdata/typdef/typdef.go 1970-01-01 00:00:00.000000000 +0000 103273@@ -1,65 +0,0 @@ 103274-package typdef 103275- 103276-type Struct struct { //@item(Struct, "Struct", "struct{...}", "struct") 103277- Field string 103278-} 103279- 103280-type Int int //@item(Int, "Int", "int", "type") 103281- 103282-func _() { 103283- var ( 103284- value Struct 103285- point *Struct 103286- ) 103287- _ = value //@typdef("value", Struct) 103288- _ = point //@typdef("point", Struct) 103289- 103290- var ( 103291- array [3]Struct 103292- slice []Struct 103293- ch chan Struct 103294- complex [3]chan *[5][]Int 103295- ) 103296- _ = array //@typdef("array", Struct) 103297- _ = slice //@typdef("slice", Struct) 103298- _ = ch //@typdef("ch", Struct) 103299- _ = complex //@typdef("complex", Int) 103300- 103301- var s struct { 103302- x struct { 103303- xx struct { 103304- field1 []Struct 103305- field2 []Int 103306- } 103307- } 103308- } 103309- s.x.xx.field1 //@typdef("field1", Struct) 103310- s.x.xx.field2 //@typdef("field2", Int) 103311-} 103312- 103313-func F1() Int { return 0 } 103314-func F2() (Int, float64) { return 0, 0 } 103315-func F3() (Struct, int, bool, error) { return Struct{}, 0, false, nil } 103316-func F4() (**int, Int, bool, *error) { return nil, Struct{}, false, nil } 103317-func F5() (int, float64, error, Struct) { return 0, 0, nil, Struct{} } 103318-func F6() (int, float64, ***Struct, error) { return 0, 0, nil, nil } 103319- 103320-func _() { 103321- F1() //@typdef("F1", Int) 103322- F2() //@typdef("F2", Int) 103323- F3() //@typdef("F3", Struct) 103324- F4() //@typdef("F4", Int) 103325- F5() //@typdef("F5", Struct) 103326- F6() //@typdef("F6", Struct) 103327- 103328- f := func() Int { return 0 } 103329- f() //@typdef("f", Int) 103330-} 103331- 103332-// https://github.com/golang/go/issues/38589#issuecomment-620350922 103333-func _() { 103334- type myFunc func(int) Int //@item(myFunc, "myFunc", "func", "type") 103335- 103336- var foo myFunc 103337- bar := foo() //@typdef("foo", myFunc) 103338-} 103339diff -urN a/gopls/internal/lsp/testdata/typeassert/type_assert.go b/gopls/internal/lsp/testdata/typeassert/type_assert.go 103340--- a/gopls/internal/lsp/testdata/typeassert/type_assert.go 2000-01-01 00:00:00.000000000 -0000 103341+++ b/gopls/internal/lsp/testdata/typeassert/type_assert.go 1970-01-01 00:00:00.000000000 +0000 103342@@ -1,24 +0,0 @@ 103343-package typeassert 103344- 103345-type abc interface { //@item(abcIntf, "abc", "interface{...}", "interface") 103346- abc() 103347-} 103348- 103349-type abcImpl struct{} //@item(abcImpl, "abcImpl", "struct{...}", "struct") 103350-func (abcImpl) abc() 103351- 103352-type abcPtrImpl struct{} //@item(abcPtrImpl, "abcPtrImpl", "struct{...}", "struct") 103353-func (*abcPtrImpl) abc() 103354- 103355-type abcNotImpl struct{} //@item(abcNotImpl, "abcNotImpl", "struct{...}", "struct") 103356- 103357-func _() { 103358- var a abc 103359- switch a.(type) { 103360- case ab: //@complete(":", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) 103361- case *ab: //@complete(":", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) 103362- } 103363- 103364- a.(ab) //@complete(")", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) 103365- a.(*ab) //@complete(")", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) 103366-} 103367diff -urN a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go 103368--- a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go 2000-01-01 00:00:00.000000000 -0000 103369+++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go 1970-01-01 00:00:00.000000000 +0000 103370@@ -1,5 +0,0 @@ 103371-package typeerrors 103372- 103373-func x() { return nil } //@suggestedfix("nil", "quickfix", "") 103374- 103375-func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "") 103376diff -urN a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden 103377--- a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden 2000-01-01 00:00:00.000000000 -0000 103378+++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden 1970-01-01 00:00:00.000000000 +0000 103379@@ -1,14 +0,0 @@ 103380--- suggestedfix_noresultvalues_3_19 -- 103381-package typeerrors 103382- 103383-func x() { return } //@suggestedfix("nil", "quickfix", "") 103384- 103385-func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "") 103386- 103387--- suggestedfix_noresultvalues_5_19 -- 103388-package typeerrors 103389- 103390-func x() { return nil } //@suggestedfix("nil", "quickfix", "") 103391- 103392-func y() { return } //@suggestedfix("nil", "quickfix", "") 103393- 103394diff -urN a/gopls/internal/lsp/testdata/typemods/type_mods.go b/gopls/internal/lsp/testdata/typemods/type_mods.go 103395--- a/gopls/internal/lsp/testdata/typemods/type_mods.go 2000-01-01 00:00:00.000000000 -0000 103396+++ b/gopls/internal/lsp/testdata/typemods/type_mods.go 1970-01-01 00:00:00.000000000 +0000 103397@@ -1,21 +0,0 @@ 103398-package typemods 103399- 103400-func fooFunc() func() int { //@item(modFooFunc, "fooFunc", "func() func() int", "func") 103401- return func() int { 103402- return 0 103403- } 103404-} 103405- 103406-func fooPtr() *int { //@item(modFooPtr, "fooPtr", "func() *int", "func") 103407- return nil 103408-} 103409- 103410-func _() { 103411- var _ int = foo //@snippet(" //", modFooFunc, "fooFunc()()", "fooFunc()()"),snippet(" //", modFooPtr, "*fooPtr()", "*fooPtr()") 103412-} 103413- 103414-func _() { 103415- var m map[int][]chan int //@item(modMapChanPtr, "m", "map[int]chan *int", "var") 103416- 103417- var _ int = m //@snippet(" //", modMapChanPtr, "<-m[${1:}][${2:}]", "<-m[${1:}][${2:}]") 103418-} 103419diff -urN a/gopls/internal/lsp/testdata/typeparams/type_params.go b/gopls/internal/lsp/testdata/typeparams/type_params.go 103420--- a/gopls/internal/lsp/testdata/typeparams/type_params.go 2000-01-01 00:00:00.000000000 -0000 103421+++ b/gopls/internal/lsp/testdata/typeparams/type_params.go 1970-01-01 00:00:00.000000000 +0000 103422@@ -1,61 +0,0 @@ 103423-//go:build go1.18 103424-// +build go1.18 103425- 103426-package typeparams 103427- 103428-func one[a int | string]() {} 103429-func two[a int | string, b float64 | int]() {} 103430- 103431-func _() { 103432- one[]() //@rank("]", string, float64) 103433- two[]() //@rank("]", int, float64) 103434- two[int, f]() //@rank("]", float64, float32) 103435-} 103436- 103437-func slices[a []int | []float64]() {} //@item(tpInts, "[]int", "[]int", "type"),item(tpFloats, "[]float64", "[]float64", "type") 103438- 103439-func _() { 103440- slices[]() //@rank("]", tpInts),rank("]", tpFloats) 103441-} 103442- 103443-type s[a int | string] struct{} 103444- 103445-func _() { 103446- s[]{} //@rank("]", int, float64) 103447-} 103448- 103449-func takesGeneric[a int | string](s[a]) { 103450- "s[a]{}" //@item(tpInScopeLit, "s[a]{}", "", "var") 103451- takesGeneric() //@rank(")", tpInScopeLit),snippet(")", tpInScopeLit, "s[a]{\\}", "s[a]{\\}") 103452-} 103453- 103454-func _() { 103455- s[int]{} //@item(tpInstLit, "s[int]{}", "", "var") 103456- takesGeneric[int]() //@rank(")", tpInstLit),snippet(")", tpInstLit, "s[int]{\\}", "s[int]{\\}") 103457- 103458- "s[...]{}" //@item(tpUninstLit, "s[...]{}", "", "var") 103459- takesGeneric() //@rank(")", tpUninstLit),snippet(")", tpUninstLit, "s[${1:}]{\\}", "s[${1:a}]{\\}") 103460-} 103461- 103462-func returnTP[A int | float64](a A) A { //@item(returnTP, "returnTP", "something", "func") 103463- return a 103464-} 103465- 103466-func _() { 103467- // disabled - see issue #54822 103468- var _ int = returnTP // snippet(" //", returnTP, "returnTP[${1:}](${2:})", "returnTP[${1:A int|float64}](${2:a A})") 103469- 103470- var aa int //@item(tpInt, "aa", "int", "var") 103471- var ab float64 //@item(tpFloat, "ab", "float64", "var") 103472- returnTP[int](a) //@rank(")", tpInt, tpFloat) 103473-} 103474- 103475-func takesFunc[T any](func(T) T) { 103476- var _ func(t T) T = f //@snippet(" //", tpLitFunc, "func(t T) T {$0\\}", "func(t T) T {$0\\}") 103477-} 103478- 103479-func _() { 103480- _ = "func(...) {}" //@item(tpLitFunc, "func(...) {}", "", "var") 103481- takesFunc() //@snippet(")", tpLitFunc, "func(${1:}) ${2:} {$0\\}", "func(${1:t} ${2:T}) ${3:T} {$0\\}") 103482- takesFunc[int]() //@snippet(")", tpLitFunc, "func(i int) int {$0\\}", "func(${1:i} int) int {$0\\}") 103483-} 103484diff -urN a/gopls/internal/lsp/testdata/types/types.go b/gopls/internal/lsp/testdata/types/types.go 103485--- a/gopls/internal/lsp/testdata/types/types.go 2000-01-01 00:00:00.000000000 -0000 103486+++ b/gopls/internal/lsp/testdata/types/types.go 1970-01-01 00:00:00.000000000 +0000 103487@@ -1,18 +0,0 @@ 103488-package types 103489- 103490-type CoolAlias = int //@item(CoolAlias, "CoolAlias", "int", "type") 103491- 103492-type X struct { //@item(X_struct, "X", "struct{...}", "struct") 103493- x int 103494-} 103495- 103496-type Y struct { //@item(Y_struct, "Y", "struct{...}", "struct") 103497- y int 103498-} 103499- 103500-type Bob interface { //@item(Bob_interface, "Bob", "interface{...}", "interface") 103501- Bobby() 103502-} 103503- 103504-func (*X) Bobby() {} 103505-func (*Y) Bobby() {} 103506diff -urN a/gopls/internal/lsp/testdata/undeclared/var.go b/gopls/internal/lsp/testdata/undeclared/var.go 103507--- a/gopls/internal/lsp/testdata/undeclared/var.go 2000-01-01 00:00:00.000000000 -0000 103508+++ b/gopls/internal/lsp/testdata/undeclared/var.go 1970-01-01 00:00:00.000000000 +0000 103509@@ -1,14 +0,0 @@ 103510-package undeclared 103511- 103512-func m() int { 103513- z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") 103514- if 100 < 90 { 103515- z = 1 103516- } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") 103517- z = 4 103518- } 103519- for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") 103520- } 103521- r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") 103522- return z 103523-} 103524diff -urN a/gopls/internal/lsp/testdata/undeclared/var.go.golden b/gopls/internal/lsp/testdata/undeclared/var.go.golden 103525--- a/gopls/internal/lsp/testdata/undeclared/var.go.golden 2000-01-01 00:00:00.000000000 -0000 103526+++ b/gopls/internal/lsp/testdata/undeclared/var.go.golden 1970-01-01 00:00:00.000000000 +0000 103527@@ -1,51 +0,0 @@ 103528--- suggestedfix_var_10_6 -- 103529-package undeclared 103530- 103531-func m() int { 103532- z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") 103533- if 100 < 90 { 103534- z = 1 103535- } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") 103536- z = 4 103537- } 103538- i := 103539- for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") 103540- } 103541- r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") 103542- return z 103543-} 103544- 103545--- suggestedfix_var_4_12 -- 103546-package undeclared 103547- 103548-func m() int { 103549- y := 103550- z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") 103551- if 100 < 90 { 103552- z = 1 103553- } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") 103554- z = 4 103555- } 103556- for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") 103557- } 103558- r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") 103559- return z 103560-} 103561- 103562--- suggestedfix_var_7_18 -- 103563-package undeclared 103564- 103565-func m() int { 103566- z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") 103567- n := 103568- if 100 < 90 { 103569- z = 1 103570- } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") 103571- z = 4 103572- } 103573- for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") 103574- } 103575- r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") 103576- return z 103577-} 103578- 103579diff -urN a/gopls/internal/lsp/testdata/unimported/export_test.go b/gopls/internal/lsp/testdata/unimported/export_test.go 103580--- a/gopls/internal/lsp/testdata/unimported/export_test.go 2000-01-01 00:00:00.000000000 -0000 103581+++ b/gopls/internal/lsp/testdata/unimported/export_test.go 1970-01-01 00:00:00.000000000 +0000 103582@@ -1,3 +0,0 @@ 103583-package unimported 103584- 103585-var TestExport int //@item(testexport, "TestExport", "var (from \"golang.org/lsptests/unimported\")", "var") 103586diff -urN a/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go 103587--- a/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go 2000-01-01 00:00:00.000000000 -0000 103588+++ b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go 1970-01-01 00:00:00.000000000 +0000 103589@@ -1,16 +0,0 @@ 103590-package unimported 103591- 103592-import ( 103593- _ "context" 103594- 103595- "golang.org/lsptests/baz" 103596- _ "golang.org/lsptests/signature" // provide type information for unimported completions in the other file 103597-) 103598- 103599-func _() { 103600- foo.StructFoo{} //@item(litFooStructFoo, "foo.StructFoo{}", "struct{...}", "struct") 103601- 103602- // We get the literal completion for "foo.StructFoo{}" even though we haven't 103603- // imported "foo" yet. 103604- baz.FooStruct = f //@snippet(" //", litFooStructFoo, "foo.StructFoo{$0\\}", "foo.StructFoo{$0\\}") 103605-} 103606diff -urN a/gopls/internal/lsp/testdata/unimported/unimported.go.in b/gopls/internal/lsp/testdata/unimported/unimported.go.in 103607--- a/gopls/internal/lsp/testdata/unimported/unimported.go.in 2000-01-01 00:00:00.000000000 -0000 103608+++ b/gopls/internal/lsp/testdata/unimported/unimported.go.in 1970-01-01 00:00:00.000000000 +0000 103609@@ -1,23 +0,0 @@ 103610-package unimported 103611- 103612-func _() { 103613- http //@unimported("p", nethttp) 103614- // container/ring is extremely unlikely to be imported by anything, so shouldn't have type information. 103615- ring.Ring //@unimported("Ring", ringring) 103616- signature.Foo //@unimported("Foo", signaturefoo) 103617- 103618- context.Bac //@unimported(" //", contextBackground) 103619-} 103620- 103621-// Create markers for unimported std lib packages. Only for use by this test. 103622-/* http */ //@item(nethttp, "http", "\"net/http\"", "package") 103623- 103624-/* ring.Ring */ //@item(ringring, "Ring", "(from \"container/ring\")", "var") 103625- 103626-/* signature.Foo */ //@item(signaturefoo, "Foo", "func (from \"golang.org/lsptests/signature\")", "func") 103627- 103628-/* context.Background */ //@item(contextBackground, "Background", "func (from \"context\")", "func") 103629- 103630-// Now that we no longer type-check imported completions, 103631-// we don't expect the context.Background().Err method (see golang/go#58663). 103632-/* context.Background().Err */ //@item(contextBackgroundErr, "Background().Err", "func (from \"context\")", "method") 103633diff -urN a/gopls/internal/lsp/testdata/unimported/x_test.go b/gopls/internal/lsp/testdata/unimported/x_test.go 103634--- a/gopls/internal/lsp/testdata/unimported/x_test.go 2000-01-01 00:00:00.000000000 -0000 103635+++ b/gopls/internal/lsp/testdata/unimported/x_test.go 1970-01-01 00:00:00.000000000 +0000 103636@@ -1,9 +0,0 @@ 103637-package unimported_test 103638- 103639-import ( 103640- "testing" 103641-) 103642- 103643-func TestSomething(t *testing.T) { 103644- _ = unimported.TestExport //@unimported("TestExport", testexport) 103645-} 103646diff -urN a/gopls/internal/lsp/testdata/unresolved/unresolved.go.in b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in 103647--- a/gopls/internal/lsp/testdata/unresolved/unresolved.go.in 2000-01-01 00:00:00.000000000 -0000 103648+++ b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in 1970-01-01 00:00:00.000000000 +0000 103649@@ -1,6 +0,0 @@ 103650-package unresolved 103651- 103652-func foo(interface{}) { 103653- // don't crash on fake "resolved" type 103654- foo(func(i, j f //@complete(" //") 103655-} 103656diff -urN a/gopls/internal/lsp/testdata/unsafe/unsafe.go b/gopls/internal/lsp/testdata/unsafe/unsafe.go 103657--- a/gopls/internal/lsp/testdata/unsafe/unsafe.go 2000-01-01 00:00:00.000000000 -0000 103658+++ b/gopls/internal/lsp/testdata/unsafe/unsafe.go 1970-01-01 00:00:00.000000000 +0000 103659@@ -1,13 +0,0 @@ 103660-package unsafe 103661- 103662-import ( 103663- "unsafe" 103664-) 103665- 103666-// Pre-set this marker, as we don't have a "source" for it in this package. 103667-/* unsafe.Sizeof */ //@item(Sizeof, "Sizeof", "invalid type", "text") 103668- 103669-func _() { 103670- x := struct{}{} 103671- _ = unsafe.Sizeof(x) //@complete("z", Sizeof) 103672-} 103673diff -urN a/gopls/internal/lsp/testdata/variadic/variadic.go.in b/gopls/internal/lsp/testdata/variadic/variadic.go.in 103674--- a/gopls/internal/lsp/testdata/variadic/variadic.go.in 2000-01-01 00:00:00.000000000 -0000 103675+++ b/gopls/internal/lsp/testdata/variadic/variadic.go.in 1970-01-01 00:00:00.000000000 +0000 103676@@ -1,38 +0,0 @@ 103677-package variadic 103678- 103679-func foo(i int, strs ...string) {} 103680- 103681-func bar() []string { //@item(vFunc, "bar", "func() []string", "func") 103682- return nil 103683-} 103684- 103685-func _() { 103686- var ( 103687- i int //@item(vInt, "i", "int", "var") 103688- s string //@item(vStr, "s", "string", "var") 103689- ss []string //@item(vStrSlice, "ss", "[]string", "var") 103690- v interface{} //@item(vIntf, "v", "interface{}", "var") 103691- ) 103692- 103693- foo() //@rank(")", vInt, vStr),rank(")", vInt, vStrSlice) 103694- foo(123, ) //@rank(")", vStr, vInt),rank(")", vStrSlice, vInt) 103695- foo(123, "", ) //@rank(")", vStr, vInt),rank(")", vStr, vStrSlice) 103696- foo(123, s, "") //@rank(", \"", vStr, vStrSlice) 103697- 103698- // snippet will add the "..." for you 103699- foo(123, ) //@snippet(")", vStrSlice, "ss...", "ss..."),snippet(")", vFunc, "bar()...", "bar()..."),snippet(")", vStr, "s", "s") 103700- 103701- // don't add "..." for interface{} 103702- foo(123, ) //@snippet(")", vIntf, "v", "v") 103703-} 103704- 103705-func qux(...func()) {} 103706-func f() {} //@item(vVarArg, "f", "func()", "func") 103707- 103708-func _() { 103709- qux(f) //@snippet(")", vVarArg, "f", "f") 103710-} 103711- 103712-func _() { 103713- foo(0, []string{}...) //@complete(")") 103714-} 103715diff -urN a/gopls/internal/lsp/testdata/variadic/variadic_intf.go b/gopls/internal/lsp/testdata/variadic/variadic_intf.go 103716--- a/gopls/internal/lsp/testdata/variadic/variadic_intf.go 2000-01-01 00:00:00.000000000 -0000 103717+++ b/gopls/internal/lsp/testdata/variadic/variadic_intf.go 1970-01-01 00:00:00.000000000 +0000 103718@@ -1,21 +0,0 @@ 103719-package variadic 103720- 103721-type baz interface { 103722- baz() 103723-} 103724- 103725-func wantsBaz(...baz) {} 103726- 103727-type bazImpl int 103728- 103729-func (bazImpl) baz() {} 103730- 103731-func _() { 103732- var ( 103733- impls []bazImpl //@item(vImplSlice, "impls", "[]bazImpl", "var") 103734- impl bazImpl //@item(vImpl, "impl", "bazImpl", "var") 103735- bazes []baz //@item(vIntfSlice, "bazes", "[]baz", "var") 103736- ) 103737- 103738- wantsBaz() //@rank(")", vImpl, vImplSlice),rank(")", vIntfSlice, vImplSlice) 103739-} 103740diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/a/a.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go 103741--- a/gopls/internal/lsp/testdata/workspacesymbol/a/a.go 2000-01-01 00:00:00.000000000 -0000 103742+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go 1970-01-01 00:00:00.000000000 +0000 103743@@ -1,9 +0,0 @@ 103744-package a 103745- 103746-var RandomGopherVariableA = "a" 103747- 103748-const RandomGopherConstantA = "a" 103749- 103750-const ( 103751- randomgopherinvariable = iota 103752-) 103753diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go 103754--- a/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go 2000-01-01 00:00:00.000000000 -0000 103755+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go 1970-01-01 00:00:00.000000000 +0000 103756@@ -1,3 +0,0 @@ 103757-package a 103758- 103759-var RandomGopherTestVariableA = "a" 103760diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go 103761--- a/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go 2000-01-01 00:00:00.000000000 -0000 103762+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go 1970-01-01 00:00:00.000000000 +0000 103763@@ -1,3 +0,0 @@ 103764-package a_test 103765- 103766-var RandomGopherXTestVariableA = "a" 103767diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/b/b.go b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go 103768--- a/gopls/internal/lsp/testdata/workspacesymbol/b/b.go 2000-01-01 00:00:00.000000000 -0000 103769+++ b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go 1970-01-01 00:00:00.000000000 +0000 103770@@ -1,7 +0,0 @@ 103771-package b 103772- 103773-var RandomGopherVariableB = "b" 103774- 103775-type RandomGopherStructB struct { 103776- Bar int 103777-} 103778diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go 103779--- a/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go 2000-01-01 00:00:00.000000000 -0000 103780+++ b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go 1970-01-01 00:00:00.000000000 +0000 103781@@ -1,10 +0,0 @@ 103782-package main 103783- 103784-type T struct{} 103785- 103786-// We should accept all valid receiver syntax when scanning symbols. 103787-func (*(T)) m1() {} 103788-func (*T) m2() {} 103789-func (T) m3() {} 103790-func ((T)) m4() {} 103791-func ((*T)) m5() {} 103792diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/main.go b/gopls/internal/lsp/testdata/workspacesymbol/main.go 103793--- a/gopls/internal/lsp/testdata/workspacesymbol/main.go 2000-01-01 00:00:00.000000000 -0000 103794+++ b/gopls/internal/lsp/testdata/workspacesymbol/main.go 1970-01-01 00:00:00.000000000 +0000 103795@@ -1,47 +0,0 @@ 103796-package main 103797- 103798-import ( 103799- "encoding/json" 103800- "fmt" 103801-) 103802- 103803-func main() { // function 103804- fmt.Println("Hello") 103805-} 103806- 103807-var myvar int // variable 103808- 103809-type myType string // basic type 103810- 103811-type myDecoder json.Decoder // to use the encoding/json import 103812- 103813-func (m *myType) Blahblah() {} // method 103814- 103815-type myStruct struct { // struct type 103816- myStructField int // struct field 103817-} 103818- 103819-type myInterface interface { // interface 103820- DoSomeCoolStuff() string // interface method 103821-} 103822- 103823-type embed struct { 103824- myStruct 103825- 103826- nestedStruct struct { 103827- nestedField int 103828- 103829- nestedStruct2 struct { 103830- int 103831- } 103832- } 103833- 103834- nestedInterface interface { 103835- myInterface 103836- nestedMethod() 103837- } 103838-} 103839- 103840-func Dunk() int { return 0 } 103841- 103842-func dunk() {} 103843diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/p/p.go b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go 103844--- a/gopls/internal/lsp/testdata/workspacesymbol/p/p.go 2000-01-01 00:00:00.000000000 -0000 103845+++ b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go 1970-01-01 00:00:00.000000000 +0000 103846@@ -1,3 +0,0 @@ 103847-package p 103848- 103849-const Message = "Hello World." // constant 103850diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/query.go b/gopls/internal/lsp/testdata/workspacesymbol/query.go 103851--- a/gopls/internal/lsp/testdata/workspacesymbol/query.go 2000-01-01 00:00:00.000000000 -0000 103852+++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go 1970-01-01 00:00:00.000000000 +0000 103853@@ -1,29 +0,0 @@ 103854-package main 103855- 103856-// Contains all of the workspace symbol queries. 103857- 103858-// -- Fuzzy matching -- 103859-//@workspacesymbolfuzzy("rgop") 103860-//@workspacesymbolfuzzy("randoma") 103861-//@workspacesymbolfuzzy("randomb") 103862- 103863-// -- Case sensitive -- 103864-//@workspacesymbolcasesensitive("main.main") 103865-//@workspacesymbolcasesensitive("p.Message") 103866-//@workspacesymbolcasesensitive("main.myvar") 103867-//@workspacesymbolcasesensitive("main.myType") 103868-//@workspacesymbolcasesensitive("main.myType.Blahblah") 103869-//@workspacesymbolcasesensitive("main.myStruct") 103870-//@workspacesymbolcasesensitive("main.myStruct.myStructField") 103871-//@workspacesymbolcasesensitive("main.myInterface") 103872-//@workspacesymbolcasesensitive("main.myInterface.DoSomeCoolStuff") 103873-//@workspacesymbolcasesensitive("main.embed.myStruct") 103874-//@workspacesymbolcasesensitive("main.embed.nestedStruct.nestedStruct2.int") 103875-//@workspacesymbolcasesensitive("main.embed.nestedInterface.myInterface") 103876-//@workspacesymbolcasesensitive("main.embed.nestedInterface.nestedMethod") 103877-//@workspacesymbolcasesensitive("dunk") 103878-//@workspacesymbolcasesensitive("Dunk") 103879- 103880-// -- Standard -- 103881-//@workspacesymbol("") 103882-//@workspacesymbol("randomgophervar") 103883diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden 103884--- a/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden 2000-01-01 00:00:00.000000000 -0000 103885+++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden 1970-01-01 00:00:00.000000000 +0000 103886@@ -1,83 +0,0 @@ 103887--- workspace_symbol-caseinsensitive- -- 103888- 103889- 103890--- workspace_symbol-caseinsensitive-randomgophervar -- 103891-workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable 103892-workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable 103893- 103894--- workspace_symbol-casesensitive-Dunk -- 103895-workspacesymbol/main.go:45:6-10 Dunk Function 103896- 103897--- workspace_symbol-casesensitive-dunk -- 103898-workspacesymbol/main.go:47:6-10 dunk Function 103899- 103900--- workspace_symbol-casesensitive-main.embed.myStruct -- 103901-workspacesymbol/main.go:29:2-10 main.embed.myStruct Field 103902- 103903--- workspace_symbol-casesensitive-main.embed.nestedInterface.myInterface -- 103904-workspacesymbol/main.go:40:3-14 main.embed.nestedInterface.myInterface Interface 103905- 103906--- workspace_symbol-casesensitive-main.embed.nestedInterface.nestedMethod -- 103907-workspacesymbol/main.go:41:3-15 main.embed.nestedInterface.nestedMethod Method 103908- 103909--- workspace_symbol-casesensitive-main.embed.nestedStruct.nestedStruct2.int -- 103910-workspacesymbol/main.go:35:4-7 main.embed.nestedStruct.nestedStruct2.int Field 103911- 103912--- workspace_symbol-casesensitive-main.main -- 103913-workspacesymbol/main.go:8:6-10 main.main Function 103914- 103915--- workspace_symbol-casesensitive-main.myInterface -- 103916-workspacesymbol/main.go:24:6-17 main.myInterface Interface 103917-workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method 103918- 103919--- workspace_symbol-casesensitive-main.myInterface.DoSomeCoolStuff -- 103920-workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method 103921- 103922--- workspace_symbol-casesensitive-main.myStruct -- 103923-workspacesymbol/main.go:20:6-14 main.myStruct Struct 103924-workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field 103925- 103926--- workspace_symbol-casesensitive-main.myStruct.myStructField -- 103927-workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field 103928- 103929--- workspace_symbol-casesensitive-main.myType -- 103930-workspacesymbol/main.go:14:6-12 main.myType Class 103931-workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method 103932- 103933--- workspace_symbol-casesensitive-main.myType.Blahblah -- 103934-workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method 103935- 103936--- workspace_symbol-casesensitive-main.myvar -- 103937-workspacesymbol/main.go:12:5-10 main.myvar Variable 103938- 103939--- workspace_symbol-casesensitive-p.Message -- 103940-workspacesymbol/p/p.go:3:7-14 p.Message Constant 103941- 103942--- workspace_symbol-fuzzy-randoma -- 103943-workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable 103944-workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant 103945-workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant 103946-workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable 103947-workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable 103948-workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable 103949-workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field 103950- 103951--- workspace_symbol-fuzzy-randomb -- 103952-workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable 103953-workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant 103954-workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable 103955-workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable 103956-workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable 103957-workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct 103958-workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field 103959- 103960--- workspace_symbol-fuzzy-rgop -- 103961-workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable 103962-workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant 103963-workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant 103964-workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable 103965-workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable 103966-workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable 103967-workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct 103968-workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field 103969- 103970diff -urN a/gopls/internal/lsp/tests/compare/text.go b/gopls/internal/lsp/tests/compare/text.go 103971--- a/gopls/internal/lsp/tests/compare/text.go 2000-01-01 00:00:00.000000000 -0000 103972+++ b/gopls/internal/lsp/tests/compare/text.go 1970-01-01 00:00:00.000000000 +0000 103973@@ -1,49 +0,0 @@ 103974-// Copyright 2022 The Go Authors. All rights reserved. 103975-// Use of this source code is governed by a BSD-style 103976-// license that can be found in the LICENSE file. 103977- 103978-package compare 103979- 103980-import ( 103981- "bytes" 103982- 103983- "golang.org/x/tools/internal/diff" 103984-) 103985- 103986-// Text returns a formatted unified diff of the edits to go from want to 103987-// got, returning "" if and only if want == got. 103988-// 103989-// This function is intended for use in testing, and panics if any error occurs 103990-// while computing the diff. It is not sufficiently tested for production use. 103991-func Text(want, got string) string { 103992- return NamedText("want", "got", want, got) 103993-} 103994- 103995-// NamedText is like text, but allows passing custom names of the 'want' and 103996-// 'got' content. 103997-func NamedText(wantName, gotName, want, got string) string { 103998- if want == got { 103999- return "" 104000- } 104001- 104002- // Add newlines to avoid verbose newline messages ("No newline at end of file"). 104003- unified := diff.Unified(wantName, gotName, want+"\n", got+"\n") 104004- 104005- // Defensively assert that we get an actual diff, so that we guarantee the 104006- // invariant that we return "" if and only if want == got. 104007- // 104008- // This is probably unnecessary, but convenient. 104009- if unified == "" { 104010- panic("empty diff for non-identical input") 104011- } 104012- 104013- return unified 104014-} 104015- 104016-// Bytes is like Text but using byte slices. 104017-func Bytes(want, got []byte) string { 104018- if bytes.Equal(want, got) { 104019- return "" // common case 104020- } 104021- return Text(string(want), string(got)) 104022-} 104023diff -urN a/gopls/internal/lsp/tests/compare/text_test.go b/gopls/internal/lsp/tests/compare/text_test.go 104024--- a/gopls/internal/lsp/tests/compare/text_test.go 2000-01-01 00:00:00.000000000 -0000 104025+++ b/gopls/internal/lsp/tests/compare/text_test.go 1970-01-01 00:00:00.000000000 +0000 104026@@ -1,28 +0,0 @@ 104027-// Copyright 2022 The Go Authors. All rights reserved. 104028-// Use of this source code is governed by a BSD-style 104029-// license that can be found in the LICENSE file. 104030- 104031-package compare_test 104032- 104033-import ( 104034- "testing" 104035- 104036- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 104037-) 104038- 104039-func TestText(t *testing.T) { 104040- tests := []struct { 104041- got, want, wantDiff string 104042- }{ 104043- {"", "", ""}, 104044- {"equal", "equal", ""}, 104045- {"a", "b", "--- want\n+++ got\n@@ -1 +1 @@\n-b\n+a\n"}, 104046- {"a\nd\nc\n", "a\nb\nc\n", "--- want\n+++ got\n@@ -1,4 +1,4 @@\n a\n-b\n+d\n c\n \n"}, 104047- } 104048- 104049- for _, test := range tests { 104050- if gotDiff := compare.Text(test.want, test.got); gotDiff != test.wantDiff { 104051- t.Errorf("compare.Text(%q, %q) =\n%q, want\n%q", test.want, test.got, gotDiff, test.wantDiff) 104052- } 104053- } 104054-} 104055diff -urN a/gopls/internal/lsp/tests/markdown_go118.go b/gopls/internal/lsp/tests/markdown_go118.go 104056--- a/gopls/internal/lsp/tests/markdown_go118.go 2000-01-01 00:00:00.000000000 -0000 104057+++ b/gopls/internal/lsp/tests/markdown_go118.go 1970-01-01 00:00:00.000000000 +0000 104058@@ -1,69 +0,0 @@ 104059-// Copyright 2022 The Go Authors. All rights reserved. 104060-// Use of this source code is governed by a BSD-style 104061-// license that can be found in the LICENSE file. 104062- 104063-//go:build !go1.19 104064-// +build !go1.19 104065- 104066-package tests 104067- 104068-import ( 104069- "regexp" 104070- "strings" 104071- 104072- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 104073-) 104074- 104075-// DiffMarkdown compares two markdown strings produced by parsing go doc 104076-// comments. 104077-// 104078-// For go1.19 and later, markdown conversion is done using go/doc/comment. 104079-// Compared to the newer version, the older version has extra escapes, and 104080-// treats code blocks slightly differently. 104081-func DiffMarkdown(want, got string) string { 104082- want = normalizeMarkdown(want) 104083- got = normalizeMarkdown(got) 104084- return compare.Text(want, got) 104085-} 104086- 104087-// normalizeMarkdown normalizes whitespace and escaping of the input string, to 104088-// eliminate differences between the Go 1.18 and Go 1.19 generated markdown for 104089-// doc comments. Note that it does not normalize to either the 1.18 or 1.19 104090-// formatting: it simplifies both so that they may be compared. 104091-// 104092-// This function may need to be adjusted as we encounter more differences in 104093-// the generated text. 104094-// 104095-// TODO(rfindley): this function doesn't correctly handle the case of 104096-// multi-line docstrings. 104097-func normalizeMarkdown(input string) string { 104098- input = strings.TrimSpace(input) 104099- 104100- // For simplicity, eliminate blank lines. 104101- input = regexp.MustCompile("\n+").ReplaceAllString(input, "\n") 104102- 104103- // Replace common escaped characters with their unescaped version. 104104- // 104105- // This list may not be exhaustive: it was just sufficient to make tests 104106- // pass. 104107- input = strings.NewReplacer( 104108- `\\`, ``, 104109- `\@`, `@`, 104110- `\(`, `(`, 104111- `\)`, `)`, 104112- `\{`, `{`, 104113- `\}`, `}`, 104114- `\"`, `"`, 104115- `\.`, `.`, 104116- `\-`, `-`, 104117- `\'`, `'`, 104118- `\+`, `+`, 104119- `\~`, `~`, 104120- `\=`, `=`, 104121- `\:`, `:`, 104122- `\?`, `?`, 104123- `\n\n\n`, `\n\n`, // Note that these are *escaped* newlines. 104124- ).Replace(input) 104125- 104126- return input 104127-} 104128diff -urN a/gopls/internal/lsp/tests/markdown_go119.go b/gopls/internal/lsp/tests/markdown_go119.go 104129--- a/gopls/internal/lsp/tests/markdown_go119.go 2000-01-01 00:00:00.000000000 -0000 104130+++ b/gopls/internal/lsp/tests/markdown_go119.go 1970-01-01 00:00:00.000000000 +0000 104131@@ -1,22 +0,0 @@ 104132-// Copyright 2022 The Go Authors. All rights reserved. 104133-// Use of this source code is governed by a BSD-style 104134-// license that can be found in the LICENSE file. 104135- 104136-//go:build go1.19 104137-// +build go1.19 104138- 104139-package tests 104140- 104141-import ( 104142- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 104143-) 104144- 104145-// DiffMarkdown compares two markdown strings produced by parsing go doc 104146-// comments. 104147-// 104148-// For go1.19 and later, markdown conversion is done using go/doc/comment. 104149-// Compared to the newer version, the older version has extra escapes, and 104150-// treats code blocks slightly differently. 104151-func DiffMarkdown(want, got string) string { 104152- return compare.Text(want, got) 104153-} 104154diff -urN a/gopls/internal/lsp/tests/normalizer.go b/gopls/internal/lsp/tests/normalizer.go 104155--- a/gopls/internal/lsp/tests/normalizer.go 2000-01-01 00:00:00.000000000 -0000 104156+++ b/gopls/internal/lsp/tests/normalizer.go 1970-01-01 00:00:00.000000000 +0000 104157@@ -1,113 +0,0 @@ 104158-// Copyright 2019 The Go Authors. All rights reserved. 104159-// Use of this source code is governed by a BSD-style 104160-// license that can be found in the LICENSE file. 104161- 104162-package tests 104163- 104164-import ( 104165- "path/filepath" 104166- "strconv" 104167- "strings" 104168- 104169- "golang.org/x/tools/go/packages/packagestest" 104170-) 104171- 104172-type Normalizer struct { 104173- path string 104174- slashed string 104175- escaped string 104176- fragment string 104177-} 104178- 104179-func CollectNormalizers(exported *packagestest.Exported) []Normalizer { 104180- // build the path normalizing patterns 104181- var normalizers []Normalizer 104182- for _, m := range exported.Modules { 104183- for fragment := range m.Files { 104184- n := Normalizer{ 104185- path: exported.File(m.Name, fragment), 104186- fragment: fragment, 104187- } 104188- if n.slashed = filepath.ToSlash(n.path); n.slashed == n.path { 104189- n.slashed = "" 104190- } 104191- quoted := strconv.Quote(n.path) 104192- if n.escaped = quoted[1 : len(quoted)-1]; n.escaped == n.path { 104193- n.escaped = "" 104194- } 104195- normalizers = append(normalizers, n) 104196- } 104197- } 104198- return normalizers 104199-} 104200- 104201-// Normalize replaces all paths present in s with just the fragment portion 104202-// this is used to make golden files not depend on the temporary paths of the files 104203-func Normalize(s string, normalizers []Normalizer) string { 104204- type entry struct { 104205- path string 104206- index int 104207- fragment string 104208- } 104209- var match []entry 104210- // collect the initial state of all the matchers 104211- for _, n := range normalizers { 104212- index := strings.Index(s, n.path) 104213- if index >= 0 { 104214- match = append(match, entry{n.path, index, n.fragment}) 104215- } 104216- if n.slashed != "" { 104217- index := strings.Index(s, n.slashed) 104218- if index >= 0 { 104219- match = append(match, entry{n.slashed, index, n.fragment}) 104220- } 104221- } 104222- if n.escaped != "" { 104223- index := strings.Index(s, n.escaped) 104224- if index >= 0 { 104225- match = append(match, entry{n.escaped, index, n.fragment}) 104226- } 104227- } 104228- } 104229- // result should be the same or shorter than the input 104230- var b strings.Builder 104231- last := 0 104232- for { 104233- // find the nearest path match to the start of the buffer 104234- next := -1 104235- nearest := len(s) 104236- for i, c := range match { 104237- if c.index >= 0 && nearest > c.index { 104238- nearest = c.index 104239- next = i 104240- } 104241- } 104242- // if there are no matches, we copy the rest of the string and are done 104243- if next < 0 { 104244- b.WriteString(s[last:]) 104245- return b.String() 104246- } 104247- // we have a match 104248- n := &match[next] 104249- // copy up to the start of the match 104250- b.WriteString(s[last:n.index]) 104251- // skip over the filename 104252- last = n.index + len(n.path) 104253- 104254- // Hack: In multi-module mode, we add a "testmodule/" prefix, so trim 104255- // it from the fragment. 104256- fragment := n.fragment 104257- if strings.HasPrefix(fragment, "testmodule") { 104258- split := strings.Split(filepath.ToSlash(fragment), "/") 104259- fragment = filepath.FromSlash(strings.Join(split[1:], "/")) 104260- } 104261- 104262- // add in the fragment instead 104263- b.WriteString(fragment) 104264- // see what the next match for this path is 104265- n.index = strings.Index(s[last:], n.path) 104266- if n.index >= 0 { 104267- n.index += last 104268- } 104269- } 104270-} 104271diff -urN a/gopls/internal/lsp/tests/README.md b/gopls/internal/lsp/tests/README.md 104272--- a/gopls/internal/lsp/tests/README.md 2000-01-01 00:00:00.000000000 -0000 104273+++ b/gopls/internal/lsp/tests/README.md 1970-01-01 00:00:00.000000000 +0000 104274@@ -1,66 +0,0 @@ 104275-# Testing 104276- 104277-LSP has "marker tests" defined in `internal/lsp/testdata`, as well as 104278-traditional tests. 104279- 104280-## Marker tests 104281- 104282-Marker tests have a standard input file, like 104283-`internal/lsp/testdata/foo/bar.go`, and some may have a corresponding golden 104284-file, like `internal/lsp/testdata/foo/bar.go.golden`. The former is the "input" 104285-and the latter is the expected output. 104286- 104287-Each input file contains annotations like 104288-`//@suggestedfix("}", "refactor.rewrite", "Fill anonymous struct")`. These annotations are interpreted by 104289-test runners to perform certain actions. The expected output after those actions 104290-is encoded in the golden file. 104291- 104292-When tests are run, each annotation results in a new subtest, which is encoded 104293-in the golden file with a heading like, 104294- 104295-```bash 104296--- suggestedfix_bar_11_21 -- 104297-// expected contents go here 104298--- suggestedfix_bar_13_20 -- 104299-// expected contents go here 104300-``` 104301- 104302-The format of these headings vary: they are defined by the 104303-[`Golden`](https://pkg.go.dev/golang.org/x/tools/gopls/internal/lsp/tests#Data.Golden) 104304-function for each annotation. In the case above, the format is: annotation 104305-name, file name, annotation line location, annotation character location. 104306- 104307-So, if `internal/lsp/testdata/foo/bar.go` has three `suggestedfix` annotations, 104308-the golden file should have three headers with `suggestedfix_bar_xx_yy` 104309-headings. 104310- 104311-To see a list of all available annotations, see the exported "expectations" in 104312-[tests.go](https://github.com/golang/tools/blob/299f270db45902e93469b1152fafed034bb3f033/internal/lsp/tests/tests.go#L418-L447). 104313- 104314-To run marker tests, 104315- 104316-```bash 104317-cd /path/to/tools 104318- 104319-# The marker tests are located in "internal/lsp", "internal/lsp/cmd, and 104320-# "internal/lsp/source". 104321-go test ./internal/lsp/... 104322-``` 104323- 104324-There are quite a lot of marker tests, so to run one individually, pass the test 104325-path and heading into a -run argument: 104326- 104327-```bash 104328-cd /path/to/tools 104329-go test ./internal/lsp/... -v -run TestLSP/Modules/SuggestedFix/bar_11_21 104330-``` 104331- 104332-## Resetting marker tests 104333- 104334-Sometimes, a change is made to lsp that requires a change to multiple golden 104335-files. When this happens, you can run, 104336- 104337-```bash 104338-cd /path/to/tools 104339-./internal/lsp/reset_golden.sh 104340-``` 104341diff -urN a/gopls/internal/lsp/tests/tests.go b/gopls/internal/lsp/tests/tests.go 104342--- a/gopls/internal/lsp/tests/tests.go 2000-01-01 00:00:00.000000000 -0000 104343+++ b/gopls/internal/lsp/tests/tests.go 1970-01-01 00:00:00.000000000 +0000 104344@@ -1,1446 +0,0 @@ 104345-// Copyright 2019 The Go Authors. All rights reserved. 104346-// Use of this source code is governed by a BSD-style 104347-// license that can be found in the LICENSE file. 104348- 104349-// Package tests exports functionality to be used across a variety of gopls tests. 104350-package tests 104351- 104352-import ( 104353- "bytes" 104354- "context" 104355- "flag" 104356- "fmt" 104357- "go/ast" 104358- "go/token" 104359- "io" 104360- "io/ioutil" 104361- "os" 104362- "path/filepath" 104363- "regexp" 104364- "sort" 104365- "strconv" 104366- "strings" 104367- "sync" 104368- "testing" 104369- "time" 104370- 104371- "golang.org/x/tools/go/expect" 104372- "golang.org/x/tools/go/packages" 104373- "golang.org/x/tools/go/packages/packagestest" 104374- "golang.org/x/tools/gopls/internal/lsp/command" 104375- "golang.org/x/tools/gopls/internal/lsp/protocol" 104376- "golang.org/x/tools/gopls/internal/lsp/safetoken" 104377- "golang.org/x/tools/gopls/internal/lsp/source" 104378- "golang.org/x/tools/gopls/internal/lsp/source/completion" 104379- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 104380- "golang.org/x/tools/gopls/internal/span" 104381- "golang.org/x/tools/internal/testenv" 104382- "golang.org/x/tools/internal/typeparams" 104383- "golang.org/x/tools/txtar" 104384-) 104385- 104386-const ( 104387- overlayFileSuffix = ".overlay" 104388- goldenFileSuffix = ".golden" 104389- inFileSuffix = ".in" 104390- 104391- // The module path containing the testdata packages. 104392- // 104393- // Warning: the length of this module path matters, as we have bumped up 104394- // against command-line limitations on windows (golang/go#54800). 104395- testModule = "golang.org/lsptests" 104396-) 104397- 104398-var summaryFile = "summary.txt" 104399- 104400-func init() { 104401- if typeparams.Enabled { 104402- summaryFile = "summary_go1.18.txt" 104403- } 104404-} 104405- 104406-var UpdateGolden = flag.Bool("golden", false, "Update golden files") 104407- 104408-// These type names apparently avoid the need to repeat the 104409-// type in the field name and the make() expression. 104410-type CallHierarchy = map[span.Span]*CallHierarchyResult 104411-type CodeLens = map[span.URI][]protocol.CodeLens 104412-type Diagnostics = map[span.URI][]*source.Diagnostic 104413-type CompletionItems = map[token.Pos]*completion.CompletionItem 104414-type Completions = map[span.Span][]Completion 104415-type CompletionSnippets = map[span.Span][]CompletionSnippet 104416-type UnimportedCompletions = map[span.Span][]Completion 104417-type DeepCompletions = map[span.Span][]Completion 104418-type FuzzyCompletions = map[span.Span][]Completion 104419-type CaseSensitiveCompletions = map[span.Span][]Completion 104420-type RankCompletions = map[span.Span][]Completion 104421-type FoldingRanges = []span.Span 104422-type Formats = []span.Span 104423-type Imports = []span.Span 104424-type SemanticTokens = []span.Span 104425-type SuggestedFixes = map[span.Span][]SuggestedFix 104426-type FunctionExtractions = map[span.Span]span.Span 104427-type MethodExtractions = map[span.Span]span.Span 104428-type Definitions = map[span.Span]Definition 104429-type Implementations = map[span.Span][]span.Span 104430-type Highlights = map[span.Span][]span.Span 104431-type References = map[span.Span][]span.Span 104432-type Renames = map[span.Span]string 104433-type PrepareRenames = map[span.Span]*source.PrepareItem 104434-type Symbols = map[span.URI][]*symbol 104435-type InlayHints = []span.Span 104436-type WorkspaceSymbols = map[WorkspaceSymbolsTestType]map[span.URI][]string 104437-type Signatures = map[span.Span]*protocol.SignatureHelp 104438-type Links = map[span.URI][]Link 104439-type AddImport = map[span.URI]string 104440-type SelectionRanges = []span.Span 104441- 104442-type Data struct { 104443- Config packages.Config 104444- Exported *packagestest.Exported 104445- CallHierarchy CallHierarchy 104446- CodeLens CodeLens 104447- Diagnostics Diagnostics 104448- CompletionItems CompletionItems 104449- Completions Completions 104450- CompletionSnippets CompletionSnippets 104451- UnimportedCompletions UnimportedCompletions 104452- DeepCompletions DeepCompletions 104453- FuzzyCompletions FuzzyCompletions 104454- CaseSensitiveCompletions CaseSensitiveCompletions 104455- RankCompletions RankCompletions 104456- FoldingRanges FoldingRanges 104457- Formats Formats 104458- Imports Imports 104459- SemanticTokens SemanticTokens 104460- SuggestedFixes SuggestedFixes 104461- FunctionExtractions FunctionExtractions 104462- MethodExtractions MethodExtractions 104463- Definitions Definitions 104464- Implementations Implementations 104465- Highlights Highlights 104466- References References 104467- Renames Renames 104468- InlayHints InlayHints 104469- PrepareRenames PrepareRenames 104470- Symbols Symbols 104471- WorkspaceSymbols WorkspaceSymbols 104472- Signatures Signatures 104473- Links Links 104474- AddImport AddImport 104475- SelectionRanges SelectionRanges 104476- 104477- fragments map[string]string 104478- dir string 104479- golden map[string]*Golden 104480- mode string 104481- 104482- ModfileFlagAvailable bool 104483- 104484- mappersMu sync.Mutex 104485- mappers map[span.URI]*protocol.Mapper 104486-} 104487- 104488-// The Tests interface abstracts the LSP-based implementation of the marker 104489-// test operators (such as @codelens) appearing in files beneath ../testdata/. 104490-// 104491-// TODO(adonovan): reduce duplication; see https://github.com/golang/go/issues/54845. 104492-// There is only one implementation (*runner in ../lsp_test.go), so 104493-// we can abolish the interface now. 104494-type Tests interface { 104495- CallHierarchy(*testing.T, span.Span, *CallHierarchyResult) 104496- CodeLens(*testing.T, span.URI, []protocol.CodeLens) 104497- Diagnostics(*testing.T, span.URI, []*source.Diagnostic) 104498- Completion(*testing.T, span.Span, Completion, CompletionItems) 104499- CompletionSnippet(*testing.T, span.Span, CompletionSnippet, bool, CompletionItems) 104500- UnimportedCompletion(*testing.T, span.Span, Completion, CompletionItems) 104501- DeepCompletion(*testing.T, span.Span, Completion, CompletionItems) 104502- FuzzyCompletion(*testing.T, span.Span, Completion, CompletionItems) 104503- CaseSensitiveCompletion(*testing.T, span.Span, Completion, CompletionItems) 104504- RankCompletion(*testing.T, span.Span, Completion, CompletionItems) 104505- FoldingRanges(*testing.T, span.Span) 104506- Format(*testing.T, span.Span) 104507- Import(*testing.T, span.Span) 104508- SemanticTokens(*testing.T, span.Span) 104509- SuggestedFix(*testing.T, span.Span, []SuggestedFix, int) 104510- FunctionExtraction(*testing.T, span.Span, span.Span) 104511- MethodExtraction(*testing.T, span.Span, span.Span) 104512- Definition(*testing.T, span.Span, Definition) 104513- Implementation(*testing.T, span.Span, []span.Span) 104514- Highlight(*testing.T, span.Span, []span.Span) 104515- InlayHints(*testing.T, span.Span) 104516- References(*testing.T, span.Span, []span.Span) 104517- Rename(*testing.T, span.Span, string) 104518- PrepareRename(*testing.T, span.Span, *source.PrepareItem) 104519- Symbols(*testing.T, span.URI, []protocol.DocumentSymbol) 104520- WorkspaceSymbols(*testing.T, span.URI, string, WorkspaceSymbolsTestType) 104521- SignatureHelp(*testing.T, span.Span, *protocol.SignatureHelp) 104522- Link(*testing.T, span.URI, []Link) 104523- AddImport(*testing.T, span.URI, string) 104524- SelectionRanges(*testing.T, span.Span) 104525-} 104526- 104527-type Definition struct { 104528- Name string 104529- IsType bool 104530- OnlyHover bool 104531- Src, Def span.Span 104532-} 104533- 104534-type CompletionTestType int 104535- 104536-const ( 104537- // Default runs the standard completion tests. 104538- CompletionDefault = CompletionTestType(iota) 104539- 104540- // Unimported tests the autocompletion of unimported packages. 104541- CompletionUnimported 104542- 104543- // Deep tests deep completion. 104544- CompletionDeep 104545- 104546- // Fuzzy tests deep completion and fuzzy matching. 104547- CompletionFuzzy 104548- 104549- // CaseSensitive tests case sensitive completion. 104550- CompletionCaseSensitive 104551- 104552- // CompletionRank candidates in test must be valid and in the right relative order. 104553- CompletionRank 104554-) 104555- 104556-type WorkspaceSymbolsTestType int 104557- 104558-const ( 104559- // Default runs the standard workspace symbols tests. 104560- WorkspaceSymbolsDefault = WorkspaceSymbolsTestType(iota) 104561- 104562- // Fuzzy tests workspace symbols with fuzzy matching. 104563- WorkspaceSymbolsFuzzy 104564- 104565- // CaseSensitive tests workspace symbols with case sensitive. 104566- WorkspaceSymbolsCaseSensitive 104567-) 104568- 104569-type Completion struct { 104570- CompletionItems []token.Pos 104571-} 104572- 104573-type CompletionSnippet struct { 104574- CompletionItem token.Pos 104575- PlainSnippet string 104576- PlaceholderSnippet string 104577-} 104578- 104579-type CallHierarchyResult struct { 104580- IncomingCalls, OutgoingCalls []protocol.CallHierarchyItem 104581-} 104582- 104583-type Link struct { 104584- Src span.Span 104585- Target string 104586- NotePosition token.Position 104587-} 104588- 104589-type SuggestedFix struct { 104590- ActionKind, Title string 104591-} 104592- 104593-// A symbol holds a DocumentSymbol along with its parent-child edge. 104594-type symbol struct { 104595- pSymbol protocol.DocumentSymbol 104596- id, parentID string 104597-} 104598- 104599-type Golden struct { 104600- Filename string 104601- Archive *txtar.Archive 104602- Modified bool 104603-} 104604- 104605-func Context(t testing.TB) context.Context { 104606- return context.Background() 104607-} 104608- 104609-func DefaultOptions(o *source.Options) { 104610- o.SupportedCodeActions = map[source.FileKind]map[protocol.CodeActionKind]bool{ 104611- source.Go: { 104612- protocol.SourceOrganizeImports: true, 104613- protocol.QuickFix: true, 104614- protocol.RefactorRewrite: true, 104615- protocol.RefactorExtract: true, 104616- protocol.SourceFixAll: true, 104617- }, 104618- source.Mod: { 104619- protocol.SourceOrganizeImports: true, 104620- }, 104621- source.Sum: {}, 104622- source.Work: {}, 104623- source.Tmpl: {}, 104624- } 104625- o.UserOptions.Codelenses[string(command.Test)] = true 104626- o.HoverKind = source.SynopsisDocumentation 104627- o.InsertTextFormat = protocol.SnippetTextFormat 104628- o.CompletionBudget = time.Minute 104629- o.HierarchicalDocumentSymbolSupport = true 104630- o.SemanticTokens = true 104631- o.InternalOptions.NewDiff = "both" 104632-} 104633- 104634-func RunTests(t *testing.T, dataDir string, includeMultiModule bool, f func(*testing.T, *Data)) { 104635- t.Helper() 104636- modes := []string{"Modules", "GOPATH"} 104637- if includeMultiModule { 104638- modes = append(modes, "MultiModule") 104639- } 104640- for _, mode := range modes { 104641- t.Run(mode, func(t *testing.T) { 104642- datum := load(t, mode, dataDir) 104643- t.Helper() 104644- f(t, datum) 104645- }) 104646- } 104647-} 104648- 104649-func load(t testing.TB, mode string, dir string) *Data { 104650- datum := &Data{ 104651- CallHierarchy: make(CallHierarchy), 104652- CodeLens: make(CodeLens), 104653- Diagnostics: make(Diagnostics), 104654- CompletionItems: make(CompletionItems), 104655- Completions: make(Completions), 104656- CompletionSnippets: make(CompletionSnippets), 104657- UnimportedCompletions: make(UnimportedCompletions), 104658- DeepCompletions: make(DeepCompletions), 104659- FuzzyCompletions: make(FuzzyCompletions), 104660- RankCompletions: make(RankCompletions), 104661- CaseSensitiveCompletions: make(CaseSensitiveCompletions), 104662- Definitions: make(Definitions), 104663- Implementations: make(Implementations), 104664- Highlights: make(Highlights), 104665- References: make(References), 104666- Renames: make(Renames), 104667- PrepareRenames: make(PrepareRenames), 104668- SuggestedFixes: make(SuggestedFixes), 104669- FunctionExtractions: make(FunctionExtractions), 104670- MethodExtractions: make(MethodExtractions), 104671- Symbols: make(Symbols), 104672- WorkspaceSymbols: make(WorkspaceSymbols), 104673- Signatures: make(Signatures), 104674- Links: make(Links), 104675- AddImport: make(AddImport), 104676- 104677- dir: dir, 104678- fragments: map[string]string{}, 104679- golden: map[string]*Golden{}, 104680- mode: mode, 104681- mappers: map[span.URI]*protocol.Mapper{}, 104682- } 104683- 104684- if !*UpdateGolden { 104685- summary := filepath.Join(filepath.FromSlash(dir), summaryFile+goldenFileSuffix) 104686- if _, err := os.Stat(summary); os.IsNotExist(err) { 104687- t.Fatalf("could not find golden file summary.txt in %#v", dir) 104688- } 104689- archive, err := txtar.ParseFile(summary) 104690- if err != nil { 104691- t.Fatalf("could not read golden file %v/%v: %v", dir, summary, err) 104692- } 104693- datum.golden[summaryFile] = &Golden{ 104694- Filename: summary, 104695- Archive: archive, 104696- } 104697- } 104698- 104699- files := packagestest.MustCopyFileTree(dir) 104700- // Prune test cases that exercise generics. 104701- if !typeparams.Enabled { 104702- for name := range files { 104703- if strings.Contains(name, "_generics") { 104704- delete(files, name) 104705- } 104706- } 104707- } 104708- overlays := map[string][]byte{} 104709- for fragment, operation := range files { 104710- if trimmed := strings.TrimSuffix(fragment, goldenFileSuffix); trimmed != fragment { 104711- delete(files, fragment) 104712- goldFile := filepath.Join(dir, fragment) 104713- archive, err := txtar.ParseFile(goldFile) 104714- if err != nil { 104715- t.Fatalf("could not read golden file %v: %v", fragment, err) 104716- } 104717- datum.golden[trimmed] = &Golden{ 104718- Filename: goldFile, 104719- Archive: archive, 104720- } 104721- } else if trimmed := strings.TrimSuffix(fragment, inFileSuffix); trimmed != fragment { 104722- delete(files, fragment) 104723- files[trimmed] = operation 104724- } else if index := strings.Index(fragment, overlayFileSuffix); index >= 0 { 104725- delete(files, fragment) 104726- partial := fragment[:index] + fragment[index+len(overlayFileSuffix):] 104727- contents, err := ioutil.ReadFile(filepath.Join(dir, fragment)) 104728- if err != nil { 104729- t.Fatal(err) 104730- } 104731- overlays[partial] = contents 104732- } 104733- } 104734- 104735- modules := []packagestest.Module{ 104736- { 104737- Name: testModule, 104738- Files: files, 104739- Overlay: overlays, 104740- }, 104741- } 104742- switch mode { 104743- case "Modules": 104744- datum.Exported = packagestest.Export(t, packagestest.Modules, modules) 104745- case "GOPATH": 104746- datum.Exported = packagestest.Export(t, packagestest.GOPATH, modules) 104747- case "MultiModule": 104748- files := map[string]interface{}{} 104749- for k, v := range modules[0].Files { 104750- files[filepath.Join("testmodule", k)] = v 104751- } 104752- modules[0].Files = files 104753- 104754- overlays := map[string][]byte{} 104755- for k, v := range modules[0].Overlay { 104756- overlays[filepath.Join("testmodule", k)] = v 104757- } 104758- modules[0].Overlay = overlays 104759- 104760- golden := map[string]*Golden{} 104761- for k, v := range datum.golden { 104762- if k == summaryFile { 104763- golden[k] = v 104764- } else { 104765- golden[filepath.Join("testmodule", k)] = v 104766- } 104767- } 104768- datum.golden = golden 104769- 104770- datum.Exported = packagestest.Export(t, packagestest.Modules, modules) 104771- default: 104772- panic("unknown mode " + mode) 104773- } 104774- 104775- for _, m := range modules { 104776- for fragment := range m.Files { 104777- filename := datum.Exported.File(m.Name, fragment) 104778- datum.fragments[filename] = fragment 104779- } 104780- } 104781- 104782- // Turn off go/packages debug logging. 104783- datum.Exported.Config.Logf = nil 104784- datum.Config.Logf = nil 104785- 104786- // Merge the exported.Config with the view.Config. 104787- datum.Config = *datum.Exported.Config 104788- datum.Config.Fset = token.NewFileSet() 104789- datum.Config.Context = Context(nil) 104790- datum.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) { 104791- panic("ParseFile should not be called") 104792- } 104793- 104794- // Do a first pass to collect special markers for completion and workspace symbols. 104795- if err := datum.Exported.Expect(map[string]interface{}{ 104796- "item": func(name string, r packagestest.Range, _ []string) { 104797- datum.Exported.Mark(name, r) 104798- }, 104799- "symbol": func(name string, r packagestest.Range, _ []string) { 104800- datum.Exported.Mark(name, r) 104801- }, 104802- }); err != nil { 104803- t.Fatal(err) 104804- } 104805- 104806- // Collect any data that needs to be used by subsequent tests. 104807- if err := datum.Exported.Expect(map[string]interface{}{ 104808- "codelens": datum.collectCodeLens, 104809- "diag": datum.collectDiagnostics, 104810- "item": datum.collectCompletionItems, 104811- "complete": datum.collectCompletions(CompletionDefault), 104812- "unimported": datum.collectCompletions(CompletionUnimported), 104813- "deep": datum.collectCompletions(CompletionDeep), 104814- "fuzzy": datum.collectCompletions(CompletionFuzzy), 104815- "casesensitive": datum.collectCompletions(CompletionCaseSensitive), 104816- "rank": datum.collectCompletions(CompletionRank), 104817- "snippet": datum.collectCompletionSnippets, 104818- "fold": datum.collectFoldingRanges, 104819- "format": datum.collectFormats, 104820- "import": datum.collectImports, 104821- "semantic": datum.collectSemanticTokens, 104822- "godef": datum.collectDefinitions, 104823- "implementations": datum.collectImplementations, 104824- "typdef": datum.collectTypeDefinitions, 104825- "hoverdef": datum.collectHoverDefinitions, 104826- "highlight": datum.collectHighlights, 104827- "inlayHint": datum.collectInlayHints, 104828- "refs": datum.collectReferences, 104829- "rename": datum.collectRenames, 104830- "prepare": datum.collectPrepareRenames, 104831- "symbol": datum.collectSymbols, 104832- "signature": datum.collectSignatures, 104833- "link": datum.collectLinks, 104834- "suggestedfix": datum.collectSuggestedFixes, 104835- "extractfunc": datum.collectFunctionExtractions, 104836- "extractmethod": datum.collectMethodExtractions, 104837- "incomingcalls": datum.collectIncomingCalls, 104838- "outgoingcalls": datum.collectOutgoingCalls, 104839- "addimport": datum.collectAddImports, 104840- "selectionrange": datum.collectSelectionRanges, 104841- }); err != nil { 104842- t.Fatal(err) 104843- } 104844- 104845- // Collect names for the entries that require golden files. 104846- if err := datum.Exported.Expect(map[string]interface{}{ 104847- "godef": datum.collectDefinitionNames, 104848- "hoverdef": datum.collectDefinitionNames, 104849- "workspacesymbol": datum.collectWorkspaceSymbols(WorkspaceSymbolsDefault), 104850- "workspacesymbolfuzzy": datum.collectWorkspaceSymbols(WorkspaceSymbolsFuzzy), 104851- "workspacesymbolcasesensitive": datum.collectWorkspaceSymbols(WorkspaceSymbolsCaseSensitive), 104852- }); err != nil { 104853- t.Fatal(err) 104854- } 104855- if mode == "MultiModule" { 104856- if err := moveFile(filepath.Join(datum.Config.Dir, "go.mod"), filepath.Join(datum.Config.Dir, "testmodule/go.mod")); err != nil { 104857- t.Fatal(err) 104858- } 104859- } 104860- 104861- return datum 104862-} 104863- 104864-// moveFile moves the file at oldpath to newpath, by renaming if possible 104865-// or copying otherwise. 104866-func moveFile(oldpath, newpath string) (err error) { 104867- renameErr := os.Rename(oldpath, newpath) 104868- if renameErr == nil { 104869- return nil 104870- } 104871- 104872- src, err := os.Open(oldpath) 104873- if err != nil { 104874- return err 104875- } 104876- defer func() { 104877- src.Close() 104878- if err == nil { 104879- err = os.Remove(oldpath) 104880- } 104881- }() 104882- 104883- perm := os.ModePerm 104884- fi, err := src.Stat() 104885- if err == nil { 104886- perm = fi.Mode().Perm() 104887- } 104888- 104889- dst, err := os.OpenFile(newpath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) 104890- if err != nil { 104891- return err 104892- } 104893- 104894- _, err = io.Copy(dst, src) 104895- if closeErr := dst.Close(); err == nil { 104896- err = closeErr 104897- } 104898- return err 104899-} 104900- 104901-func Run(t *testing.T, tests Tests, data *Data) { 104902- t.Helper() 104903- checkData(t, data) 104904- 104905- eachCompletion := func(t *testing.T, cases map[span.Span][]Completion, test func(*testing.T, span.Span, Completion, CompletionItems)) { 104906- t.Helper() 104907- 104908- for src, exp := range cases { 104909- for i, e := range exp { 104910- t.Run(SpanName(src)+"_"+strconv.Itoa(i), func(t *testing.T) { 104911- t.Helper() 104912- if strings.Contains(t.Name(), "cgo") { 104913- testenv.NeedsTool(t, "cgo") 104914- } 104915- test(t, src, e, data.CompletionItems) 104916- }) 104917- } 104918- 104919- } 104920- } 104921- 104922- t.Run("CallHierarchy", func(t *testing.T) { 104923- t.Helper() 104924- for spn, callHierarchyResult := range data.CallHierarchy { 104925- t.Run(SpanName(spn), func(t *testing.T) { 104926- t.Helper() 104927- tests.CallHierarchy(t, spn, callHierarchyResult) 104928- }) 104929- } 104930- }) 104931- 104932- t.Run("Completion", func(t *testing.T) { 104933- t.Helper() 104934- eachCompletion(t, data.Completions, tests.Completion) 104935- }) 104936- 104937- t.Run("CompletionSnippets", func(t *testing.T) { 104938- t.Helper() 104939- for _, placeholders := range []bool{true, false} { 104940- for src, expecteds := range data.CompletionSnippets { 104941- for i, expected := range expecteds { 104942- name := SpanName(src) + "_" + strconv.Itoa(i+1) 104943- if placeholders { 104944- name += "_placeholders" 104945- } 104946- 104947- t.Run(name, func(t *testing.T) { 104948- t.Helper() 104949- tests.CompletionSnippet(t, src, expected, placeholders, data.CompletionItems) 104950- }) 104951- } 104952- } 104953- } 104954- }) 104955- 104956- t.Run("UnimportedCompletion", func(t *testing.T) { 104957- t.Helper() 104958- eachCompletion(t, data.UnimportedCompletions, tests.UnimportedCompletion) 104959- }) 104960- 104961- t.Run("DeepCompletion", func(t *testing.T) { 104962- t.Helper() 104963- eachCompletion(t, data.DeepCompletions, tests.DeepCompletion) 104964- }) 104965- 104966- t.Run("FuzzyCompletion", func(t *testing.T) { 104967- t.Helper() 104968- eachCompletion(t, data.FuzzyCompletions, tests.FuzzyCompletion) 104969- }) 104970- 104971- t.Run("CaseSensitiveCompletion", func(t *testing.T) { 104972- t.Helper() 104973- eachCompletion(t, data.CaseSensitiveCompletions, tests.CaseSensitiveCompletion) 104974- }) 104975- 104976- t.Run("RankCompletions", func(t *testing.T) { 104977- t.Helper() 104978- eachCompletion(t, data.RankCompletions, tests.RankCompletion) 104979- }) 104980- 104981- t.Run("CodeLens", func(t *testing.T) { 104982- t.Helper() 104983- for uri, want := range data.CodeLens { 104984- // Check if we should skip this URI if the -modfile flag is not available. 104985- if shouldSkip(data, uri) { 104986- continue 104987- } 104988- t.Run(uriName(uri), func(t *testing.T) { 104989- t.Helper() 104990- tests.CodeLens(t, uri, want) 104991- }) 104992- } 104993- }) 104994- 104995- t.Run("Diagnostics", func(t *testing.T) { 104996- t.Helper() 104997- for uri, want := range data.Diagnostics { 104998- // Check if we should skip this URI if the -modfile flag is not available. 104999- if shouldSkip(data, uri) { 105000- continue 105001- } 105002- t.Run(uriName(uri), func(t *testing.T) { 105003- t.Helper() 105004- tests.Diagnostics(t, uri, want) 105005- }) 105006- } 105007- }) 105008- 105009- t.Run("FoldingRange", func(t *testing.T) { 105010- t.Helper() 105011- for _, spn := range data.FoldingRanges { 105012- t.Run(uriName(spn.URI()), func(t *testing.T) { 105013- t.Helper() 105014- tests.FoldingRanges(t, spn) 105015- }) 105016- } 105017- }) 105018- 105019- t.Run("Format", func(t *testing.T) { 105020- t.Helper() 105021- for _, spn := range data.Formats { 105022- t.Run(uriName(spn.URI()), func(t *testing.T) { 105023- t.Helper() 105024- tests.Format(t, spn) 105025- }) 105026- } 105027- }) 105028- 105029- t.Run("Import", func(t *testing.T) { 105030- t.Helper() 105031- for _, spn := range data.Imports { 105032- t.Run(uriName(spn.URI()), func(t *testing.T) { 105033- t.Helper() 105034- tests.Import(t, spn) 105035- }) 105036- } 105037- }) 105038- 105039- t.Run("SemanticTokens", func(t *testing.T) { 105040- t.Helper() 105041- for _, spn := range data.SemanticTokens { 105042- t.Run(uriName(spn.URI()), func(t *testing.T) { 105043- t.Helper() 105044- tests.SemanticTokens(t, spn) 105045- }) 105046- } 105047- }) 105048- 105049- t.Run("SuggestedFix", func(t *testing.T) { 105050- t.Helper() 105051- for spn, actionKinds := range data.SuggestedFixes { 105052- // Check if we should skip this spn if the -modfile flag is not available. 105053- if shouldSkip(data, spn.URI()) { 105054- continue 105055- } 105056- t.Run(SpanName(spn), func(t *testing.T) { 105057- t.Helper() 105058- tests.SuggestedFix(t, spn, actionKinds, 1) 105059- }) 105060- } 105061- }) 105062- 105063- t.Run("FunctionExtraction", func(t *testing.T) { 105064- t.Helper() 105065- for start, end := range data.FunctionExtractions { 105066- // Check if we should skip this spn if the -modfile flag is not available. 105067- if shouldSkip(data, start.URI()) { 105068- continue 105069- } 105070- t.Run(SpanName(start), func(t *testing.T) { 105071- t.Helper() 105072- tests.FunctionExtraction(t, start, end) 105073- }) 105074- } 105075- }) 105076- 105077- t.Run("MethodExtraction", func(t *testing.T) { 105078- t.Helper() 105079- for start, end := range data.MethodExtractions { 105080- // Check if we should skip this spn if the -modfile flag is not available. 105081- if shouldSkip(data, start.URI()) { 105082- continue 105083- } 105084- t.Run(SpanName(start), func(t *testing.T) { 105085- t.Helper() 105086- tests.MethodExtraction(t, start, end) 105087- }) 105088- } 105089- }) 105090- 105091- t.Run("Definition", func(t *testing.T) { 105092- t.Helper() 105093- for spn, d := range data.Definitions { 105094- t.Run(SpanName(spn), func(t *testing.T) { 105095- t.Helper() 105096- if strings.Contains(t.Name(), "cgo") { 105097- testenv.NeedsTool(t, "cgo") 105098- } 105099- tests.Definition(t, spn, d) 105100- }) 105101- } 105102- }) 105103- 105104- t.Run("Implementation", func(t *testing.T) { 105105- t.Helper() 105106- for spn, m := range data.Implementations { 105107- t.Run(SpanName(spn), func(t *testing.T) { 105108- t.Helper() 105109- tests.Implementation(t, spn, m) 105110- }) 105111- } 105112- }) 105113- 105114- t.Run("Highlight", func(t *testing.T) { 105115- t.Helper() 105116- for pos, locations := range data.Highlights { 105117- t.Run(SpanName(pos), func(t *testing.T) { 105118- t.Helper() 105119- tests.Highlight(t, pos, locations) 105120- }) 105121- } 105122- }) 105123- 105124- t.Run("InlayHints", func(t *testing.T) { 105125- t.Helper() 105126- for _, src := range data.InlayHints { 105127- t.Run(SpanName(src), func(t *testing.T) { 105128- t.Helper() 105129- tests.InlayHints(t, src) 105130- }) 105131- } 105132- }) 105133- 105134- t.Run("References", func(t *testing.T) { 105135- t.Helper() 105136- for src, itemList := range data.References { 105137- t.Run(SpanName(src), func(t *testing.T) { 105138- t.Helper() 105139- tests.References(t, src, itemList) 105140- }) 105141- } 105142- }) 105143- 105144- t.Run("Renames", func(t *testing.T) { 105145- t.Helper() 105146- for spn, newText := range data.Renames { 105147- t.Run(uriName(spn.URI())+"_"+newText, func(t *testing.T) { 105148- t.Helper() 105149- tests.Rename(t, spn, newText) 105150- }) 105151- } 105152- }) 105153- 105154- t.Run("PrepareRenames", func(t *testing.T) { 105155- t.Helper() 105156- for src, want := range data.PrepareRenames { 105157- t.Run(SpanName(src), func(t *testing.T) { 105158- t.Helper() 105159- tests.PrepareRename(t, src, want) 105160- }) 105161- } 105162- }) 105163- 105164- t.Run("Symbols", func(t *testing.T) { 105165- t.Helper() 105166- for uri, allSymbols := range data.Symbols { 105167- byParent := make(map[string][]*symbol) 105168- for _, sym := range allSymbols { 105169- if sym.parentID != "" { 105170- byParent[sym.parentID] = append(byParent[sym.parentID], sym) 105171- } 105172- } 105173- 105174- // collectChildren does a depth-first traversal of the symbol tree, 105175- // computing children of child nodes before returning to their parent. 105176- // This is necessary as the Children field is slice of non-pointer types, 105177- // and therefore we need to be careful to mutate children first before 105178- // assigning them to their parent. 105179- var collectChildren func(id string) []protocol.DocumentSymbol 105180- collectChildren = func(id string) []protocol.DocumentSymbol { 105181- children := byParent[id] 105182- // delete from byParent before recursing, to ensure that 105183- // collectChildren terminates even in the presence of cycles. 105184- delete(byParent, id) 105185- var result []protocol.DocumentSymbol 105186- for _, child := range children { 105187- child.pSymbol.Children = collectChildren(child.id) 105188- result = append(result, child.pSymbol) 105189- } 105190- return result 105191- } 105192- 105193- var topLevel []protocol.DocumentSymbol 105194- for _, sym := range allSymbols { 105195- if sym.parentID == "" { 105196- sym.pSymbol.Children = collectChildren(sym.id) 105197- topLevel = append(topLevel, sym.pSymbol) 105198- } 105199- } 105200- 105201- t.Run(uriName(uri), func(t *testing.T) { 105202- t.Helper() 105203- tests.Symbols(t, uri, topLevel) 105204- }) 105205- } 105206- }) 105207- 105208- t.Run("WorkspaceSymbols", func(t *testing.T) { 105209- t.Helper() 105210- 105211- for _, typ := range []WorkspaceSymbolsTestType{ 105212- WorkspaceSymbolsDefault, 105213- WorkspaceSymbolsCaseSensitive, 105214- WorkspaceSymbolsFuzzy, 105215- } { 105216- for uri, cases := range data.WorkspaceSymbols[typ] { 105217- for _, query := range cases { 105218- name := query 105219- if name == "" { 105220- name = "EmptyQuery" 105221- } 105222- t.Run(name, func(t *testing.T) { 105223- t.Helper() 105224- tests.WorkspaceSymbols(t, uri, query, typ) 105225- }) 105226- } 105227- } 105228- } 105229- 105230- }) 105231- 105232- t.Run("SignatureHelp", func(t *testing.T) { 105233- t.Helper() 105234- for spn, expectedSignature := range data.Signatures { 105235- t.Run(SpanName(spn), func(t *testing.T) { 105236- t.Helper() 105237- tests.SignatureHelp(t, spn, expectedSignature) 105238- }) 105239- } 105240- }) 105241- 105242- t.Run("Link", func(t *testing.T) { 105243- t.Helper() 105244- for uri, wantLinks := range data.Links { 105245- // If we are testing GOPATH, then we do not want links with the versions 105246- // attached (pkg.go.dev/repoa/moda@v1.1.0/pkg), unless the file is a 105247- // go.mod, then we can skip it altogether. 105248- if data.Exported.Exporter == packagestest.GOPATH { 105249- if strings.HasSuffix(uri.Filename(), ".mod") { 105250- continue 105251- } 105252- re := regexp.MustCompile(`@v\d+\.\d+\.[\w-]+`) 105253- for i, link := range wantLinks { 105254- wantLinks[i].Target = re.ReplaceAllString(link.Target, "") 105255- } 105256- } 105257- t.Run(uriName(uri), func(t *testing.T) { 105258- t.Helper() 105259- tests.Link(t, uri, wantLinks) 105260- }) 105261- } 105262- }) 105263- 105264- t.Run("AddImport", func(t *testing.T) { 105265- t.Helper() 105266- for uri, exp := range data.AddImport { 105267- t.Run(uriName(uri), func(t *testing.T) { 105268- tests.AddImport(t, uri, exp) 105269- }) 105270- } 105271- }) 105272- 105273- t.Run("SelectionRanges", func(t *testing.T) { 105274- t.Helper() 105275- for _, span := range data.SelectionRanges { 105276- t.Run(SpanName(span), func(t *testing.T) { 105277- tests.SelectionRanges(t, span) 105278- }) 105279- } 105280- }) 105281- 105282- if *UpdateGolden { 105283- for _, golden := range data.golden { 105284- if !golden.Modified { 105285- continue 105286- } 105287- sort.Slice(golden.Archive.Files, func(i, j int) bool { 105288- return golden.Archive.Files[i].Name < golden.Archive.Files[j].Name 105289- }) 105290- if err := ioutil.WriteFile(golden.Filename, txtar.Format(golden.Archive), 0666); err != nil { 105291- t.Fatal(err) 105292- } 105293- } 105294- } 105295-} 105296- 105297-func checkData(t *testing.T, data *Data) { 105298- buf := &bytes.Buffer{} 105299- diagnosticsCount := 0 105300- for _, want := range data.Diagnostics { 105301- diagnosticsCount += len(want) 105302- } 105303- linksCount := 0 105304- for _, want := range data.Links { 105305- linksCount += len(want) 105306- } 105307- definitionCount := 0 105308- typeDefinitionCount := 0 105309- for _, d := range data.Definitions { 105310- if d.IsType { 105311- typeDefinitionCount++ 105312- } else { 105313- definitionCount++ 105314- } 105315- } 105316- 105317- snippetCount := 0 105318- for _, want := range data.CompletionSnippets { 105319- snippetCount += len(want) 105320- } 105321- 105322- countCompletions := func(c map[span.Span][]Completion) (count int) { 105323- for _, want := range c { 105324- count += len(want) 105325- } 105326- return count 105327- } 105328- 105329- countCodeLens := func(c map[span.URI][]protocol.CodeLens) (count int) { 105330- for _, want := range c { 105331- count += len(want) 105332- } 105333- return count 105334- } 105335- 105336- countWorkspaceSymbols := func(c map[WorkspaceSymbolsTestType]map[span.URI][]string) (count int) { 105337- for _, typs := range c { 105338- for _, queries := range typs { 105339- count += len(queries) 105340- } 105341- } 105342- return count 105343- } 105344- 105345- fmt.Fprintf(buf, "CallHierarchyCount = %v\n", len(data.CallHierarchy)) 105346- fmt.Fprintf(buf, "CodeLensCount = %v\n", countCodeLens(data.CodeLens)) 105347- fmt.Fprintf(buf, "CompletionsCount = %v\n", countCompletions(data.Completions)) 105348- fmt.Fprintf(buf, "CompletionSnippetCount = %v\n", snippetCount) 105349- fmt.Fprintf(buf, "UnimportedCompletionsCount = %v\n", countCompletions(data.UnimportedCompletions)) 105350- fmt.Fprintf(buf, "DeepCompletionsCount = %v\n", countCompletions(data.DeepCompletions)) 105351- fmt.Fprintf(buf, "FuzzyCompletionsCount = %v\n", countCompletions(data.FuzzyCompletions)) 105352- fmt.Fprintf(buf, "RankedCompletionsCount = %v\n", countCompletions(data.RankCompletions)) 105353- fmt.Fprintf(buf, "CaseSensitiveCompletionsCount = %v\n", countCompletions(data.CaseSensitiveCompletions)) 105354- fmt.Fprintf(buf, "DiagnosticsCount = %v\n", diagnosticsCount) 105355- fmt.Fprintf(buf, "FoldingRangesCount = %v\n", len(data.FoldingRanges)) 105356- fmt.Fprintf(buf, "FormatCount = %v\n", len(data.Formats)) 105357- fmt.Fprintf(buf, "ImportCount = %v\n", len(data.Imports)) 105358- fmt.Fprintf(buf, "SemanticTokenCount = %v\n", len(data.SemanticTokens)) 105359- fmt.Fprintf(buf, "SuggestedFixCount = %v\n", len(data.SuggestedFixes)) 105360- fmt.Fprintf(buf, "FunctionExtractionCount = %v\n", len(data.FunctionExtractions)) 105361- fmt.Fprintf(buf, "MethodExtractionCount = %v\n", len(data.MethodExtractions)) 105362- fmt.Fprintf(buf, "DefinitionsCount = %v\n", definitionCount) 105363- fmt.Fprintf(buf, "TypeDefinitionsCount = %v\n", typeDefinitionCount) 105364- fmt.Fprintf(buf, "HighlightsCount = %v\n", len(data.Highlights)) 105365- fmt.Fprintf(buf, "InlayHintsCount = %v\n", len(data.InlayHints)) 105366- fmt.Fprintf(buf, "ReferencesCount = %v\n", len(data.References)) 105367- fmt.Fprintf(buf, "RenamesCount = %v\n", len(data.Renames)) 105368- fmt.Fprintf(buf, "PrepareRenamesCount = %v\n", len(data.PrepareRenames)) 105369- fmt.Fprintf(buf, "SymbolsCount = %v\n", len(data.Symbols)) 105370- fmt.Fprintf(buf, "WorkspaceSymbolsCount = %v\n", countWorkspaceSymbols(data.WorkspaceSymbols)) 105371- fmt.Fprintf(buf, "SignaturesCount = %v\n", len(data.Signatures)) 105372- fmt.Fprintf(buf, "LinksCount = %v\n", linksCount) 105373- fmt.Fprintf(buf, "ImplementationsCount = %v\n", len(data.Implementations)) 105374- fmt.Fprintf(buf, "SelectionRangesCount = %v\n", len(data.SelectionRanges)) 105375- 105376- want := string(data.Golden(t, "summary", summaryFile, func() ([]byte, error) { 105377- return buf.Bytes(), nil 105378- })) 105379- got := buf.String() 105380- if want != got { 105381- // These counters change when assertions are added or removed. 105382- // They act as an independent safety net to ensure that the 105383- // tests didn't spuriously pass because they did no work. 105384- t.Errorf("test summary does not match:\n%s\n(Run with -golden to update golden file; also, there may be one per Go version.)", compare.Text(want, got)) 105385- } 105386-} 105387- 105388-func (data *Data) Mapper(uri span.URI) (*protocol.Mapper, error) { 105389- data.mappersMu.Lock() 105390- defer data.mappersMu.Unlock() 105391- 105392- if _, ok := data.mappers[uri]; !ok { 105393- content, err := data.Exported.FileContents(uri.Filename()) 105394- if err != nil { 105395- return nil, err 105396- } 105397- data.mappers[uri] = protocol.NewMapper(uri, content) 105398- } 105399- return data.mappers[uri], nil 105400-} 105401- 105402-func (data *Data) Golden(t *testing.T, tag, target string, update func() ([]byte, error)) []byte { 105403- t.Helper() 105404- fragment, found := data.fragments[target] 105405- if !found { 105406- if filepath.IsAbs(target) { 105407- t.Fatalf("invalid golden file fragment %v", target) 105408- } 105409- fragment = target 105410- } 105411- golden := data.golden[fragment] 105412- if golden == nil { 105413- if !*UpdateGolden { 105414- t.Fatalf("could not find golden file %v: %v", fragment, tag) 105415- } 105416- golden = &Golden{ 105417- Filename: filepath.Join(data.dir, fragment+goldenFileSuffix), 105418- Archive: &txtar.Archive{}, 105419- Modified: true, 105420- } 105421- data.golden[fragment] = golden 105422- } 105423- var file *txtar.File 105424- for i := range golden.Archive.Files { 105425- f := &golden.Archive.Files[i] 105426- if f.Name == tag { 105427- file = f 105428- break 105429- } 105430- } 105431- if *UpdateGolden { 105432- if file == nil { 105433- golden.Archive.Files = append(golden.Archive.Files, txtar.File{ 105434- Name: tag, 105435- }) 105436- file = &golden.Archive.Files[len(golden.Archive.Files)-1] 105437- } 105438- contents, err := update() 105439- if err != nil { 105440- t.Fatalf("could not update golden file %v: %v", fragment, err) 105441- } 105442- file.Data = append(contents, '\n') // add trailing \n for txtar 105443- golden.Modified = true 105444- 105445- } 105446- if file == nil { 105447- t.Fatalf("could not find golden contents %v: %v", fragment, tag) 105448- } 105449- if len(file.Data) == 0 { 105450- return file.Data 105451- } 105452- return file.Data[:len(file.Data)-1] // drop the trailing \n 105453-} 105454- 105455-func (data *Data) collectCodeLens(spn span.Span, title, cmd string) { 105456- data.CodeLens[spn.URI()] = append(data.CodeLens[spn.URI()], protocol.CodeLens{ 105457- Range: data.mustRange(spn), 105458- Command: &protocol.Command{ 105459- Title: title, 105460- Command: cmd, 105461- }, 105462- }) 105463-} 105464- 105465-func (data *Data) collectDiagnostics(spn span.Span, msgSource, msgPattern, msgSeverity string) { 105466- severity := protocol.SeverityError 105467- switch msgSeverity { 105468- case "error": 105469- severity = protocol.SeverityError 105470- case "warning": 105471- severity = protocol.SeverityWarning 105472- case "hint": 105473- severity = protocol.SeverityHint 105474- case "information": 105475- severity = protocol.SeverityInformation 105476- } 105477- 105478- data.Diagnostics[spn.URI()] = append(data.Diagnostics[spn.URI()], &source.Diagnostic{ 105479- Range: data.mustRange(spn), 105480- Severity: severity, 105481- Source: source.DiagnosticSource(msgSource), 105482- Message: msgPattern, 105483- }) 105484-} 105485- 105486-func (data *Data) collectCompletions(typ CompletionTestType) func(span.Span, []token.Pos) { 105487- result := func(m map[span.Span][]Completion, src span.Span, expected []token.Pos) { 105488- m[src] = append(m[src], Completion{ 105489- CompletionItems: expected, 105490- }) 105491- } 105492- switch typ { 105493- case CompletionDeep: 105494- return func(src span.Span, expected []token.Pos) { 105495- result(data.DeepCompletions, src, expected) 105496- } 105497- case CompletionUnimported: 105498- return func(src span.Span, expected []token.Pos) { 105499- result(data.UnimportedCompletions, src, expected) 105500- } 105501- case CompletionFuzzy: 105502- return func(src span.Span, expected []token.Pos) { 105503- result(data.FuzzyCompletions, src, expected) 105504- } 105505- case CompletionRank: 105506- return func(src span.Span, expected []token.Pos) { 105507- result(data.RankCompletions, src, expected) 105508- } 105509- case CompletionCaseSensitive: 105510- return func(src span.Span, expected []token.Pos) { 105511- result(data.CaseSensitiveCompletions, src, expected) 105512- } 105513- default: 105514- return func(src span.Span, expected []token.Pos) { 105515- result(data.Completions, src, expected) 105516- } 105517- } 105518-} 105519- 105520-func (data *Data) collectCompletionItems(pos token.Pos, label, detail, kind string, args []string) { 105521- var documentation string 105522- if len(args) > 3 { 105523- documentation = args[3] 105524- } 105525- data.CompletionItems[pos] = &completion.CompletionItem{ 105526- Label: label, 105527- Detail: detail, 105528- Kind: protocol.ParseCompletionItemKind(kind), 105529- Documentation: documentation, 105530- } 105531-} 105532- 105533-func (data *Data) collectFoldingRanges(spn span.Span) { 105534- data.FoldingRanges = append(data.FoldingRanges, spn) 105535-} 105536- 105537-func (data *Data) collectFormats(spn span.Span) { 105538- data.Formats = append(data.Formats, spn) 105539-} 105540- 105541-func (data *Data) collectImports(spn span.Span) { 105542- data.Imports = append(data.Imports, spn) 105543-} 105544- 105545-func (data *Data) collectAddImports(spn span.Span, imp string) { 105546- data.AddImport[spn.URI()] = imp 105547-} 105548- 105549-func (data *Data) collectSemanticTokens(spn span.Span) { 105550- data.SemanticTokens = append(data.SemanticTokens, spn) 105551-} 105552- 105553-func (data *Data) collectSuggestedFixes(spn span.Span, actionKind, fix string) { 105554- data.SuggestedFixes[spn] = append(data.SuggestedFixes[spn], SuggestedFix{actionKind, fix}) 105555-} 105556- 105557-func (data *Data) collectFunctionExtractions(start span.Span, end span.Span) { 105558- if _, ok := data.FunctionExtractions[start]; !ok { 105559- data.FunctionExtractions[start] = end 105560- } 105561-} 105562- 105563-func (data *Data) collectMethodExtractions(start span.Span, end span.Span) { 105564- if _, ok := data.MethodExtractions[start]; !ok { 105565- data.MethodExtractions[start] = end 105566- } 105567-} 105568- 105569-func (data *Data) collectDefinitions(src, target span.Span) { 105570- data.Definitions[src] = Definition{ 105571- Src: src, 105572- Def: target, 105573- } 105574-} 105575- 105576-func (data *Data) collectSelectionRanges(spn span.Span) { 105577- data.SelectionRanges = append(data.SelectionRanges, spn) 105578-} 105579- 105580-func (data *Data) collectImplementations(src span.Span, targets []span.Span) { 105581- data.Implementations[src] = targets 105582-} 105583- 105584-func (data *Data) collectIncomingCalls(src span.Span, calls []span.Span) { 105585- for _, call := range calls { 105586- rng := data.mustRange(call) 105587- // we're only comparing protocol.range 105588- if data.CallHierarchy[src] != nil { 105589- data.CallHierarchy[src].IncomingCalls = append(data.CallHierarchy[src].IncomingCalls, 105590- protocol.CallHierarchyItem{ 105591- URI: protocol.DocumentURI(call.URI()), 105592- Range: rng, 105593- }) 105594- } else { 105595- data.CallHierarchy[src] = &CallHierarchyResult{ 105596- IncomingCalls: []protocol.CallHierarchyItem{ 105597- {URI: protocol.DocumentURI(call.URI()), Range: rng}, 105598- }, 105599- } 105600- } 105601- } 105602-} 105603- 105604-func (data *Data) collectOutgoingCalls(src span.Span, calls []span.Span) { 105605- if data.CallHierarchy[src] == nil { 105606- data.CallHierarchy[src] = &CallHierarchyResult{} 105607- } 105608- for _, call := range calls { 105609- // we're only comparing protocol.range 105610- data.CallHierarchy[src].OutgoingCalls = append(data.CallHierarchy[src].OutgoingCalls, 105611- protocol.CallHierarchyItem{ 105612- URI: protocol.DocumentURI(call.URI()), 105613- Range: data.mustRange(call), 105614- }) 105615- } 105616-} 105617- 105618-func (data *Data) collectHoverDefinitions(src, target span.Span) { 105619- data.Definitions[src] = Definition{ 105620- Src: src, 105621- Def: target, 105622- OnlyHover: true, 105623- } 105624-} 105625- 105626-func (data *Data) collectTypeDefinitions(src, target span.Span) { 105627- data.Definitions[src] = Definition{ 105628- Src: src, 105629- Def: target, 105630- IsType: true, 105631- } 105632-} 105633- 105634-func (data *Data) collectDefinitionNames(src span.Span, name string) { 105635- d := data.Definitions[src] 105636- d.Name = name 105637- data.Definitions[src] = d 105638-} 105639- 105640-func (data *Data) collectHighlights(src span.Span, expected []span.Span) { 105641- // Declaring a highlight in a test file: @highlight(src, expected1, expected2) 105642- data.Highlights[src] = append(data.Highlights[src], expected...) 105643-} 105644- 105645-func (data *Data) collectInlayHints(src span.Span) { 105646- data.InlayHints = append(data.InlayHints, src) 105647-} 105648- 105649-func (data *Data) collectReferences(src span.Span, expected []span.Span) { 105650- data.References[src] = expected 105651-} 105652- 105653-func (data *Data) collectRenames(src span.Span, newText string) { 105654- data.Renames[src] = newText 105655-} 105656- 105657-func (data *Data) collectPrepareRenames(src, spn span.Span, placeholder string) { 105658- data.PrepareRenames[src] = &source.PrepareItem{ 105659- Range: data.mustRange(spn), 105660- Text: placeholder, 105661- } 105662-} 105663- 105664-// collectSymbols is responsible for collecting @symbol annotations. 105665-func (data *Data) collectSymbols(name string, selectionRng span.Span, kind, detail, id, parentID string) { 105666- // We don't set 'Range' here as it is difficult (impossible?) to express 105667- // multi-line ranges in the packagestest framework. 105668- uri := selectionRng.URI() 105669- data.Symbols[uri] = append(data.Symbols[uri], &symbol{ 105670- pSymbol: protocol.DocumentSymbol{ 105671- Name: name, 105672- Kind: protocol.ParseSymbolKind(kind), 105673- SelectionRange: data.mustRange(selectionRng), 105674- Detail: detail, 105675- }, 105676- id: id, 105677- parentID: parentID, 105678- }) 105679-} 105680- 105681-// mustRange converts spn into a protocol.Range, panicking on any error. 105682-func (data *Data) mustRange(spn span.Span) protocol.Range { 105683- m, err := data.Mapper(spn.URI()) 105684- rng, err := m.SpanRange(spn) 105685- if err != nil { 105686- panic(fmt.Sprintf("converting span %s to range: %v", spn, err)) 105687- } 105688- return rng 105689-} 105690- 105691-func (data *Data) collectWorkspaceSymbols(typ WorkspaceSymbolsTestType) func(*expect.Note, string) { 105692- return func(note *expect.Note, query string) { 105693- if data.WorkspaceSymbols[typ] == nil { 105694- data.WorkspaceSymbols[typ] = make(map[span.URI][]string) 105695- } 105696- pos := safetoken.StartPosition(data.Exported.ExpectFileSet, note.Pos) 105697- uri := span.URIFromPath(pos.Filename) 105698- data.WorkspaceSymbols[typ][uri] = append(data.WorkspaceSymbols[typ][uri], query) 105699- } 105700-} 105701- 105702-func (data *Data) collectSignatures(spn span.Span, signature string, activeParam int64) { 105703- data.Signatures[spn] = &protocol.SignatureHelp{ 105704- Signatures: []protocol.SignatureInformation{ 105705- { 105706- Label: signature, 105707- }, 105708- }, 105709- ActiveParameter: uint32(activeParam), 105710- } 105711- // Hardcode special case to test the lack of a signature. 105712- if signature == "" && activeParam == 0 { 105713- data.Signatures[spn] = nil 105714- } 105715-} 105716- 105717-func (data *Data) collectCompletionSnippets(spn span.Span, item token.Pos, plain, placeholder string) { 105718- data.CompletionSnippets[spn] = append(data.CompletionSnippets[spn], CompletionSnippet{ 105719- CompletionItem: item, 105720- PlainSnippet: plain, 105721- PlaceholderSnippet: placeholder, 105722- }) 105723-} 105724- 105725-func (data *Data) collectLinks(spn span.Span, link string, note *expect.Note, fset *token.FileSet) { 105726- position := safetoken.StartPosition(fset, note.Pos) 105727- uri := spn.URI() 105728- data.Links[uri] = append(data.Links[uri], Link{ 105729- Src: spn, 105730- Target: link, 105731- NotePosition: position, 105732- }) 105733-} 105734- 105735-func uriName(uri span.URI) string { 105736- return filepath.Base(strings.TrimSuffix(uri.Filename(), ".go")) 105737-} 105738- 105739-// TODO(golang/go#54845): improve the formatting here to match standard 105740-// line:column position formatting. 105741-func SpanName(spn span.Span) string { 105742- return fmt.Sprintf("%v_%v_%v", uriName(spn.URI()), spn.Start().Line(), spn.Start().Column()) 105743-} 105744- 105745-func CopyFolderToTempDir(folder string) (string, error) { 105746- if _, err := os.Stat(folder); err != nil { 105747- return "", err 105748- } 105749- dst, err := ioutil.TempDir("", "modfile_test") 105750- if err != nil { 105751- return "", err 105752- } 105753- fds, err := ioutil.ReadDir(folder) 105754- if err != nil { 105755- return "", err 105756- } 105757- for _, fd := range fds { 105758- srcfp := filepath.Join(folder, fd.Name()) 105759- stat, err := os.Stat(srcfp) 105760- if err != nil { 105761- return "", err 105762- } 105763- if !stat.Mode().IsRegular() { 105764- return "", fmt.Errorf("cannot copy non regular file %s", srcfp) 105765- } 105766- contents, err := ioutil.ReadFile(srcfp) 105767- if err != nil { 105768- return "", err 105769- } 105770- if err := ioutil.WriteFile(filepath.Join(dst, fd.Name()), contents, stat.Mode()); err != nil { 105771- return "", err 105772- } 105773- } 105774- return dst, nil 105775-} 105776- 105777-func shouldSkip(data *Data, uri span.URI) bool { 105778- if data.ModfileFlagAvailable { 105779- return false 105780- } 105781- // If the -modfile flag is not available, then we do not want to run 105782- // any tests on the go.mod file. 105783- if strings.HasSuffix(uri.Filename(), ".mod") { 105784- return true 105785- } 105786- // If the -modfile flag is not available, then we do not want to test any 105787- // uri that contains "go mod tidy". 105788- m, err := data.Mapper(uri) 105789- return err == nil && strings.Contains(string(m.Content), ", \"go mod tidy\",") 105790-} 105791diff -urN a/gopls/internal/lsp/tests/util.go b/gopls/internal/lsp/tests/util.go 105792--- a/gopls/internal/lsp/tests/util.go 2000-01-01 00:00:00.000000000 -0000 105793+++ b/gopls/internal/lsp/tests/util.go 1970-01-01 00:00:00.000000000 +0000 105794@@ -1,547 +0,0 @@ 105795-// Copyright 2020 The Go Authors. All rights reserved. 105796-// Use of this source code is governed by a BSD-style 105797-// license that can be found in the LICENSE file. 105798- 105799-package tests 105800- 105801-import ( 105802- "bytes" 105803- "context" 105804- "fmt" 105805- "go/token" 105806- "path" 105807- "path/filepath" 105808- "regexp" 105809- "sort" 105810- "strconv" 105811- "strings" 105812- "testing" 105813- 105814- "github.com/google/go-cmp/cmp" 105815- "github.com/google/go-cmp/cmp/cmpopts" 105816- "golang.org/x/tools/gopls/internal/lsp/protocol" 105817- "golang.org/x/tools/gopls/internal/lsp/source" 105818- "golang.org/x/tools/gopls/internal/lsp/source/completion" 105819- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 105820- "golang.org/x/tools/gopls/internal/span" 105821-) 105822- 105823-var builtins = map[string]bool{ 105824- "append": true, 105825- "cap": true, 105826- "close": true, 105827- "complex": true, 105828- "copy": true, 105829- "delete": true, 105830- "error": true, 105831- "false": true, 105832- "imag": true, 105833- "iota": true, 105834- "len": true, 105835- "make": true, 105836- "new": true, 105837- "nil": true, 105838- "panic": true, 105839- "print": true, 105840- "println": true, 105841- "real": true, 105842- "recover": true, 105843- "true": true, 105844-} 105845- 105846-// DiffLinks takes the links we got and checks if they are located within the source or a Note. 105847-// If the link is within a Note, the link is removed. 105848-// Returns an diff comment if there are differences and empty string if no diffs. 105849-func DiffLinks(mapper *protocol.Mapper, wantLinks []Link, gotLinks []protocol.DocumentLink) string { 105850- var notePositions []token.Position 105851- links := make(map[span.Span]string, len(wantLinks)) 105852- for _, link := range wantLinks { 105853- links[link.Src] = link.Target 105854- notePositions = append(notePositions, link.NotePosition) 105855- } 105856- 105857- var msg strings.Builder 105858- for _, link := range gotLinks { 105859- spn, err := mapper.RangeSpan(link.Range) 105860- if err != nil { 105861- return fmt.Sprintf("%v", err) 105862- } 105863- linkInNote := false 105864- for _, notePosition := range notePositions { 105865- // Drop the links found inside expectation notes arguments as this links are not collected by expect package. 105866- if notePosition.Line == spn.Start().Line() && 105867- notePosition.Column <= spn.Start().Column() { 105868- delete(links, spn) 105869- linkInNote = true 105870- } 105871- } 105872- if linkInNote { 105873- continue 105874- } 105875- 105876- if target, ok := links[spn]; ok { 105877- delete(links, spn) 105878- if target != link.Target { 105879- fmt.Fprintf(&msg, "%s: want link with target %q, got %q\n", spn, target, link.Target) 105880- } 105881- } else { 105882- fmt.Fprintf(&msg, "%s: got unexpected link with target %q\n", spn, link.Target) 105883- } 105884- } 105885- for spn, target := range links { 105886- fmt.Fprintf(&msg, "%s: expected link with target %q is missing\n", spn, target) 105887- } 105888- return msg.String() 105889-} 105890- 105891-// CompareDiagnostics reports testing errors to t when the diagnostic set got 105892-// does not match want. If the sole expectation has source "no_diagnostics", 105893-// the test expects that no diagnostics were received for the given document. 105894-func CompareDiagnostics(t *testing.T, uri span.URI, want, got []*source.Diagnostic) { 105895- t.Helper() 105896- fileName := path.Base(string(uri)) 105897- 105898- // A special case to test that there are no diagnostics for a file. 105899- if len(want) == 1 && want[0].Source == "no_diagnostics" { 105900- want = nil 105901- } 105902- 105903- // Build a helper function to match an actual diagnostic to an overlapping 105904- // expected diagnostic (if any). 105905- unmatched := make([]*source.Diagnostic, len(want)) 105906- copy(unmatched, want) 105907- source.SortDiagnostics(unmatched) 105908- match := func(g *source.Diagnostic) *source.Diagnostic { 105909- // Find the last expected diagnostic d for which start(d) < end(g), and 105910- // check to see if it overlaps. 105911- i := sort.Search(len(unmatched), func(i int) bool { 105912- d := unmatched[i] 105913- // See rangeOverlaps: if a range is a single point, we consider End to be 105914- // included in the range... 105915- if g.Range.Start == g.Range.End { 105916- return protocol.ComparePosition(d.Range.Start, g.Range.End) > 0 105917- } 105918- // ...otherwise the end position of a range is not included. 105919- return protocol.ComparePosition(d.Range.Start, g.Range.End) >= 0 105920- }) 105921- if i == 0 { 105922- return nil 105923- } 105924- w := unmatched[i-1] 105925- if rangeOverlaps(w.Range, g.Range) { 105926- unmatched = append(unmatched[:i-1], unmatched[i:]...) 105927- return w 105928- } 105929- return nil 105930- } 105931- 105932- for _, g := range got { 105933- w := match(g) 105934- if w == nil { 105935- t.Errorf("%s:%s: unexpected diagnostic %q", fileName, g.Range, g.Message) 105936- continue 105937- } 105938- if match, err := regexp.MatchString(w.Message, g.Message); err != nil { 105939- t.Errorf("%s:%s: invalid regular expression %q: %v", fileName, w.Range.Start, w.Message, err) 105940- } else if !match { 105941- t.Errorf("%s:%s: got Message %q, want match for pattern %q", fileName, g.Range.Start, g.Message, w.Message) 105942- } 105943- if w.Severity != g.Severity { 105944- t.Errorf("%s:%s: got Severity %v, want %v", fileName, g.Range.Start, g.Severity, w.Severity) 105945- } 105946- if w.Source != g.Source { 105947- t.Errorf("%s:%s: got Source %v, want %v", fileName, g.Range.Start, g.Source, w.Source) 105948- } 105949- } 105950- 105951- for _, w := range unmatched { 105952- t.Errorf("%s:%s: unmatched diagnostic pattern %q", fileName, w.Range, w.Message) 105953- } 105954-} 105955- 105956-// rangeOverlaps reports whether r1 and r2 overlap. 105957-func rangeOverlaps(r1, r2 protocol.Range) bool { 105958- if inRange(r2.Start, r1) || inRange(r1.Start, r2) { 105959- return true 105960- } 105961- return false 105962-} 105963- 105964-// inRange reports whether p is contained within [r.Start, r.End), or if p == 105965-// r.Start == r.End (special handling for the case where the range is a single 105966-// point). 105967-func inRange(p protocol.Position, r protocol.Range) bool { 105968- if protocol.IsPoint(r) { 105969- return protocol.ComparePosition(r.Start, p) == 0 105970- } 105971- if protocol.ComparePosition(r.Start, p) <= 0 && protocol.ComparePosition(p, r.End) < 0 { 105972- return true 105973- } 105974- return false 105975-} 105976- 105977-func DiffCodeLens(uri span.URI, want, got []protocol.CodeLens) string { 105978- sortCodeLens(want) 105979- sortCodeLens(got) 105980- 105981- if len(got) != len(want) { 105982- return summarizeCodeLens(-1, uri, want, got, "different lengths got %v want %v", len(got), len(want)) 105983- } 105984- for i, w := range want { 105985- g := got[i] 105986- if w.Command.Command != g.Command.Command { 105987- return summarizeCodeLens(i, uri, want, got, "incorrect Command Name got %v want %v", g.Command.Command, w.Command.Command) 105988- } 105989- if w.Command.Title != g.Command.Title { 105990- return summarizeCodeLens(i, uri, want, got, "incorrect Command Title got %v want %v", g.Command.Title, w.Command.Title) 105991- } 105992- if protocol.ComparePosition(w.Range.Start, g.Range.Start) != 0 { 105993- return summarizeCodeLens(i, uri, want, got, "incorrect Start got %v want %v", g.Range.Start, w.Range.Start) 105994- } 105995- if !protocol.IsPoint(g.Range) { // Accept any 'want' range if the codelens returns a zero-length range. 105996- if protocol.ComparePosition(w.Range.End, g.Range.End) != 0 { 105997- return summarizeCodeLens(i, uri, want, got, "incorrect End got %v want %v", g.Range.End, w.Range.End) 105998- } 105999- } 106000- } 106001- return "" 106002-} 106003- 106004-func sortCodeLens(c []protocol.CodeLens) { 106005- sort.Slice(c, func(i int, j int) bool { 106006- if r := protocol.CompareRange(c[i].Range, c[j].Range); r != 0 { 106007- return r < 0 106008- } 106009- if c[i].Command.Command < c[j].Command.Command { 106010- return true 106011- } else if c[i].Command.Command == c[j].Command.Command { 106012- return c[i].Command.Title < c[j].Command.Title 106013- } else { 106014- return false 106015- } 106016- }) 106017-} 106018- 106019-func summarizeCodeLens(i int, uri span.URI, want, got []protocol.CodeLens, reason string, args ...interface{}) string { 106020- msg := &bytes.Buffer{} 106021- fmt.Fprint(msg, "codelens failed") 106022- if i >= 0 { 106023- fmt.Fprintf(msg, " at %d", i) 106024- } 106025- fmt.Fprint(msg, " because of ") 106026- fmt.Fprintf(msg, reason, args...) 106027- fmt.Fprint(msg, ":\nexpected:\n") 106028- for _, d := range want { 106029- fmt.Fprintf(msg, " %s:%v: %s | %s\n", uri, d.Range, d.Command.Command, d.Command.Title) 106030- } 106031- fmt.Fprintf(msg, "got:\n") 106032- for _, d := range got { 106033- fmt.Fprintf(msg, " %s:%v: %s | %s\n", uri, d.Range, d.Command.Command, d.Command.Title) 106034- } 106035- return msg.String() 106036-} 106037- 106038-func DiffSignatures(spn span.Span, want, got *protocol.SignatureHelp) string { 106039- decorate := func(f string, args ...interface{}) string { 106040- return fmt.Sprintf("invalid signature at %s: %s", spn, fmt.Sprintf(f, args...)) 106041- } 106042- if len(got.Signatures) != 1 { 106043- return decorate("wanted 1 signature, got %d", len(got.Signatures)) 106044- } 106045- if got.ActiveSignature != 0 { 106046- return decorate("wanted active signature of 0, got %d", int(got.ActiveSignature)) 106047- } 106048- if want.ActiveParameter != got.ActiveParameter { 106049- return decorate("wanted active parameter of %d, got %d", want.ActiveParameter, int(got.ActiveParameter)) 106050- } 106051- g := got.Signatures[0] 106052- w := want.Signatures[0] 106053- if diff := compare.Text(NormalizeAny(w.Label), NormalizeAny(g.Label)); diff != "" { 106054- return decorate("mismatched labels:\n%s", diff) 106055- } 106056- var paramParts []string 106057- for _, p := range g.Parameters { 106058- paramParts = append(paramParts, p.Label) 106059- } 106060- paramsStr := strings.Join(paramParts, ", ") 106061- if !strings.Contains(g.Label, paramsStr) { 106062- return decorate("expected signature %q to contain params %q", g.Label, paramsStr) 106063- } 106064- return "" 106065-} 106066- 106067-// NormalizeAny replaces occurrences of interface{} in input with any. 106068-// 106069-// In Go 1.18, standard library functions were changed to use the 'any' 106070-// alias in place of interface{}, which affects their type string. 106071-func NormalizeAny(input string) string { 106072- return strings.ReplaceAll(input, "interface{}", "any") 106073-} 106074- 106075-// DiffCallHierarchyItems returns the diff between expected and actual call locations for incoming/outgoing call hierarchies 106076-func DiffCallHierarchyItems(gotCalls []protocol.CallHierarchyItem, expectedCalls []protocol.CallHierarchyItem) string { 106077- expected := make(map[protocol.Location]bool) 106078- for _, call := range expectedCalls { 106079- expected[protocol.Location{URI: call.URI, Range: call.Range}] = true 106080- } 106081- 106082- got := make(map[protocol.Location]bool) 106083- for _, call := range gotCalls { 106084- got[protocol.Location{URI: call.URI, Range: call.Range}] = true 106085- } 106086- if len(got) != len(expected) { 106087- return fmt.Sprintf("expected %d calls but got %d", len(expected), len(got)) 106088- } 106089- for spn := range got { 106090- if !expected[spn] { 106091- return fmt.Sprintf("incorrect calls, expected locations %v but got locations %v", expected, got) 106092- } 106093- } 106094- return "" 106095-} 106096- 106097-func FilterBuiltins(src span.Span, items []protocol.CompletionItem) []protocol.CompletionItem { 106098- var ( 106099- got []protocol.CompletionItem 106100- wantBuiltins = strings.Contains(string(src.URI()), "builtins") 106101- wantKeywords = strings.Contains(string(src.URI()), "keywords") 106102- ) 106103- for _, item := range items { 106104- if !wantBuiltins && isBuiltin(item.Label, item.Detail, item.Kind) { 106105- continue 106106- } 106107- 106108- if !wantKeywords && token.Lookup(item.Label).IsKeyword() { 106109- continue 106110- } 106111- 106112- got = append(got, item) 106113- } 106114- return got 106115-} 106116- 106117-func isBuiltin(label, detail string, kind protocol.CompletionItemKind) bool { 106118- if detail == "" && kind == protocol.ClassCompletion { 106119- return true 106120- } 106121- // Remaining builtin constants, variables, interfaces, and functions. 106122- trimmed := label 106123- if i := strings.Index(trimmed, "("); i >= 0 { 106124- trimmed = trimmed[:i] 106125- } 106126- return builtins[trimmed] 106127-} 106128- 106129-func CheckCompletionOrder(want, got []protocol.CompletionItem, strictScores bool) string { 106130- var ( 106131- matchedIdxs []int 106132- lastGotIdx int 106133- lastGotSort float64 106134- inOrder = true 106135- errorMsg = "completions out of order" 106136- ) 106137- for _, w := range want { 106138- var found bool 106139- for i, g := range got { 106140- if w.Label == g.Label && NormalizeAny(w.Detail) == NormalizeAny(g.Detail) && w.Kind == g.Kind { 106141- matchedIdxs = append(matchedIdxs, i) 106142- found = true 106143- 106144- if i < lastGotIdx { 106145- inOrder = false 106146- } 106147- lastGotIdx = i 106148- 106149- sort, _ := strconv.ParseFloat(g.SortText, 64) 106150- if strictScores && len(matchedIdxs) > 1 && sort <= lastGotSort { 106151- inOrder = false 106152- errorMsg = "candidate scores not strictly decreasing" 106153- } 106154- lastGotSort = sort 106155- 106156- break 106157- } 106158- } 106159- if !found { 106160- return summarizeCompletionItems(-1, []protocol.CompletionItem{w}, got, "didn't find expected completion") 106161- } 106162- } 106163- 106164- sort.Ints(matchedIdxs) 106165- matched := make([]protocol.CompletionItem, 0, len(matchedIdxs)) 106166- for _, idx := range matchedIdxs { 106167- matched = append(matched, got[idx]) 106168- } 106169- 106170- if !inOrder { 106171- return summarizeCompletionItems(-1, want, matched, errorMsg) 106172- } 106173- 106174- return "" 106175-} 106176- 106177-func DiffSnippets(want string, got *protocol.CompletionItem) string { 106178- if want == "" { 106179- if got != nil { 106180- x := got.TextEdit 106181- return fmt.Sprintf("expected no snippet but got %s", x.NewText) 106182- } 106183- } else { 106184- if got == nil { 106185- return fmt.Sprintf("couldn't find completion matching %q", want) 106186- } 106187- x := got.TextEdit 106188- if want != x.NewText { 106189- return fmt.Sprintf("expected snippet %q, got %q", want, x.NewText) 106190- } 106191- } 106192- return "" 106193-} 106194- 106195-func FindItem(list []protocol.CompletionItem, want completion.CompletionItem) *protocol.CompletionItem { 106196- for _, item := range list { 106197- if item.Label == want.Label { 106198- return &item 106199- } 106200- } 106201- return nil 106202-} 106203- 106204-// DiffCompletionItems prints the diff between expected and actual completion 106205-// test results. 106206-// 106207-// The diff will be formatted using '-' and '+' for want and got, respectively. 106208-func DiffCompletionItems(want, got []protocol.CompletionItem) string { 106209- // Many fields are not set in the "want" slice. 106210- irrelevantFields := []string{ 106211- "AdditionalTextEdits", 106212- "Documentation", 106213- "TextEdit", 106214- "SortText", 106215- "Preselect", 106216- "FilterText", 106217- "InsertText", 106218- "InsertTextFormat", 106219- } 106220- ignore := cmpopts.IgnoreFields(protocol.CompletionItem{}, irrelevantFields...) 106221- normalizeAny := cmpopts.AcyclicTransformer("NormalizeAny", func(item protocol.CompletionItem) protocol.CompletionItem { 106222- item.Detail = NormalizeAny(item.Detail) 106223- return item 106224- }) 106225- return cmp.Diff(want, got, ignore, normalizeAny) 106226-} 106227- 106228-func summarizeCompletionItems(i int, want, got []protocol.CompletionItem, reason string, args ...interface{}) string { 106229- msg := &bytes.Buffer{} 106230- fmt.Fprint(msg, "completion failed") 106231- if i >= 0 { 106232- fmt.Fprintf(msg, " at %d", i) 106233- } 106234- fmt.Fprint(msg, " because of ") 106235- fmt.Fprintf(msg, reason, args...) 106236- fmt.Fprint(msg, ":\nexpected:\n") 106237- for _, d := range want { 106238- fmt.Fprintf(msg, " %v\n", d) 106239- } 106240- fmt.Fprintf(msg, "got:\n") 106241- for _, d := range got { 106242- fmt.Fprintf(msg, " %v\n", d) 106243- } 106244- return msg.String() 106245-} 106246- 106247-func EnableAllAnalyzers(opts *source.Options) { 106248- if opts.Analyses == nil { 106249- opts.Analyses = make(map[string]bool) 106250- } 106251- for _, a := range opts.DefaultAnalyzers { 106252- if !a.IsEnabled(opts) { 106253- opts.Analyses[a.Analyzer.Name] = true 106254- } 106255- } 106256- for _, a := range opts.TypeErrorAnalyzers { 106257- if !a.IsEnabled(opts) { 106258- opts.Analyses[a.Analyzer.Name] = true 106259- } 106260- } 106261- for _, a := range opts.ConvenienceAnalyzers { 106262- if !a.IsEnabled(opts) { 106263- opts.Analyses[a.Analyzer.Name] = true 106264- } 106265- } 106266- for _, a := range opts.StaticcheckAnalyzers { 106267- if !a.IsEnabled(opts) { 106268- opts.Analyses[a.Analyzer.Name] = true 106269- } 106270- } 106271-} 106272- 106273-func EnableAllInlayHints(opts *source.Options) { 106274- if opts.Hints == nil { 106275- opts.Hints = make(map[string]bool) 106276- } 106277- for name := range source.AllInlayHints { 106278- opts.Hints[name] = true 106279- } 106280-} 106281- 106282-func WorkspaceSymbolsString(ctx context.Context, data *Data, queryURI span.URI, symbols []protocol.SymbolInformation) (string, error) { 106283- queryDir := filepath.Dir(queryURI.Filename()) 106284- var filtered []string 106285- for _, s := range symbols { 106286- uri := s.Location.URI.SpanURI() 106287- dir := filepath.Dir(uri.Filename()) 106288- if !source.InDir(queryDir, dir) { // assume queries always issue from higher directories 106289- continue 106290- } 106291- m, err := data.Mapper(uri) 106292- if err != nil { 106293- return "", err 106294- } 106295- spn, err := m.LocationSpan(s.Location) 106296- if err != nil { 106297- return "", err 106298- } 106299- filtered = append(filtered, fmt.Sprintf("%s %s %s", spn, s.Name, s.Kind)) 106300- } 106301- sort.Strings(filtered) 106302- return strings.Join(filtered, "\n") + "\n", nil 106303-} 106304- 106305-func WorkspaceSymbolsTestTypeToMatcher(typ WorkspaceSymbolsTestType) source.SymbolMatcher { 106306- switch typ { 106307- case WorkspaceSymbolsFuzzy: 106308- return source.SymbolFuzzy 106309- case WorkspaceSymbolsCaseSensitive: 106310- return source.SymbolCaseSensitive 106311- default: 106312- return source.SymbolCaseInsensitive 106313- } 106314-} 106315- 106316-// LocationsToSpans converts protocol location into span form for testing. 106317-func LocationsToSpans(data *Data, locs []protocol.Location) ([]span.Span, error) { 106318- spans := make([]span.Span, len(locs)) 106319- for i, loc := range locs { 106320- m, err := data.Mapper(loc.URI.SpanURI()) 106321- if err != nil { 106322- return nil, err 106323- } 106324- spn, err := m.LocationSpan(loc) 106325- if err != nil { 106326- return nil, fmt.Errorf("failed for %v: %w", loc, err) 106327- } 106328- spans[i] = spn 106329- } 106330- return spans, nil 106331-} 106332- 106333-// SortAndFormatSpans sorts and formats a list of spans for use in an assertion. 106334-func SortAndFormatSpans(spans []span.Span) string { 106335- span.SortSpans(spans) 106336- var buf strings.Builder 106337- for _, spn := range spans { 106338- fmt.Fprintf(&buf, "%v\n", spn) 106339- } 106340- return buf.String() 106341-} 106342diff -urN a/gopls/internal/lsp/tests/util_go118.go b/gopls/internal/lsp/tests/util_go118.go 106343--- a/gopls/internal/lsp/tests/util_go118.go 2000-01-01 00:00:00.000000000 -0000 106344+++ b/gopls/internal/lsp/tests/util_go118.go 1970-01-01 00:00:00.000000000 +0000 106345@@ -1,13 +0,0 @@ 106346-// Copyright 2023 The Go Authors. All rights reserved. 106347-// Use of this source code is governed by a BSD-style 106348-// license that can be found in the LICENSE file. 106349- 106350-//go:build go1.18 106351-// +build go1.18 106352- 106353-package tests 106354- 106355-func init() { 106356- builtins["any"] = true 106357- builtins["comparable"] = true 106358-} 106359diff -urN a/gopls/internal/lsp/tests/util_go121.go b/gopls/internal/lsp/tests/util_go121.go 106360--- a/gopls/internal/lsp/tests/util_go121.go 2000-01-01 00:00:00.000000000 -0000 106361+++ b/gopls/internal/lsp/tests/util_go121.go 1970-01-01 00:00:00.000000000 +0000 106362@@ -1,12 +0,0 @@ 106363-// Copyright 2023 The Go Authors. All rights reserved. 106364-// Use of this source code is governed by a BSD-style 106365-// license that can be found in the LICENSE file. 106366- 106367-//go:build go1.21 106368-// +build go1.21 106369- 106370-package tests 106371- 106372-func init() { 106373- builtins["clear"] = true 106374-} 106375diff -urN a/gopls/internal/lsp/text_synchronization.go b/gopls/internal/lsp/text_synchronization.go 106376--- a/gopls/internal/lsp/text_synchronization.go 2000-01-01 00:00:00.000000000 -0000 106377+++ b/gopls/internal/lsp/text_synchronization.go 1970-01-01 00:00:00.000000000 +0000 106378@@ -1,349 +0,0 @@ 106379-// Copyright 2019 The Go Authors. All rights reserved. 106380-// Use of this source code is governed by a BSD-style 106381-// license that can be found in the LICENSE file. 106382- 106383-package lsp 106384- 106385-import ( 106386- "bytes" 106387- "context" 106388- "errors" 106389- "fmt" 106390- "path/filepath" 106391- "sync" 106392- 106393- "golang.org/x/tools/gopls/internal/lsp/protocol" 106394- "golang.org/x/tools/gopls/internal/lsp/source" 106395- "golang.org/x/tools/gopls/internal/span" 106396- "golang.org/x/tools/internal/jsonrpc2" 106397-) 106398- 106399-// ModificationSource identifies the originating cause of a file modification. 106400-type ModificationSource int 106401- 106402-const ( 106403- // FromDidOpen is a file modification caused by opening a file. 106404- FromDidOpen = ModificationSource(iota) 106405- 106406- // FromDidChange is a file modification caused by changing a file. 106407- FromDidChange 106408- 106409- // FromDidChangeWatchedFiles is a file modification caused by a change to a 106410- // watched file. 106411- FromDidChangeWatchedFiles 106412- 106413- // FromDidSave is a file modification caused by a file save. 106414- FromDidSave 106415- 106416- // FromDidClose is a file modification caused by closing a file. 106417- FromDidClose 106418- 106419- // TODO: add FromDidChangeConfiguration, once configuration changes cause a 106420- // new snapshot to be created. 106421- 106422- // FromRegenerateCgo refers to file modifications caused by regenerating 106423- // the cgo sources for the workspace. 106424- FromRegenerateCgo 106425- 106426- // FromInitialWorkspaceLoad refers to the loading of all packages in the 106427- // workspace when the view is first created. 106428- FromInitialWorkspaceLoad 106429-) 106430- 106431-func (m ModificationSource) String() string { 106432- switch m { 106433- case FromDidOpen: 106434- return "opened files" 106435- case FromDidChange: 106436- return "changed files" 106437- case FromDidChangeWatchedFiles: 106438- return "files changed on disk" 106439- case FromDidSave: 106440- return "saved files" 106441- case FromDidClose: 106442- return "close files" 106443- case FromRegenerateCgo: 106444- return "regenerate cgo" 106445- case FromInitialWorkspaceLoad: 106446- return "initial workspace load" 106447- default: 106448- return "unknown file modification" 106449- } 106450-} 106451- 106452-func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { 106453- uri := params.TextDocument.URI.SpanURI() 106454- if !uri.IsFile() { 106455- return nil 106456- } 106457- // There may not be any matching view in the current session. If that's 106458- // the case, try creating a new view based on the opened file path. 106459- // 106460- // TODO(rstambler): This seems like it would continuously add new 106461- // views, but it won't because ViewOf only returns an error when there 106462- // are no views in the session. I don't know if that logic should go 106463- // here, or if we can continue to rely on that implementation detail. 106464- if _, err := s.session.ViewOf(uri); err != nil { 106465- dir := filepath.Dir(uri.Filename()) 106466- if err := s.addFolders(ctx, []protocol.WorkspaceFolder{{ 106467- URI: string(protocol.URIFromPath(dir)), 106468- Name: filepath.Base(dir), 106469- }}); err != nil { 106470- return err 106471- } 106472- } 106473- return s.didModifyFiles(ctx, []source.FileModification{{ 106474- URI: uri, 106475- Action: source.Open, 106476- Version: params.TextDocument.Version, 106477- Text: []byte(params.TextDocument.Text), 106478- LanguageID: params.TextDocument.LanguageID, 106479- }}, FromDidOpen) 106480-} 106481- 106482-func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error { 106483- uri := params.TextDocument.URI.SpanURI() 106484- if !uri.IsFile() { 106485- return nil 106486- } 106487- 106488- text, err := s.changedText(ctx, uri, params.ContentChanges) 106489- if err != nil { 106490- return err 106491- } 106492- c := source.FileModification{ 106493- URI: uri, 106494- Action: source.Change, 106495- Version: params.TextDocument.Version, 106496- Text: text, 106497- } 106498- if err := s.didModifyFiles(ctx, []source.FileModification{c}, FromDidChange); err != nil { 106499- return err 106500- } 106501- return s.warnAboutModifyingGeneratedFiles(ctx, uri) 106502-} 106503- 106504-// warnAboutModifyingGeneratedFiles shows a warning if a user tries to edit a 106505-// generated file for the first time. 106506-func (s *Server) warnAboutModifyingGeneratedFiles(ctx context.Context, uri span.URI) error { 106507- s.changedFilesMu.Lock() 106508- _, ok := s.changedFiles[uri] 106509- if !ok { 106510- s.changedFiles[uri] = struct{}{} 106511- } 106512- s.changedFilesMu.Unlock() 106513- 106514- // This file has already been edited before. 106515- if ok { 106516- return nil 106517- } 106518- 106519- // Ideally, we should be able to specify that a generated file should 106520- // be opened as read-only. Tell the user that they should not be 106521- // editing a generated file. 106522- view, err := s.session.ViewOf(uri) 106523- if err != nil { 106524- return err 106525- } 106526- snapshot, release, err := view.Snapshot() 106527- if err != nil { 106528- return err 106529- } 106530- isGenerated := source.IsGenerated(ctx, snapshot, uri) 106531- release() 106532- 106533- if !isGenerated { 106534- return nil 106535- } 106536- return s.client.ShowMessage(ctx, &protocol.ShowMessageParams{ 106537- Message: fmt.Sprintf("Do not edit this file! %s is a generated file.", uri.Filename()), 106538- Type: protocol.Warning, 106539- }) 106540-} 106541- 106542-func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.DidChangeWatchedFilesParams) error { 106543- var modifications []source.FileModification 106544- for _, change := range params.Changes { 106545- uri := change.URI.SpanURI() 106546- if !uri.IsFile() { 106547- continue 106548- } 106549- action := changeTypeToFileAction(change.Type) 106550- modifications = append(modifications, source.FileModification{ 106551- URI: uri, 106552- Action: action, 106553- OnDisk: true, 106554- }) 106555- } 106556- return s.didModifyFiles(ctx, modifications, FromDidChangeWatchedFiles) 106557-} 106558- 106559-func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) error { 106560- uri := params.TextDocument.URI.SpanURI() 106561- if !uri.IsFile() { 106562- return nil 106563- } 106564- c := source.FileModification{ 106565- URI: uri, 106566- Action: source.Save, 106567- } 106568- if params.Text != nil { 106569- c.Text = []byte(*params.Text) 106570- } 106571- return s.didModifyFiles(ctx, []source.FileModification{c}, FromDidSave) 106572-} 106573- 106574-func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error { 106575- uri := params.TextDocument.URI.SpanURI() 106576- if !uri.IsFile() { 106577- return nil 106578- } 106579- return s.didModifyFiles(ctx, []source.FileModification{ 106580- { 106581- URI: uri, 106582- Action: source.Close, 106583- Version: -1, 106584- Text: nil, 106585- }, 106586- }, FromDidClose) 106587-} 106588- 106589-func (s *Server) didModifyFiles(ctx context.Context, modifications []source.FileModification, cause ModificationSource) error { 106590- // wg guards two conditions: 106591- // 1. didModifyFiles is complete 106592- // 2. the goroutine diagnosing changes on behalf of didModifyFiles is 106593- // complete, if it was started 106594- // 106595- // Both conditions must be satisfied for the purpose of testing: we don't 106596- // want to observe the completion of change processing until we have received 106597- // all diagnostics as well as all server->client notifications done on behalf 106598- // of this function. 106599- var wg sync.WaitGroup 106600- wg.Add(1) 106601- defer wg.Done() 106602- 106603- if s.session.Options().VerboseWorkDoneProgress { 106604- work := s.progress.Start(ctx, DiagnosticWorkTitle(cause), "Calculating file diagnostics...", nil, nil) 106605- go func() { 106606- wg.Wait() 106607- work.End(ctx, "Done.") 106608- }() 106609- } 106610- 106611- onDisk := cause == FromDidChangeWatchedFiles 106612- 106613- s.stateMu.Lock() 106614- if s.state >= serverShutDown { 106615- // This state check does not prevent races below, and exists only to 106616- // produce a better error message. The actual race to the cache should be 106617- // guarded by Session.viewMu. 106618- s.stateMu.Unlock() 106619- return errors.New("server is shut down") 106620- } 106621- s.stateMu.Unlock() 106622- 106623- // If the set of changes included directories, expand those directories 106624- // to their files. 106625- modifications = s.session.ExpandModificationsToDirectories(ctx, modifications) 106626- 106627- // Build a lookup map for file modifications, so that we can later join 106628- // with the snapshot file associations. 106629- modMap := make(map[span.URI]source.FileModification) 106630- for _, mod := range modifications { 106631- modMap[mod.URI] = mod 106632- } 106633- 106634- snapshots, release, err := s.session.DidModifyFiles(ctx, modifications) 106635- if err != nil { 106636- return err 106637- } 106638- 106639- // golang/go#50267: diagnostics should be re-sent after an open or close. For 106640- // some clients, it may be helpful to re-send after each change. 106641- for snapshot, uris := range snapshots { 106642- for _, uri := range uris { 106643- mod := modMap[uri] 106644- if snapshot.View().Options().ChattyDiagnostics || mod.Action == source.Open || mod.Action == source.Close { 106645- s.mustPublishDiagnostics(uri) 106646- } 106647- } 106648- } 106649- 106650- wg.Add(1) 106651- go func() { 106652- s.diagnoseSnapshots(snapshots, onDisk) 106653- release() 106654- wg.Done() 106655- }() 106656- 106657- // After any file modifications, we need to update our watched files, 106658- // in case something changed. Compute the new set of directories to watch, 106659- // and if it differs from the current set, send updated registrations. 106660- return s.updateWatchedDirectories(ctx) 106661-} 106662- 106663-// DiagnosticWorkTitle returns the title of the diagnostic work resulting from a 106664-// file change originating from the given cause. 106665-func DiagnosticWorkTitle(cause ModificationSource) string { 106666- return fmt.Sprintf("diagnosing %v", cause) 106667-} 106668- 106669-func (s *Server) changedText(ctx context.Context, uri span.URI, changes []protocol.TextDocumentContentChangeEvent) ([]byte, error) { 106670- if len(changes) == 0 { 106671- return nil, fmt.Errorf("%w: no content changes provided", jsonrpc2.ErrInternal) 106672- } 106673- 106674- // Check if the client sent the full content of the file. 106675- // We accept a full content change even if the server expected incremental changes. 106676- if len(changes) == 1 && changes[0].Range == nil && changes[0].RangeLength == 0 { 106677- return []byte(changes[0].Text), nil 106678- } 106679- return s.applyIncrementalChanges(ctx, uri, changes) 106680-} 106681- 106682-func (s *Server) applyIncrementalChanges(ctx context.Context, uri span.URI, changes []protocol.TextDocumentContentChangeEvent) ([]byte, error) { 106683- fh, err := s.session.GetFile(ctx, uri) 106684- if err != nil { 106685- return nil, err 106686- } 106687- content, err := fh.Read() 106688- if err != nil { 106689- return nil, fmt.Errorf("%w: file not found (%v)", jsonrpc2.ErrInternal, err) 106690- } 106691- for _, change := range changes { 106692- // TODO(adonovan): refactor to use diff.Apply, which is robust w.r.t. 106693- // out-of-order or overlapping changes---and much more efficient. 106694- 106695- // Make sure to update mapper along with the content. 106696- m := protocol.NewMapper(uri, content) 106697- if change.Range == nil { 106698- return nil, fmt.Errorf("%w: unexpected nil range for change", jsonrpc2.ErrInternal) 106699- } 106700- spn, err := m.RangeSpan(*change.Range) 106701- if err != nil { 106702- return nil, err 106703- } 106704- start, end := spn.Start().Offset(), spn.End().Offset() 106705- if end < start { 106706- return nil, fmt.Errorf("%w: invalid range for content change", jsonrpc2.ErrInternal) 106707- } 106708- var buf bytes.Buffer 106709- buf.Write(content[:start]) 106710- buf.WriteString(change.Text) 106711- buf.Write(content[end:]) 106712- content = buf.Bytes() 106713- } 106714- return content, nil 106715-} 106716- 106717-func changeTypeToFileAction(ct protocol.FileChangeType) source.FileAction { 106718- switch ct { 106719- case protocol.Changed: 106720- return source.Change 106721- case protocol.Created: 106722- return source.Create 106723- case protocol.Deleted: 106724- return source.Delete 106725- } 106726- return source.UnknownFileAction 106727-} 106728diff -urN a/gopls/internal/lsp/work/completion.go b/gopls/internal/lsp/work/completion.go 106729--- a/gopls/internal/lsp/work/completion.go 2000-01-01 00:00:00.000000000 -0000 106730+++ b/gopls/internal/lsp/work/completion.go 1970-01-01 00:00:00.000000000 +0000 106731@@ -1,154 +0,0 @@ 106732-// Copyright 2022 The Go Authors. All rights reserved. 106733-// Use of this source code is governed by a BSD-style 106734-// license that can be found in the LICENSE file. 106735- 106736-package work 106737- 106738-import ( 106739- "context" 106740- "errors" 106741- "fmt" 106742- "os" 106743- "path/filepath" 106744- "sort" 106745- "strings" 106746- 106747- "golang.org/x/tools/gopls/internal/lsp/protocol" 106748- "golang.org/x/tools/gopls/internal/lsp/source" 106749- "golang.org/x/tools/internal/event" 106750-) 106751- 106752-func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.CompletionList, error) { 106753- ctx, done := event.Start(ctx, "work.Completion") 106754- defer done() 106755- 106756- // Get the position of the cursor. 106757- pw, err := snapshot.ParseWork(ctx, fh) 106758- if err != nil { 106759- return nil, fmt.Errorf("getting go.work file handle: %w", err) 106760- } 106761- cursor, err := pw.Mapper.PositionOffset(position) 106762- if err != nil { 106763- return nil, fmt.Errorf("computing cursor offset: %w", err) 106764- } 106765- 106766- // Find the use statement the user is in. 106767- use, pathStart, _ := usePath(pw, cursor) 106768- if use == nil { 106769- return &protocol.CompletionList{}, nil 106770- } 106771- completingFrom := use.Path[:cursor-pathStart] 106772- 106773- // We're going to find the completions of the user input 106774- // (completingFrom) by doing a walk on the innermost directory 106775- // of the given path, and comparing the found paths to make sure 106776- // that they match the component of the path after the 106777- // innermost directory. 106778- // 106779- // We'll maintain two paths when doing this: pathPrefixSlash 106780- // is essentially the path the user typed in, and pathPrefixAbs 106781- // is the path made absolute from the go.work directory. 106782- 106783- pathPrefixSlash := completingFrom 106784- pathPrefixAbs := filepath.FromSlash(pathPrefixSlash) 106785- if !filepath.IsAbs(pathPrefixAbs) { 106786- pathPrefixAbs = filepath.Join(filepath.Dir(pw.URI.Filename()), pathPrefixAbs) 106787- } 106788- 106789- // pathPrefixDir is the directory that will be walked to find matches. 106790- // If pathPrefixSlash is not explicitly a directory boundary (is either equivalent to "." or 106791- // ends in a separator) we need to examine its parent directory to find sibling files that 106792- // match. 106793- depthBound := 5 106794- pathPrefixDir, pathPrefixBase := pathPrefixAbs, "" 106795- pathPrefixSlashDir := pathPrefixSlash 106796- if filepath.Clean(pathPrefixSlash) != "." && !strings.HasSuffix(pathPrefixSlash, "/") { 106797- depthBound++ 106798- pathPrefixDir, pathPrefixBase = filepath.Split(pathPrefixAbs) 106799- pathPrefixSlashDir = dirNonClean(pathPrefixSlash) 106800- } 106801- 106802- var completions []string 106803- // Stop traversing deeper once we've hit 10k files to try to stay generally under 100ms. 106804- const numSeenBound = 10000 106805- var numSeen int 106806- stopWalking := errors.New("hit numSeenBound") 106807- err = filepath.Walk(pathPrefixDir, func(wpath string, info os.FileInfo, err error) error { 106808- if numSeen > numSeenBound { 106809- // Stop traversing if we hit bound. 106810- return stopWalking 106811- } 106812- numSeen++ 106813- 106814- // rel is the path relative to pathPrefixDir. 106815- // Make sure that it has pathPrefixBase as a prefix 106816- // otherwise it won't match the beginning of the 106817- // base component of the path the user typed in. 106818- rel := strings.TrimPrefix(wpath[len(pathPrefixDir):], string(filepath.Separator)) 106819- if info.IsDir() && wpath != pathPrefixDir && !strings.HasPrefix(rel, pathPrefixBase) { 106820- return filepath.SkipDir 106821- } 106822- 106823- // Check for a match (a module directory). 106824- if filepath.Base(rel) == "go.mod" { 106825- relDir := strings.TrimSuffix(dirNonClean(rel), string(os.PathSeparator)) 106826- completionPath := join(pathPrefixSlashDir, filepath.ToSlash(relDir)) 106827- 106828- if !strings.HasPrefix(completionPath, completingFrom) { 106829- return nil 106830- } 106831- if strings.HasSuffix(completionPath, "/") { 106832- // Don't suggest paths that end in "/". This happens 106833- // when the input is a path that ends in "/" and 106834- // the completion is empty. 106835- return nil 106836- } 106837- completion := completionPath[len(completingFrom):] 106838- if completingFrom == "" && !strings.HasPrefix(completion, "./") { 106839- // Bias towards "./" prefixes. 106840- completion = join(".", completion) 106841- } 106842- 106843- completions = append(completions, completion) 106844- } 106845- 106846- if depth := strings.Count(rel, string(filepath.Separator)); depth >= depthBound { 106847- return filepath.SkipDir 106848- } 106849- return nil 106850- }) 106851- if err != nil && !errors.Is(err, stopWalking) { 106852- return nil, fmt.Errorf("walking to find completions: %w", err) 106853- } 106854- 106855- sort.Strings(completions) 106856- 106857- var items []protocol.CompletionItem 106858- for _, c := range completions { 106859- items = append(items, protocol.CompletionItem{ 106860- Label: c, 106861- InsertText: c, 106862- }) 106863- } 106864- return &protocol.CompletionList{Items: items}, nil 106865-} 106866- 106867-// dirNonClean is filepath.Dir, without the Clean at the end. 106868-func dirNonClean(path string) string { 106869- vol := filepath.VolumeName(path) 106870- i := len(path) - 1 106871- for i >= len(vol) && !os.IsPathSeparator(path[i]) { 106872- i-- 106873- } 106874- return path[len(vol) : i+1] 106875-} 106876- 106877-func join(a, b string) string { 106878- if a == "" { 106879- return b 106880- } 106881- if b == "" { 106882- return a 106883- } 106884- return strings.TrimSuffix(a, "/") + "/" + b 106885-} 106886diff -urN a/gopls/internal/lsp/work/diagnostics.go b/gopls/internal/lsp/work/diagnostics.go 106887--- a/gopls/internal/lsp/work/diagnostics.go 2000-01-01 00:00:00.000000000 -0000 106888+++ b/gopls/internal/lsp/work/diagnostics.go 1970-01-01 00:00:00.000000000 +0000 106889@@ -1,92 +0,0 @@ 106890-// Copyright 2022 The Go Authors. All rights reserved. 106891-// Use of this source code is governed by a BSD-style 106892-// license that can be found in the LICENSE file. 106893- 106894-package work 106895- 106896-import ( 106897- "context" 106898- "fmt" 106899- "os" 106900- "path/filepath" 106901- 106902- "golang.org/x/mod/modfile" 106903- "golang.org/x/tools/gopls/internal/lsp/protocol" 106904- "golang.org/x/tools/gopls/internal/lsp/source" 106905- "golang.org/x/tools/gopls/internal/span" 106906- "golang.org/x/tools/internal/event" 106907-) 106908- 106909-func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) { 106910- ctx, done := event.Start(ctx, "work.Diagnostics", source.SnapshotLabels(snapshot)...) 106911- defer done() 106912- 106913- reports := map[span.URI][]*source.Diagnostic{} 106914- uri := snapshot.WorkFile() 106915- if uri == "" { 106916- return nil, nil 106917- } 106918- fh, err := snapshot.GetFile(ctx, uri) 106919- if err != nil { 106920- return nil, err 106921- } 106922- reports[fh.URI()] = []*source.Diagnostic{} 106923- diagnostics, err := DiagnosticsForWork(ctx, snapshot, fh) 106924- if err != nil { 106925- return nil, err 106926- } 106927- for _, d := range diagnostics { 106928- fh, err := snapshot.GetFile(ctx, d.URI) 106929- if err != nil { 106930- return nil, err 106931- } 106932- reports[fh.URI()] = append(reports[fh.URI()], d) 106933- } 106934- 106935- return reports, nil 106936-} 106937- 106938-func DiagnosticsForWork(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]*source.Diagnostic, error) { 106939- pw, err := snapshot.ParseWork(ctx, fh) 106940- if err != nil { 106941- if pw == nil || len(pw.ParseErrors) == 0 { 106942- return nil, err 106943- } 106944- return pw.ParseErrors, nil 106945- } 106946- 106947- // Add diagnostic if a directory does not contain a module. 106948- var diagnostics []*source.Diagnostic 106949- for _, use := range pw.File.Use { 106950- rng, err := pw.Mapper.OffsetRange(use.Syntax.Start.Byte, use.Syntax.End.Byte) 106951- if err != nil { 106952- return nil, err 106953- } 106954- 106955- modfh, err := snapshot.GetFile(ctx, modFileURI(pw, use)) 106956- if err != nil { 106957- return nil, err 106958- } 106959- if _, err := modfh.Read(); err != nil && os.IsNotExist(err) { 106960- diagnostics = append(diagnostics, &source.Diagnostic{ 106961- URI: fh.URI(), 106962- Range: rng, 106963- Severity: protocol.SeverityError, 106964- Source: source.WorkFileError, 106965- Message: fmt.Sprintf("directory %v does not contain a module", use.Path), 106966- }) 106967- } 106968- } 106969- return diagnostics, nil 106970-} 106971- 106972-func modFileURI(pw *source.ParsedWorkFile, use *modfile.Use) span.URI { 106973- workdir := filepath.Dir(pw.URI.Filename()) 106974- 106975- modroot := filepath.FromSlash(use.Path) 106976- if !filepath.IsAbs(modroot) { 106977- modroot = filepath.Join(workdir, modroot) 106978- } 106979- 106980- return span.URIFromPath(filepath.Join(modroot, "go.mod")) 106981-} 106982diff -urN a/gopls/internal/lsp/work/format.go b/gopls/internal/lsp/work/format.go 106983--- a/gopls/internal/lsp/work/format.go 2000-01-01 00:00:00.000000000 -0000 106984+++ b/gopls/internal/lsp/work/format.go 1970-01-01 00:00:00.000000000 +0000 106985@@ -1,28 +0,0 @@ 106986-// Copyright 2022 The Go Authors. All rights reserved. 106987-// Use of this source code is governed by a BSD-style 106988-// license that can be found in the LICENSE file. 106989- 106990-package work 106991- 106992-import ( 106993- "context" 106994- 106995- "golang.org/x/mod/modfile" 106996- "golang.org/x/tools/gopls/internal/lsp/protocol" 106997- "golang.org/x/tools/gopls/internal/lsp/source" 106998- "golang.org/x/tools/internal/event" 106999-) 107000- 107001-func Format(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.TextEdit, error) { 107002- ctx, done := event.Start(ctx, "work.Format") 107003- defer done() 107004- 107005- pw, err := snapshot.ParseWork(ctx, fh) 107006- if err != nil { 107007- return nil, err 107008- } 107009- formatted := modfile.Format(pw.File.Syntax) 107010- // Calculate the edits to be made due to the change. 107011- diffs := snapshot.View().Options().ComputeEdits(string(pw.Mapper.Content), string(formatted)) 107012- return source.ToProtocolEdits(pw.Mapper, diffs) 107013-} 107014diff -urN a/gopls/internal/lsp/work/hover.go b/gopls/internal/lsp/work/hover.go 107015--- a/gopls/internal/lsp/work/hover.go 2000-01-01 00:00:00.000000000 -0000 107016+++ b/gopls/internal/lsp/work/hover.go 1970-01-01 00:00:00.000000000 +0000 107017@@ -1,89 +0,0 @@ 107018-// Copyright 2022 The Go Authors. All rights reserved. 107019-// Use of this source code is governed by a BSD-style 107020-// license that can be found in the LICENSE file. 107021- 107022-package work 107023- 107024-import ( 107025- "bytes" 107026- "context" 107027- "fmt" 107028- 107029- "golang.org/x/mod/modfile" 107030- "golang.org/x/tools/gopls/internal/lsp/protocol" 107031- "golang.org/x/tools/gopls/internal/lsp/source" 107032- "golang.org/x/tools/internal/event" 107033-) 107034- 107035-func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.Hover, error) { 107036- // We only provide hover information for the view's go.work file. 107037- if fh.URI() != snapshot.WorkFile() { 107038- return nil, nil 107039- } 107040- 107041- ctx, done := event.Start(ctx, "work.Hover") 107042- defer done() 107043- 107044- // Get the position of the cursor. 107045- pw, err := snapshot.ParseWork(ctx, fh) 107046- if err != nil { 107047- return nil, fmt.Errorf("getting go.work file handle: %w", err) 107048- } 107049- offset, err := pw.Mapper.PositionOffset(position) 107050- if err != nil { 107051- return nil, fmt.Errorf("computing cursor offset: %w", err) 107052- } 107053- 107054- // Confirm that the cursor is inside a use statement, and then find 107055- // the position of the use statement's directory path. 107056- use, pathStart, pathEnd := usePath(pw, offset) 107057- 107058- // The cursor position is not on a use statement. 107059- if use == nil { 107060- return nil, nil 107061- } 107062- 107063- // Get the mod file denoted by the use. 107064- modfh, err := snapshot.GetFile(ctx, modFileURI(pw, use)) 107065- if err != nil { 107066- return nil, fmt.Errorf("getting modfile handle: %w", err) 107067- } 107068- pm, err := snapshot.ParseMod(ctx, modfh) 107069- if err != nil { 107070- return nil, fmt.Errorf("getting modfile handle: %w", err) 107071- } 107072- mod := pm.File.Module.Mod 107073- 107074- // Get the range to highlight for the hover. 107075- rng, err := pw.Mapper.OffsetRange(pathStart, pathEnd) 107076- if err != nil { 107077- return nil, err 107078- } 107079- options := snapshot.View().Options() 107080- return &protocol.Hover{ 107081- Contents: protocol.MarkupContent{ 107082- Kind: options.PreferredContentFormat, 107083- Value: mod.Path, 107084- }, 107085- Range: rng, 107086- }, nil 107087-} 107088- 107089-func usePath(pw *source.ParsedWorkFile, offset int) (use *modfile.Use, pathStart, pathEnd int) { 107090- for _, u := range pw.File.Use { 107091- path := []byte(u.Path) 107092- s, e := u.Syntax.Start.Byte, u.Syntax.End.Byte 107093- i := bytes.Index(pw.Mapper.Content[s:e], path) 107094- if i == -1 { 107095- // This should not happen. 107096- continue 107097- } 107098- // Shift the start position to the location of the 107099- // module directory within the use statement. 107100- pathStart, pathEnd = s+i, s+i+len(path) 107101- if pathStart <= offset && offset <= pathEnd { 107102- return u, pathStart, pathEnd 107103- } 107104- } 107105- return nil, 0, 0 107106-} 107107diff -urN a/gopls/internal/lsp/workspace.go b/gopls/internal/lsp/workspace.go 107108--- a/gopls/internal/lsp/workspace.go 2000-01-01 00:00:00.000000000 -0000 107109+++ b/gopls/internal/lsp/workspace.go 1970-01-01 00:00:00.000000000 +0000 107110@@ -1,95 +0,0 @@ 107111-// Copyright 2019 The Go Authors. All rights reserved. 107112-// Use of this source code is governed by a BSD-style 107113-// license that can be found in the LICENSE file. 107114- 107115-package lsp 107116- 107117-import ( 107118- "context" 107119- "fmt" 107120- 107121- "golang.org/x/tools/gopls/internal/lsp/protocol" 107122- "golang.org/x/tools/gopls/internal/lsp/source" 107123- "golang.org/x/tools/gopls/internal/span" 107124-) 107125- 107126-func (s *Server) didChangeWorkspaceFolders(ctx context.Context, params *protocol.DidChangeWorkspaceFoldersParams) error { 107127- event := params.Event 107128- for _, folder := range event.Removed { 107129- view := s.session.View(folder.Name) 107130- if view != nil { 107131- s.session.RemoveView(view) 107132- } else { 107133- return fmt.Errorf("view %s for %v not found", folder.Name, folder.URI) 107134- } 107135- } 107136- return s.addFolders(ctx, event.Added) 107137-} 107138- 107139-// addView returns a Snapshot and a release function that must be 107140-// called when it is no longer needed. 107141-func (s *Server) addView(ctx context.Context, name string, uri span.URI) (source.Snapshot, func(), error) { 107142- s.stateMu.Lock() 107143- state := s.state 107144- s.stateMu.Unlock() 107145- if state < serverInitialized { 107146- return nil, nil, fmt.Errorf("addView called before server initialized") 107147- } 107148- options := s.session.Options().Clone() 107149- if err := s.fetchConfig(ctx, name, uri, options); err != nil { 107150- return nil, nil, err 107151- } 107152- _, snapshot, release, err := s.session.NewView(ctx, name, uri, options) 107153- return snapshot, release, err 107154-} 107155- 107156-func (s *Server) didChangeConfiguration(ctx context.Context, _ *protocol.DidChangeConfigurationParams) error { 107157- // Apply any changes to the session-level settings. 107158- options := s.session.Options().Clone() 107159- if err := s.fetchConfig(ctx, "", "", options); err != nil { 107160- return err 107161- } 107162- s.session.SetOptions(options) 107163- 107164- // Go through each view, getting and updating its configuration. 107165- for _, view := range s.session.Views() { 107166- options := s.session.Options().Clone() 107167- if err := s.fetchConfig(ctx, view.Name(), view.Folder(), options); err != nil { 107168- return err 107169- } 107170- view, err := s.session.SetViewOptions(ctx, view, options) 107171- if err != nil { 107172- return err 107173- } 107174- go func() { 107175- snapshot, release, err := view.Snapshot() 107176- if err != nil { 107177- return // view is shut down; no need to diagnose 107178- } 107179- defer release() 107180- s.diagnoseDetached(snapshot) 107181- }() 107182- } 107183- 107184- // An options change may have affected the detected Go version. 107185- s.checkViewGoVersions() 107186- 107187- return nil 107188-} 107189- 107190-func semanticTokenRegistration(tokenTypes, tokenModifiers []string) protocol.Registration { 107191- return protocol.Registration{ 107192- ID: "textDocument/semanticTokens", 107193- Method: "textDocument/semanticTokens", 107194- RegisterOptions: &protocol.SemanticTokensOptions{ 107195- Legend: protocol.SemanticTokensLegend{ 107196- // TODO(pjw): trim these to what we use (and an unused one 107197- // at position 0 of TokTypes, to catch typos) 107198- TokenTypes: tokenTypes, 107199- TokenModifiers: tokenModifiers, 107200- }, 107201- Full: &protocol.Or_SemanticTokensOptions_full{Value: true}, 107202- Range: &protocol.Or_SemanticTokensOptions_range{Value: true}, 107203- }, 107204- } 107205-} 107206diff -urN a/gopls/internal/lsp/workspace_symbol.go b/gopls/internal/lsp/workspace_symbol.go 107207--- a/gopls/internal/lsp/workspace_symbol.go 2000-01-01 00:00:00.000000000 -0000 107208+++ b/gopls/internal/lsp/workspace_symbol.go 1970-01-01 00:00:00.000000000 +0000 107209@@ -1,32 +0,0 @@ 107210-// Copyright 2020 The Go Authors. All rights reserved. 107211-// Use of this source code is governed by a BSD-style 107212-// license that can be found in the LICENSE file. 107213- 107214-package lsp 107215- 107216-import ( 107217- "context" 107218- 107219- "golang.org/x/tools/gopls/internal/lsp/protocol" 107220- "golang.org/x/tools/gopls/internal/lsp/source" 107221- "golang.org/x/tools/internal/event" 107222-) 107223- 107224-func (s *Server) symbol(ctx context.Context, params *protocol.WorkspaceSymbolParams) ([]protocol.SymbolInformation, error) { 107225- ctx, done := event.Start(ctx, "lsp.Server.symbol") 107226- defer done() 107227- 107228- views := s.session.Views() 107229- matcher := s.session.Options().SymbolMatcher 107230- style := s.session.Options().SymbolStyle 107231- // TODO(rfindley): it looks wrong that we need to pass views here. 107232- // 107233- // Evidence: 107234- // - this is the only place we convert views to []source.View 107235- // - workspace symbols is the only place where we call source.View.Snapshot 107236- var sourceViews []source.View 107237- for _, v := range views { 107238- sourceViews = append(sourceViews, v) 107239- } 107240- return source.WorkspaceSymbols(ctx, matcher, style, sourceViews, params.Query) 107241-} 107242diff -urN a/gopls/internal/regtest/bench/bench_test.go b/gopls/internal/regtest/bench/bench_test.go 107243--- a/gopls/internal/regtest/bench/bench_test.go 2000-01-01 00:00:00.000000000 -0000 107244+++ b/gopls/internal/regtest/bench/bench_test.go 1970-01-01 00:00:00.000000000 +0000 107245@@ -1,249 +0,0 @@ 107246-// Copyright 2020 The Go Authors. All rights reserved. 107247-// Use of this source code is governed by a BSD-style 107248-// license that can be found in the LICENSE file. 107249- 107250-package bench 107251- 107252-import ( 107253- "context" 107254- "flag" 107255- "fmt" 107256- "io/ioutil" 107257- "log" 107258- "os" 107259- "os/exec" 107260- "path/filepath" 107261- "sync" 107262- "testing" 107263- "time" 107264- 107265- "golang.org/x/tools/gopls/internal/hooks" 107266- "golang.org/x/tools/gopls/internal/lsp/cmd" 107267- "golang.org/x/tools/gopls/internal/lsp/fake" 107268- "golang.org/x/tools/internal/bug" 107269- "golang.org/x/tools/internal/event" 107270- "golang.org/x/tools/internal/fakenet" 107271- "golang.org/x/tools/internal/jsonrpc2" 107272- "golang.org/x/tools/internal/jsonrpc2/servertest" 107273- "golang.org/x/tools/internal/tool" 107274- 107275- . "golang.org/x/tools/gopls/internal/lsp/regtest" 107276-) 107277- 107278-var ( 107279- goplsPath = flag.String("gopls_path", "", "if set, use this gopls for testing; incompatible with -gopls_commit") 107280- 107281- installGoplsOnce sync.Once // guards installing gopls at -gopls_commit 107282- goplsCommit = flag.String("gopls_commit", "", "if set, install and use gopls at this commit for testing; incompatible with -gopls_path") 107283- 107284- cpuProfile = flag.String("gopls_cpuprofile", "", "if set, the cpu profile file suffix; see \"Profiling\" in the package doc") 107285- memProfile = flag.String("gopls_memprofile", "", "if set, the mem profile file suffix; see \"Profiling\" in the package doc") 107286- trace = flag.String("gopls_trace", "", "if set, the trace file suffix; see \"Profiling\" in the package doc") 107287- 107288- // If non-empty, tempDir is a temporary working dir that was created by this 107289- // test suite. 107290- makeTempDirOnce sync.Once // guards creation of the temp dir 107291- tempDir string 107292-) 107293- 107294-// if runAsGopls is "true", run the gopls command instead of the testing.M. 107295-const runAsGopls = "_GOPLS_BENCH_RUN_AS_GOPLS" 107296- 107297-func TestMain(m *testing.M) { 107298- bug.PanicOnBugs = true 107299- if os.Getenv(runAsGopls) == "true" { 107300- tool.Main(context.Background(), cmd.New("gopls", "", nil, hooks.Options), os.Args[1:]) 107301- os.Exit(0) 107302- } 107303- event.SetExporter(nil) // don't log to stderr 107304- code := m.Run() 107305- if err := cleanup(); err != nil { 107306- fmt.Fprintf(os.Stderr, "cleaning up after benchmarks: %v\n", err) 107307- if code == 0 { 107308- code = 1 107309- } 107310- } 107311- os.Exit(code) 107312-} 107313- 107314-// getTempDir returns the temporary directory to use for benchmark files, 107315-// creating it if necessary. 107316-func getTempDir() string { 107317- makeTempDirOnce.Do(func() { 107318- var err error 107319- tempDir, err = ioutil.TempDir("", "gopls-bench") 107320- if err != nil { 107321- log.Fatal(err) 107322- } 107323- }) 107324- return tempDir 107325-} 107326- 107327-// shallowClone performs a shallow clone of repo into dir at the given 107328-// 'commitish' ref (any commit reference understood by git). 107329-// 107330-// The directory dir must not already exist. 107331-func shallowClone(dir, repo, commitish string) error { 107332- if err := os.Mkdir(dir, 0750); err != nil { 107333- return fmt.Errorf("creating dir for %s: %v", repo, err) 107334- } 107335- 107336- // Set a timeout for git fetch. If this proves flaky, it can be removed. 107337- ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) 107338- defer cancel() 107339- 107340- // Use a shallow fetch to download just the relevant commit. 107341- shInit := fmt.Sprintf("git init && git fetch --depth=1 %q %q && git checkout FETCH_HEAD", repo, commitish) 107342- initCmd := exec.CommandContext(ctx, "/bin/sh", "-c", shInit) 107343- initCmd.Dir = dir 107344- if output, err := initCmd.CombinedOutput(); err != nil { 107345- return fmt.Errorf("checking out %s: %v\n%s", repo, err, output) 107346- } 107347- return nil 107348-} 107349- 107350-// connectEditor connects a fake editor session in the given dir, using the 107351-// given editor config. 107352-func connectEditor(dir string, config fake.EditorConfig, ts servertest.Connector) (*fake.Sandbox, *fake.Editor, *Awaiter, error) { 107353- s, err := fake.NewSandbox(&fake.SandboxConfig{ 107354- Workdir: dir, 107355- GOPROXY: "https://proxy.golang.org", 107356- }) 107357- if err != nil { 107358- return nil, nil, nil, err 107359- } 107360- 107361- a := NewAwaiter(s.Workdir) 107362- const skipApplyEdits = false 107363- editor, err := fake.NewEditor(s, config).Connect(context.Background(), ts, a.Hooks(), skipApplyEdits) 107364- if err != nil { 107365- return nil, nil, nil, err 107366- } 107367- 107368- return s, editor, a, nil 107369-} 107370- 107371-// newGoplsServer returns a connector that connects to a new gopls process. 107372-func newGoplsServer(name string) (servertest.Connector, error) { 107373- if *goplsPath != "" && *goplsCommit != "" { 107374- panic("can't set both -gopls_path and -gopls_commit") 107375- } 107376- var ( 107377- goplsPath = *goplsPath 107378- env []string 107379- ) 107380- if *goplsCommit != "" { 107381- goplsPath = getInstalledGopls() 107382- } 107383- if goplsPath == "" { 107384- var err error 107385- goplsPath, err = os.Executable() 107386- if err != nil { 107387- return nil, err 107388- } 107389- env = []string{fmt.Sprintf("%s=true", runAsGopls)} 107390- } 107391- var args []string 107392- if *cpuProfile != "" { 107393- args = append(args, fmt.Sprintf("-profile.cpu=%s", name+"."+*cpuProfile)) 107394- } 107395- if *memProfile != "" { 107396- args = append(args, fmt.Sprintf("-profile.mem=%s", name+"."+*memProfile)) 107397- } 107398- if *trace != "" { 107399- args = append(args, fmt.Sprintf("-profile.trace=%s", name+"."+*trace)) 107400- } 107401- return &SidecarServer{ 107402- goplsPath: goplsPath, 107403- env: env, 107404- args: args, 107405- }, nil 107406-} 107407- 107408-// getInstalledGopls builds gopls at the given -gopls_commit, returning the 107409-// path to the gopls binary. 107410-func getInstalledGopls() string { 107411- if *goplsCommit == "" { 107412- panic("must provide -gopls_commit") 107413- } 107414- toolsDir := filepath.Join(getTempDir(), "gopls_build") 107415- goplsPath := filepath.Join(toolsDir, "gopls", "gopls") 107416- 107417- installGoplsOnce.Do(func() { 107418- log.Printf("installing gopls: checking out x/tools@%s into %s\n", *goplsCommit, toolsDir) 107419- if err := shallowClone(toolsDir, "https://go.googlesource.com/tools", *goplsCommit); err != nil { 107420- log.Fatal(err) 107421- } 107422- 107423- log.Println("installing gopls: building...") 107424- bld := exec.Command("go", "build", ".") 107425- bld.Dir = filepath.Join(toolsDir, "gopls") 107426- if output, err := bld.CombinedOutput(); err != nil { 107427- log.Fatalf("building gopls: %v\n%s", err, output) 107428- } 107429- 107430- // Confirm that the resulting path now exists. 107431- if _, err := os.Stat(goplsPath); err != nil { 107432- log.Fatalf("os.Stat(%s): %v", goplsPath, err) 107433- } 107434- }) 107435- return goplsPath 107436-} 107437- 107438-// A SidecarServer starts (and connects to) a separate gopls process at the 107439-// given path. 107440-type SidecarServer struct { 107441- goplsPath string 107442- env []string // additional environment bindings 107443- args []string // command-line arguments 107444-} 107445- 107446-// Connect creates new io.Pipes and binds them to the underlying StreamServer. 107447-// 107448-// It implements the servertest.Connector interface. 107449-func (s *SidecarServer) Connect(ctx context.Context) jsonrpc2.Conn { 107450- // Note: don't use CommandContext here, as we want gopls to exit gracefully 107451- // in order to write out profile data. 107452- // 107453- // We close the connection on context cancelation below. 107454- cmd := exec.Command(s.goplsPath, s.args...) 107455- 107456- stdin, err := cmd.StdinPipe() 107457- if err != nil { 107458- log.Fatal(err) 107459- } 107460- stdout, err := cmd.StdoutPipe() 107461- if err != nil { 107462- log.Fatal(err) 107463- } 107464- cmd.Stderr = os.Stderr 107465- cmd.Env = append(os.Environ(), s.env...) 107466- if err := cmd.Start(); err != nil { 107467- log.Fatalf("starting gopls: %v", err) 107468- } 107469- 107470- go func() { 107471- // If we don't log.Fatal here, benchmarks may hang indefinitely if gopls 107472- // exits abnormally. 107473- // 107474- // TODO(rfindley): ideally we would shut down the connection gracefully, 107475- // but that doesn't currently work. 107476- if err := cmd.Wait(); err != nil { 107477- log.Fatalf("gopls invocation failed with error: %v", err) 107478- } 107479- }() 107480- 107481- clientStream := jsonrpc2.NewHeaderStream(fakenet.NewConn("stdio", stdout, stdin)) 107482- clientConn := jsonrpc2.NewConn(clientStream) 107483- 107484- go func() { 107485- select { 107486- case <-ctx.Done(): 107487- clientConn.Close() 107488- clientStream.Close() 107489- case <-clientConn.Done(): 107490- } 107491- }() 107492- 107493- return clientConn 107494-} 107495diff -urN a/gopls/internal/regtest/bench/completion_test.go b/gopls/internal/regtest/bench/completion_test.go 107496--- a/gopls/internal/regtest/bench/completion_test.go 2000-01-01 00:00:00.000000000 -0000 107497+++ b/gopls/internal/regtest/bench/completion_test.go 1970-01-01 00:00:00.000000000 +0000 107498@@ -1,173 +0,0 @@ 107499-// Copyright 2020 The Go Authors. All rights reserved. 107500-// Use of this source code is governed by a BSD-style 107501-// license that can be found in the LICENSE file. 107502- 107503-package bench 107504- 107505-import ( 107506- "fmt" 107507- "testing" 107508- 107509- "golang.org/x/tools/gopls/internal/lsp/fake" 107510- "golang.org/x/tools/gopls/internal/lsp/protocol" 107511- . "golang.org/x/tools/gopls/internal/lsp/regtest" 107512-) 107513- 107514-// TODO(rfindley): update these completion tests to run on multiple repos. 107515- 107516-type completionBenchOptions struct { 107517- file, locationRegexp string 107518- 107519- // Hooks to run edits before initial completion 107520- setup func(*Env) // run before the benchmark starts 107521- beforeCompletion func(*Env) // run before each completion 107522-} 107523- 107524-func benchmarkCompletion(options completionBenchOptions, b *testing.B) { 107525- repo := getRepo(b, "tools") 107526- env := repo.newEnv(b, "completion.tools", fake.EditorConfig{}) 107527- defer env.Close() 107528- 107529- // Run edits required for this completion. 107530- if options.setup != nil { 107531- options.setup(env) 107532- } 107533- 107534- // Run a completion to make sure the system is warm. 107535- loc := env.RegexpSearch(options.file, options.locationRegexp) 107536- completions := env.Completion(loc) 107537- 107538- if testing.Verbose() { 107539- fmt.Println("Results:") 107540- for i := 0; i < len(completions.Items); i++ { 107541- fmt.Printf("\t%d. %v\n", i, completions.Items[i]) 107542- } 107543- } 107544- 107545- b.Run("tools", func(b *testing.B) { 107546- for i := 0; i < b.N; i++ { 107547- if options.beforeCompletion != nil { 107548- options.beforeCompletion(env) 107549- } 107550- env.Completion(loc) 107551- } 107552- }) 107553-} 107554- 107555-// endRangeInBuffer returns the position for last character in the buffer for 107556-// the given file. 107557-func endRangeInBuffer(env *Env, name string) protocol.Range { 107558- buffer := env.BufferText(name) 107559- m := protocol.NewMapper("", []byte(buffer)) 107560- rng, err := m.OffsetRange(len(buffer), len(buffer)) 107561- if err != nil { 107562- env.T.Fatal(err) 107563- } 107564- return rng 107565-} 107566- 107567-// Benchmark struct completion in tools codebase. 107568-func BenchmarkStructCompletion(b *testing.B) { 107569- file := "internal/lsp/cache/session.go" 107570- 107571- setup := func(env *Env) { 107572- env.OpenFile(file) 107573- env.EditBuffer(file, protocol.TextEdit{ 107574- Range: endRangeInBuffer(env, file), 107575- NewText: "\nvar testVariable map[string]bool = Session{}.\n", 107576- }) 107577- } 107578- 107579- benchmarkCompletion(completionBenchOptions{ 107580- file: file, 107581- locationRegexp: `var testVariable map\[string\]bool = Session{}(\.)`, 107582- setup: setup, 107583- }, b) 107584-} 107585- 107586-// Benchmark import completion in tools codebase. 107587-func BenchmarkImportCompletion(b *testing.B) { 107588- const file = "internal/lsp/source/completion/completion.go" 107589- benchmarkCompletion(completionBenchOptions{ 107590- file: file, 107591- locationRegexp: `go\/()`, 107592- setup: func(env *Env) { env.OpenFile(file) }, 107593- }, b) 107594-} 107595- 107596-// Benchmark slice completion in tools codebase. 107597-func BenchmarkSliceCompletion(b *testing.B) { 107598- file := "internal/lsp/cache/session.go" 107599- 107600- setup := func(env *Env) { 107601- env.OpenFile(file) 107602- env.EditBuffer(file, protocol.TextEdit{ 107603- Range: endRangeInBuffer(env, file), 107604- NewText: "\nvar testVariable []byte = \n", 107605- }) 107606- } 107607- 107608- benchmarkCompletion(completionBenchOptions{ 107609- file: file, 107610- locationRegexp: `var testVariable \[\]byte (=)`, 107611- setup: setup, 107612- }, b) 107613-} 107614- 107615-// Benchmark deep completion in function call in tools codebase. 107616-func BenchmarkFuncDeepCompletion(b *testing.B) { 107617- file := "internal/lsp/source/completion/completion.go" 107618- fileContent := ` 107619-func (c *completer) _() { 107620- c.inference.kindMatches(c.) 107621-} 107622-` 107623- setup := func(env *Env) { 107624- env.OpenFile(file) 107625- originalBuffer := env.BufferText(file) 107626- env.EditBuffer(file, protocol.TextEdit{ 107627- Range: endRangeInBuffer(env, file), 107628- NewText: originalBuffer + fileContent, 107629- }) 107630- } 107631- 107632- benchmarkCompletion(completionBenchOptions{ 107633- file: file, 107634- locationRegexp: `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)`, 107635- setup: setup, 107636- }, b) 107637-} 107638- 107639-// Benchmark completion following an arbitrary edit. 107640-// 107641-// Edits force type-checked packages to be invalidated, so we want to measure 107642-// how long it takes before completion results are available. 107643-func BenchmarkCompletionFollowingEdit(b *testing.B) { 107644- file := "internal/lsp/source/completion/completion2.go" 107645- fileContent := ` 107646-package completion 107647- 107648-func (c *completer) _() { 107649- c.inference.kindMatches(c.) 107650- // __MAGIC_STRING_1 107651-} 107652-` 107653- setup := func(env *Env) { 107654- env.CreateBuffer(file, fileContent) 107655- } 107656- 107657- n := 1 107658- beforeCompletion := func(env *Env) { 107659- old := fmt.Sprintf("__MAGIC_STRING_%d", n) 107660- new := fmt.Sprintf("__MAGIC_STRING_%d", n+1) 107661- n++ 107662- env.RegexpReplace(file, old, new) 107663- } 107664- 107665- benchmarkCompletion(completionBenchOptions{ 107666- file: file, 107667- locationRegexp: `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)`, 107668- setup: setup, 107669- beforeCompletion: beforeCompletion, 107670- }, b) 107671-} 107672diff -urN a/gopls/internal/regtest/bench/definition_test.go b/gopls/internal/regtest/bench/definition_test.go 107673--- a/gopls/internal/regtest/bench/definition_test.go 2000-01-01 00:00:00.000000000 -0000 107674+++ b/gopls/internal/regtest/bench/definition_test.go 1970-01-01 00:00:00.000000000 +0000 107675@@ -1,39 +0,0 @@ 107676-// Copyright 2023 The Go Authors. All rights reserved. 107677-// Use of this source code is governed by a BSD-style 107678-// license that can be found in the LICENSE file. 107679- 107680-package bench 107681- 107682-import ( 107683- "testing" 107684-) 107685- 107686-func BenchmarkDefinition(b *testing.B) { 107687- tests := []struct { 107688- repo string 107689- file string 107690- regexp string 107691- }{ 107692- {"istio", "pkg/config/model.go", `gogotypes\.(MarshalAny)`}, 107693- {"kubernetes", "pkg/controller/lookup_cache.go", `hashutil\.(DeepHashObject)`}, 107694- {"kuma", "api/generic/insights.go", `proto\.(Message)`}, 107695- {"pkgsite", "internal/log/log.go", `derrors\.(Wrap)`}, 107696- {"starlark", "starlark/eval.go", "prog.compiled.(Encode)"}, 107697- {"tools", "internal/lsp/cache/check.go", `(snapshot)\) buildKey`}, 107698- } 107699- 107700- for _, test := range tests { 107701- b.Run(test.repo, func(b *testing.B) { 107702- env := getRepo(b, test.repo).sharedEnv(b) 107703- env.OpenFile(test.file) 107704- loc := env.RegexpSearch(test.file, test.regexp) 107705- env.Await(env.DoneWithOpen()) 107706- env.GoToDefinition(loc) // pre-warm the query, and open the target file 107707- b.ResetTimer() 107708- 107709- for i := 0; i < b.N; i++ { 107710- env.GoToDefinition(loc) // pre-warm the query 107711- } 107712- }) 107713- } 107714-} 107715diff -urN a/gopls/internal/regtest/bench/didchange_test.go b/gopls/internal/regtest/bench/didchange_test.go 107716--- a/gopls/internal/regtest/bench/didchange_test.go 2000-01-01 00:00:00.000000000 -0000 107717+++ b/gopls/internal/regtest/bench/didchange_test.go 1970-01-01 00:00:00.000000000 +0000 107718@@ -1,99 +0,0 @@ 107719-// Copyright 2022 The Go Authors. All rights reserved. 107720-// Use of this source code is governed by a BSD-style 107721-// license that can be found in the LICENSE file. 107722- 107723-package bench 107724- 107725-import ( 107726- "fmt" 107727- "sync/atomic" 107728- "testing" 107729- "time" 107730- 107731- "golang.org/x/tools/gopls/internal/lsp/fake" 107732- "golang.org/x/tools/gopls/internal/lsp/protocol" 107733-) 107734- 107735-// Use a global edit counter as bench function may execute multiple times, and 107736-// we want to avoid cache hits. Use time.Now to also avoid cache hits from the 107737-// shared file cache. 107738-var editID int64 = time.Now().UnixNano() 107739- 107740-var didChangeTests = []struct { 107741- repo string 107742- file string 107743-}{ 107744- {"istio", "pkg/fuzz/util.go"}, 107745- {"kubernetes", "pkg/controller/lookup_cache.go"}, 107746- {"kuma", "api/generic/insights.go"}, 107747- {"pkgsite", "internal/frontend/server.go"}, 107748- {"starlark", "starlark/eval.go"}, 107749- {"tools", "internal/lsp/cache/snapshot.go"}, 107750-} 107751- 107752-// BenchmarkDidChange benchmarks modifications of a single file by making 107753-// synthetic modifications in a comment. It controls pacing by waiting for the 107754-// server to actually start processing the didChange notification before 107755-// proceeding. Notably it does not wait for diagnostics to complete. 107756-func BenchmarkDidChange(b *testing.B) { 107757- for _, test := range didChangeTests { 107758- b.Run(test.repo, func(b *testing.B) { 107759- env := getRepo(b, test.repo).sharedEnv(b) 107760- env.OpenFile(test.file) 107761- // Insert the text we'll be modifying at the top of the file. 107762- env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"}) 107763- env.AfterChange() 107764- b.ResetTimer() 107765- 107766- for i := 0; i < b.N; i++ { 107767- edits := atomic.AddInt64(&editID, 1) 107768- env.EditBuffer(test.file, protocol.TextEdit{ 107769- Range: protocol.Range{ 107770- Start: protocol.Position{Line: 0, Character: 0}, 107771- End: protocol.Position{Line: 1, Character: 0}, 107772- }, 107773- // Increment the placeholder text, to ensure cache misses. 107774- NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits), 107775- }) 107776- env.Await(env.StartedChange()) 107777- } 107778- }) 107779- } 107780-} 107781- 107782-func BenchmarkDiagnoseChange(b *testing.B) { 107783- for _, test := range didChangeTests { 107784- b.Run(test.repo, func(b *testing.B) { 107785- // Use a new env to avoid the diagnostic delay: we want to measure how 107786- // long it takes to produce the diagnostics. 107787- env := repos[test.repo].newEnv(b, "diagnoseChange", fake.EditorConfig{ 107788- Settings: map[string]interface{}{ 107789- "diagnosticsDelay": "0s", 107790- }, 107791- }) 107792- env.OpenFile(test.file) 107793- // Insert the text we'll be modifying at the top of the file. 107794- env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"}) 107795- env.AfterChange() 107796- b.ResetTimer() 107797- 107798- // We must use an extra subtest layer here, so that we only set up the 107799- // shared env once (otherwise we pay additional overhead and the profiling 107800- // flags don't work). 107801- b.Run("diagnose", func(b *testing.B) { 107802- for i := 0; i < b.N; i++ { 107803- edits := atomic.AddInt64(&editID, 1) 107804- env.EditBuffer(test.file, protocol.TextEdit{ 107805- Range: protocol.Range{ 107806- Start: protocol.Position{Line: 0, Character: 0}, 107807- End: protocol.Position{Line: 1, Character: 0}, 107808- }, 107809- // Increment the placeholder text, to ensure cache misses. 107810- NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits), 107811- }) 107812- env.AfterChange() 107813- } 107814- }) 107815- }) 107816- } 107817-} 107818diff -urN a/gopls/internal/regtest/bench/doc.go b/gopls/internal/regtest/bench/doc.go 107819--- a/gopls/internal/regtest/bench/doc.go 2000-01-01 00:00:00.000000000 -0000 107820+++ b/gopls/internal/regtest/bench/doc.go 1970-01-01 00:00:00.000000000 +0000 107821@@ -1,33 +0,0 @@ 107822-// Copyright 2023 The Go Authors. All rights reserved. 107823-// Use of this source code is governed by a BSD-style 107824-// license that can be found in the LICENSE file. 107825- 107826-// The bench package implements benchmarks for various LSP operations. 107827-// 107828-// Benchmarks check out specific commits of popular and/or exemplary 107829-// repositories, and script an external gopls process via a fake text editor. 107830-// By default, benchmarks run the test executable as gopls (using a special 107831-// "gopls mode" environment variable). A different gopls binary may be used by 107832-// setting the -gopls_path or -gopls_commit flags. 107833-// 107834-// This package is a work in progress. 107835-// 107836-// # Profiling 107837-// 107838-// As benchmark functions run gopls in a separate process, the normal test 107839-// flags for profiling are not useful. Instead the -gopls_cpuprofile, 107840-// -gopls_memprofile, and -gopls_trace flags may be used to pass through 107841-// profiling flags to the gopls process. Each of these flags sets a suffix 107842-// for the respective gopls profiling flag, which is prefixed with a name 107843-// corresponding to the shared repository or (in some cases) benchmark name. 107844-// For example, settings -gopls_cpuprofile=cpu.out will result in profiles 107845-// named tools.cpu.out, BenchmarkInitialWorkspaceLoad.cpu.out, etc. Here, 107846-// tools.cpu.out is the cpu profile for the shared x/tools session, which may 107847-// be used by multiple benchmark functions, and BenchmarkInitialWorkspaceLoad 107848-// is the cpu profile for the last iteration of the initial workspace load 107849-// test, which starts a new editor session for each iteration. 107850-// 107851-// # TODO 107852-// - add more benchmarks, and more repositories 107853-// - improve this documentation 107854-package bench 107855diff -urN a/gopls/internal/regtest/bench/hover_test.go b/gopls/internal/regtest/bench/hover_test.go 107856--- a/gopls/internal/regtest/bench/hover_test.go 2000-01-01 00:00:00.000000000 -0000 107857+++ b/gopls/internal/regtest/bench/hover_test.go 1970-01-01 00:00:00.000000000 +0000 107858@@ -1,39 +0,0 @@ 107859-// Copyright 2023 The Go Authors. All rights reserved. 107860-// Use of this source code is governed by a BSD-style 107861-// license that can be found in the LICENSE file. 107862- 107863-package bench 107864- 107865-import ( 107866- "testing" 107867-) 107868- 107869-func BenchmarkHover(b *testing.B) { 107870- tests := []struct { 107871- repo string 107872- file string 107873- regexp string 107874- }{ 107875- {"istio", "pkg/config/model.go", `gogotypes\.(MarshalAny)`}, 107876- {"kubernetes", "pkg/apis/core/types.go", "type (Pod)"}, 107877- {"kuma", "api/generic/insights.go", `proto\.(Message)`}, 107878- {"pkgsite", "internal/log/log.go", `derrors\.(Wrap)`}, 107879- {"starlark", "starlark/eval.go", "prog.compiled.(Encode)"}, 107880- {"tools", "internal/lsp/cache/check.go", `(snapshot)\) buildKey`}, 107881- } 107882- 107883- for _, test := range tests { 107884- b.Run(test.repo, func(b *testing.B) { 107885- env := getRepo(b, test.repo).sharedEnv(b) 107886- env.OpenFile(test.file) 107887- loc := env.RegexpSearch(test.file, test.regexp) 107888- env.Await(env.DoneWithOpen()) 107889- env.Hover(loc) // pre-warm the query 107890- b.ResetTimer() 107891- 107892- for i := 0; i < b.N; i++ { 107893- env.Hover(loc) // pre-warm the query 107894- } 107895- }) 107896- } 107897-} 107898diff -urN a/gopls/internal/regtest/bench/implementations_test.go b/gopls/internal/regtest/bench/implementations_test.go 107899--- a/gopls/internal/regtest/bench/implementations_test.go 2000-01-01 00:00:00.000000000 -0000 107900+++ b/gopls/internal/regtest/bench/implementations_test.go 1970-01-01 00:00:00.000000000 +0000 107901@@ -1,37 +0,0 @@ 107902-// Copyright 2023 The Go Authors. All rights reserved. 107903-// Use of this source code is governed by a BSD-style 107904-// license that can be found in the LICENSE file. 107905- 107906-package bench 107907- 107908-import "testing" 107909- 107910-func BenchmarkImplementations(b *testing.B) { 107911- tests := []struct { 107912- repo string 107913- file string 107914- regexp string 107915- }{ 107916- {"istio", "pkg/config/mesh/watcher.go", `type (Watcher)`}, 107917- {"kubernetes", "pkg/controller/lookup_cache.go", `objectWithMeta`}, 107918- {"kuma", "api/generic/insights.go", `type (Insight)`}, 107919- {"pkgsite", "internal/datasource.go", `type (DataSource)`}, 107920- {"starlark", "syntax/syntax.go", `type (Expr)`}, 107921- {"tools", "internal/lsp/source/view.go", `type (Snapshot)`}, 107922- } 107923- 107924- for _, test := range tests { 107925- b.Run(test.repo, func(b *testing.B) { 107926- env := getRepo(b, test.repo).sharedEnv(b) 107927- env.OpenFile(test.file) 107928- loc := env.RegexpSearch(test.file, test.regexp) 107929- env.Await(env.DoneWithOpen()) 107930- env.Implementations(loc) // pre-warm the query 107931- b.ResetTimer() 107932- 107933- for i := 0; i < b.N; i++ { 107934- env.Implementations(loc) 107935- } 107936- }) 107937- } 107938-} 107939diff -urN a/gopls/internal/regtest/bench/iwl_test.go b/gopls/internal/regtest/bench/iwl_test.go 107940--- a/gopls/internal/regtest/bench/iwl_test.go 2000-01-01 00:00:00.000000000 -0000 107941+++ b/gopls/internal/regtest/bench/iwl_test.go 1970-01-01 00:00:00.000000000 +0000 107942@@ -1,77 +0,0 @@ 107943-// Copyright 2022 The Go Authors. All rights reserved. 107944-// Use of this source code is governed by a BSD-style 107945-// license that can be found in the LICENSE file. 107946- 107947-package bench 107948- 107949-import ( 107950- "testing" 107951- 107952- "golang.org/x/tools/gopls/internal/lsp/command" 107953- "golang.org/x/tools/gopls/internal/lsp/fake" 107954- "golang.org/x/tools/gopls/internal/lsp/protocol" 107955- . "golang.org/x/tools/gopls/internal/lsp/regtest" 107956-) 107957- 107958-// BenchmarkInitialWorkspaceLoad benchmarks the initial workspace load time for 107959-// a new editing session. 107960-func BenchmarkInitialWorkspaceLoad(b *testing.B) { 107961- if testing.Short() { 107962- // TODO(rfindley): remove this skip once the released gopls version 107963- // supports the memstats command. 107964- b.Skip("temporarily skipping as baseline gopls versions do not support the memstats command") 107965- } 107966- tests := []struct { 107967- repo string 107968- file string 107969- }{ 107970- {"tools", "internal/lsp/cache/snapshot.go"}, 107971- {"kubernetes", "pkg/controller/lookup_cache.go"}, 107972- {"pkgsite", "internal/frontend/server.go"}, 107973- {"starlark", "starlark/eval.go"}, 107974- {"istio", "pkg/fuzz/util.go"}, 107975- {"kuma", "api/generic/insights.go"}, 107976- } 107977- 107978- for _, test := range tests { 107979- b.Run(test.repo, func(b *testing.B) { 107980- repo := getRepo(b, test.repo) 107981- // get the (initialized) shared env to ensure the cache is warm. 107982- // Reuse its GOPATH so that we get cache hits for things in the module 107983- // cache. 107984- sharedEnv := repo.sharedEnv(b) 107985- b.ResetTimer() 107986- 107987- for i := 0; i < b.N; i++ { 107988- doIWL(b, sharedEnv.Sandbox.GOPATH(), repo, test.file) 107989- } 107990- }) 107991- } 107992-} 107993- 107994-func doIWL(b *testing.B, gopath string, repo *repo, file string) { 107995- // Exclude the time to set up the env from the benchmark time, as this may 107996- // involve installing gopls and/or checking out the repo dir. 107997- b.StopTimer() 107998- config := fake.EditorConfig{Env: map[string]string{"GOPATH": gopath}} 107999- env := repo.newEnv(b, "iwl."+repo.name, config) 108000- defer env.Close() 108001- b.StartTimer() 108002- 108003- // Open an arbitrary file to ensure that gopls starts working. 108004- // 108005- // In the future, this may matter if gopls doesn't eagerly construct 108006- // the workspace. 108007- env.OpenFile(file) 108008- 108009- env.Await(InitialWorkspaceLoad) 108010- b.StopTimer() 108011- params := &protocol.ExecuteCommandParams{ 108012- Command: command.MemStats.ID(), 108013- } 108014- var memstats command.MemStatsResult 108015- env.ExecuteCommand(params, &memstats) 108016- b.ReportMetric(float64(memstats.HeapAlloc), "alloc_bytes") 108017- b.ReportMetric(float64(memstats.HeapInUse), "in_use_bytes") 108018- b.StartTimer() 108019-} 108020diff -urN a/gopls/internal/regtest/bench/references_test.go b/gopls/internal/regtest/bench/references_test.go 108021--- a/gopls/internal/regtest/bench/references_test.go 2000-01-01 00:00:00.000000000 -0000 108022+++ b/gopls/internal/regtest/bench/references_test.go 1970-01-01 00:00:00.000000000 +0000 108023@@ -1,37 +0,0 @@ 108024-// Copyright 2023 The Go Authors. All rights reserved. 108025-// Use of this source code is governed by a BSD-style 108026-// license that can be found in the LICENSE file. 108027- 108028-package bench 108029- 108030-import "testing" 108031- 108032-func BenchmarkReferences(b *testing.B) { 108033- tests := []struct { 108034- repo string 108035- file string 108036- regexp string 108037- }{ 108038- {"istio", "pkg/config/model.go", "type (Meta)"}, 108039- {"kubernetes", "pkg/controller/lookup_cache.go", "type (objectWithMeta)"}, 108040- {"kuma", "pkg/events/interfaces.go", "type (Event)"}, 108041- {"pkgsite", "internal/log/log.go", "func (Infof)"}, 108042- {"starlark", "syntax/syntax.go", "type (Ident)"}, 108043- {"tools", "internal/lsp/source/view.go", "type (Snapshot)"}, 108044- } 108045- 108046- for _, test := range tests { 108047- b.Run(test.repo, func(b *testing.B) { 108048- env := getRepo(b, test.repo).sharedEnv(b) 108049- env.OpenFile(test.file) 108050- loc := env.RegexpSearch(test.file, test.regexp) 108051- env.Await(env.DoneWithOpen()) 108052- env.References(loc) // pre-warm the query 108053- b.ResetTimer() 108054- 108055- for i := 0; i < b.N; i++ { 108056- env.References(loc) 108057- } 108058- }) 108059- } 108060-} 108061diff -urN a/gopls/internal/regtest/bench/rename_test.go b/gopls/internal/regtest/bench/rename_test.go 108062--- a/gopls/internal/regtest/bench/rename_test.go 2000-01-01 00:00:00.000000000 -0000 108063+++ b/gopls/internal/regtest/bench/rename_test.go 1970-01-01 00:00:00.000000000 +0000 108064@@ -1,44 +0,0 @@ 108065-// Copyright 2023 The Go Authors. All rights reserved. 108066-// Use of this source code is governed by a BSD-style 108067-// license that can be found in the LICENSE file. 108068- 108069-package bench 108070- 108071-import ( 108072- "fmt" 108073- "testing" 108074-) 108075- 108076-func BenchmarkRename(b *testing.B) { 108077- tests := []struct { 108078- repo string 108079- file string 108080- regexp string 108081- baseName string 108082- }{ 108083- {"kubernetes", "pkg/controller/lookup_cache.go", `hashutil\.(DeepHashObject)`, "DeepHashObject"}, 108084- {"kuma", "pkg/events/interfaces.go", `Delete`, "Delete"}, 108085- {"istio", "pkg/config/model.go", `(Namespace) string`, "Namespace"}, 108086- {"pkgsite", "internal/log/log.go", `func (Infof)`, "Infof"}, 108087- {"starlark", "starlark/eval.go", `Program\) (Filename)`, "Filename"}, 108088- {"tools", "internal/lsp/cache/snapshot.go", `meta \*(metadataGraph)`, "metadataGraph"}, 108089- } 108090- 108091- for _, test := range tests { 108092- names := 0 // bench function may execute multiple times 108093- b.Run(test.repo, func(b *testing.B) { 108094- env := getRepo(b, test.repo).sharedEnv(b) 108095- env.OpenFile(test.file) 108096- loc := env.RegexpSearch(test.file, test.regexp) 108097- env.Await(env.DoneWithOpen()) 108098- env.Rename(loc, test.baseName+"X") // pre-warm the query 108099- b.ResetTimer() 108100- 108101- for i := 0; i < b.N; i++ { 108102- names++ 108103- newName := fmt.Sprintf("%s%d", test.baseName, names) 108104- env.Rename(loc, newName) 108105- } 108106- }) 108107- } 108108-} 108109diff -urN a/gopls/internal/regtest/bench/repo_test.go b/gopls/internal/regtest/bench/repo_test.go 108110--- a/gopls/internal/regtest/bench/repo_test.go 2000-01-01 00:00:00.000000000 -0000 108111+++ b/gopls/internal/regtest/bench/repo_test.go 1970-01-01 00:00:00.000000000 +0000 108112@@ -1,231 +0,0 @@ 108113-// Copyright 2023 The Go Authors. All rights reserved. 108114-// Use of this source code is governed by a BSD-style 108115-// license that can be found in the LICENSE file. 108116- 108117-package bench 108118- 108119-import ( 108120- "bytes" 108121- "context" 108122- "errors" 108123- "fmt" 108124- "log" 108125- "os" 108126- "path/filepath" 108127- "sync" 108128- "testing" 108129- "time" 108130- 108131- "golang.org/x/tools/gopls/internal/lsp/fake" 108132- . "golang.org/x/tools/gopls/internal/lsp/regtest" 108133-) 108134- 108135-// repos holds shared repositories for use in benchmarks. 108136-// 108137-// These repos were selected to represent a variety of different types of 108138-// codebases. 108139-var repos = map[string]*repo{ 108140- // Used by x/benchmarks; large. 108141- "istio": { 108142- name: "istio", 108143- url: "https://github.com/istio/istio", 108144- commit: "1.17.0", 108145- }, 108146- 108147- // Kubernetes is a large repo with many dependencies, and in the past has 108148- // been about as large a repo as gopls could handle. 108149- "kubernetes": { 108150- name: "kubernetes", 108151- url: "https://github.com/kubernetes/kubernetes", 108152- commit: "v1.24.0", 108153- }, 108154- 108155- // A large, industrial application. 108156- "kuma": { 108157- name: "kuma", 108158- url: "https://github.com/kumahq/kuma", 108159- commit: "2.1.1", 108160- }, 108161- 108162- // x/pkgsite is familiar and represents a common use case (a webserver). It 108163- // also has a number of static non-go files and template files. 108164- "pkgsite": { 108165- name: "pkgsite", 108166- url: "https://go.googlesource.com/pkgsite", 108167- commit: "81f6f8d4175ad0bf6feaa03543cc433f8b04b19b", 108168- short: true, 108169- }, 108170- 108171- // A tiny self-contained project. 108172- "starlark": { 108173- name: "starlark", 108174- url: "https://github.com/google/starlark-go", 108175- commit: "3f75dec8e4039385901a30981e3703470d77e027", 108176- short: true, 108177- }, 108178- 108179- // The current repository, which is medium-small and has very few dependencies. 108180- "tools": { 108181- name: "tools", 108182- url: "https://go.googlesource.com/tools", 108183- commit: "gopls/v0.9.0", 108184- short: true, 108185- }, 108186-} 108187- 108188-// getRepo gets the requested repo, and skips the test if -short is set and 108189-// repo is not configured as a short repo. 108190-func getRepo(tb testing.TB, name string) *repo { 108191- tb.Helper() 108192- repo := repos[name] 108193- if repo == nil { 108194- tb.Fatalf("repo %s does not exist", name) 108195- } 108196- if !repo.short && testing.Short() { 108197- tb.Skipf("large repo %s does not run whith -short", repo.name) 108198- } 108199- return repo 108200-} 108201- 108202-// A repo represents a working directory for a repository checked out at a 108203-// specific commit. 108204-// 108205-// Repos are used for sharing state across benchmarks that operate on the same 108206-// codebase. 108207-type repo struct { 108208- // static configuration 108209- name string // must be unique, used for subdirectory 108210- url string // repo url 108211- commit string // full commit hash or tag 108212- short bool // whether this repo runs with -short 108213- 108214- dirOnce sync.Once 108215- dir string // directory contaning source code checked out to url@commit 108216- 108217- // shared editor state 108218- editorOnce sync.Once 108219- editor *fake.Editor 108220- sandbox *fake.Sandbox 108221- awaiter *Awaiter 108222-} 108223- 108224-// getDir returns directory containing repo source code, creating it if 108225-// necessary. It is safe for concurrent use. 108226-func (r *repo) getDir() string { 108227- r.dirOnce.Do(func() { 108228- r.dir = filepath.Join(getTempDir(), r.name) 108229- log.Printf("cloning %s@%s into %s", r.url, r.commit, r.dir) 108230- if err := shallowClone(r.dir, r.url, r.commit); err != nil { 108231- log.Fatal(err) 108232- } 108233- }) 108234- return r.dir 108235-} 108236- 108237-// sharedEnv returns a shared benchmark environment. It is safe for concurrent 108238-// use. 108239-// 108240-// Every call to sharedEnv uses the same editor and sandbox, as a means to 108241-// avoid reinitializing the editor for large repos. Calling repo.Close cleans 108242-// up the shared environment. 108243-// 108244-// Repos in the package-local Repos var are closed at the end of the test main 108245-// function. 108246-func (r *repo) sharedEnv(tb testing.TB) *Env { 108247- r.editorOnce.Do(func() { 108248- dir := r.getDir() 108249- 108250- start := time.Now() 108251- log.Printf("starting initial workspace load for %s", r.name) 108252- ts, err := newGoplsServer(r.name) 108253- if err != nil { 108254- log.Fatal(err) 108255- } 108256- r.sandbox, r.editor, r.awaiter, err = connectEditor(dir, fake.EditorConfig{}, ts) 108257- if err != nil { 108258- log.Fatalf("connecting editor: %v", err) 108259- } 108260- 108261- if err := r.awaiter.Await(context.Background(), InitialWorkspaceLoad); err != nil { 108262- log.Fatal(err) 108263- } 108264- log.Printf("initial workspace load (cold) for %s took %v", r.name, time.Since(start)) 108265- }) 108266- 108267- return &Env{ 108268- T: tb, 108269- Ctx: context.Background(), 108270- Editor: r.editor, 108271- Sandbox: r.sandbox, 108272- Awaiter: r.awaiter, 108273- } 108274-} 108275- 108276-// newEnv returns a new Env connected to a new gopls process communicating 108277-// over stdin/stdout. It is safe for concurrent use. 108278-// 108279-// It is the caller's responsibility to call Close on the resulting Env when it 108280-// is no longer needed. 108281-func (r *repo) newEnv(tb testing.TB, name string, config fake.EditorConfig) *Env { 108282- dir := r.getDir() 108283- 108284- ts, err := newGoplsServer(name) 108285- if err != nil { 108286- tb.Fatal(err) 108287- } 108288- sandbox, editor, awaiter, err := connectEditor(dir, config, ts) 108289- if err != nil { 108290- log.Fatalf("connecting editor: %v", err) 108291- } 108292- 108293- return &Env{ 108294- T: tb, 108295- Ctx: context.Background(), 108296- Editor: editor, 108297- Sandbox: sandbox, 108298- Awaiter: awaiter, 108299- } 108300-} 108301- 108302-// Close cleans up shared state referenced by the repo. 108303-func (r *repo) Close() error { 108304- var errBuf bytes.Buffer 108305- if r.editor != nil { 108306- if err := r.editor.Close(context.Background()); err != nil { 108307- fmt.Fprintf(&errBuf, "closing editor: %v", err) 108308- } 108309- } 108310- if r.sandbox != nil { 108311- if err := r.sandbox.Close(); err != nil { 108312- fmt.Fprintf(&errBuf, "closing sandbox: %v", err) 108313- } 108314- } 108315- if r.dir != "" { 108316- if err := os.RemoveAll(r.dir); err != nil { 108317- fmt.Fprintf(&errBuf, "cleaning dir: %v", err) 108318- } 108319- } 108320- if errBuf.Len() > 0 { 108321- return errors.New(errBuf.String()) 108322- } 108323- return nil 108324-} 108325- 108326-// cleanup cleans up state that is shared across benchmark functions. 108327-func cleanup() error { 108328- var errBuf bytes.Buffer 108329- for _, repo := range repos { 108330- if err := repo.Close(); err != nil { 108331- fmt.Fprintf(&errBuf, "closing %q: %v", repo.name, err) 108332- } 108333- } 108334- if tempDir != "" { 108335- if err := os.RemoveAll(tempDir); err != nil { 108336- fmt.Fprintf(&errBuf, "cleaning tempDir: %v", err) 108337- } 108338- } 108339- if errBuf.Len() > 0 { 108340- return errors.New(errBuf.String()) 108341- } 108342- return nil 108343-} 108344diff -urN a/gopls/internal/regtest/bench/stress_test.go b/gopls/internal/regtest/bench/stress_test.go 108345--- a/gopls/internal/regtest/bench/stress_test.go 2000-01-01 00:00:00.000000000 -0000 108346+++ b/gopls/internal/regtest/bench/stress_test.go 1970-01-01 00:00:00.000000000 +0000 108347@@ -1,94 +0,0 @@ 108348-// Copyright 2020 The Go Authors. All rights reserved. 108349-// Use of this source code is governed by a BSD-style 108350-// license that can be found in the LICENSE file. 108351- 108352-package bench 108353- 108354-import ( 108355- "context" 108356- "flag" 108357- "fmt" 108358- "testing" 108359- "time" 108360- 108361- "golang.org/x/tools/gopls/internal/hooks" 108362- "golang.org/x/tools/gopls/internal/lsp/cache" 108363- "golang.org/x/tools/gopls/internal/lsp/fake" 108364- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 108365- "golang.org/x/tools/internal/jsonrpc2" 108366- "golang.org/x/tools/internal/jsonrpc2/servertest" 108367-) 108368- 108369-// github.com/pilosa/pilosa is a repository that has historically caused 108370-// significant memory problems for Gopls. We use it for a simple stress test 108371-// that types arbitrarily in a file with lots of dependents. 108372- 108373-var pilosaPath = flag.String("pilosa_path", "", "Path to a directory containing "+ 108374- "github.com/pilosa/pilosa, for stress testing. Do not set this unless you "+ 108375- "know what you're doing!") 108376- 108377-func TestPilosaStress(t *testing.T) { 108378- // TODO(rfindley): revisit this test and make it is hermetic: it should check 108379- // out pilosa into a directory. 108380- // 108381- // Note: This stress test has not been run recently, and may no longer 108382- // function properly. 108383- if *pilosaPath == "" { 108384- t.Skip("-pilosa_path not configured") 108385- } 108386- 108387- sandbox, err := fake.NewSandbox(&fake.SandboxConfig{ 108388- Workdir: *pilosaPath, 108389- GOPROXY: "https://proxy.golang.org", 108390- }) 108391- if err != nil { 108392- t.Fatal(err) 108393- } 108394- 108395- server := lsprpc.NewStreamServer(cache.New(nil), false, hooks.Options) 108396- ts := servertest.NewPipeServer(server, jsonrpc2.NewRawStream) 108397- ctx := context.Background() 108398- 108399- const skipApplyEdits = false 108400- editor, err := fake.NewEditor(sandbox, fake.EditorConfig{}).Connect(ctx, ts, fake.ClientHooks{}, skipApplyEdits) 108401- if err != nil { 108402- t.Fatal(err) 108403- } 108404- 108405- files := []string{ 108406- "cmd.go", 108407- "internal/private.pb.go", 108408- "roaring/roaring.go", 108409- "roaring/roaring_internal_test.go", 108410- "server/handler_test.go", 108411- } 108412- for _, file := range files { 108413- if err := editor.OpenFile(ctx, file); err != nil { 108414- t.Fatal(err) 108415- } 108416- } 108417- ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) 108418- defer cancel() 108419- 108420- i := 1 108421- // MagicNumber is an identifier that occurs in roaring.go. Just change it 108422- // arbitrarily. 108423- if err := editor.RegexpReplace(ctx, "roaring/roaring.go", "MagicNumber", fmt.Sprintf("MagicNumber%d", 1)); err != nil { 108424- t.Fatal(err) 108425- } 108426- for { 108427- select { 108428- case <-ctx.Done(): 108429- return 108430- default: 108431- } 108432- if err := editor.RegexpReplace(ctx, "roaring/roaring.go", fmt.Sprintf("MagicNumber%d", i), fmt.Sprintf("MagicNumber%d", i+1)); err != nil { 108433- t.Fatal(err) 108434- } 108435- // Simulate (very fast) typing. 108436- // 108437- // Typing 80 wpm ~150ms per keystroke. 108438- time.Sleep(150 * time.Millisecond) 108439- i++ 108440- } 108441-} 108442diff -urN a/gopls/internal/regtest/bench/workspace_symbols_test.go b/gopls/internal/regtest/bench/workspace_symbols_test.go 108443--- a/gopls/internal/regtest/bench/workspace_symbols_test.go 2000-01-01 00:00:00.000000000 -0000 108444+++ b/gopls/internal/regtest/bench/workspace_symbols_test.go 1970-01-01 00:00:00.000000000 +0000 108445@@ -1,37 +0,0 @@ 108446-// Copyright 2022 The Go Authors. All rights reserved. 108447-// Use of this source code is governed by a BSD-style 108448-// license that can be found in the LICENSE file. 108449- 108450-package bench 108451- 108452-import ( 108453- "flag" 108454- "fmt" 108455- "testing" 108456-) 108457- 108458-var symbolQuery = flag.String("symbol_query", "test", "symbol query to use in benchmark") 108459- 108460-// BenchmarkWorkspaceSymbols benchmarks the time to execute a workspace symbols 108461-// request (controlled by the -symbol_query flag). 108462-func BenchmarkWorkspaceSymbols(b *testing.B) { 108463- for name := range repos { 108464- b.Run(name, func(b *testing.B) { 108465- env := getRepo(b, name).sharedEnv(b) 108466- symbols := env.Symbol(*symbolQuery) // warm the cache 108467- 108468- if testing.Verbose() { 108469- fmt.Println("Results:") 108470- for i, symbol := range symbols { 108471- fmt.Printf("\t%d. %s (%s)\n", i, symbol.Name, symbol.ContainerName) 108472- } 108473- } 108474- 108475- b.ResetTimer() 108476- 108477- for i := 0; i < b.N; i++ { 108478- env.Symbol(*symbolQuery) 108479- } 108480- }) 108481- } 108482-} 108483diff -urN a/gopls/internal/regtest/codelens/codelens_test.go b/gopls/internal/regtest/codelens/codelens_test.go 108484--- a/gopls/internal/regtest/codelens/codelens_test.go 2000-01-01 00:00:00.000000000 -0000 108485+++ b/gopls/internal/regtest/codelens/codelens_test.go 1970-01-01 00:00:00.000000000 +0000 108486@@ -1,336 +0,0 @@ 108487-// Copyright 2020 The Go Authors. All rights reserved. 108488-// Use of this source code is governed by a BSD-style 108489-// license that can be found in the LICENSE file. 108490- 108491-package codelens 108492- 108493-import ( 108494- "fmt" 108495- "testing" 108496- 108497- "golang.org/x/tools/gopls/internal/hooks" 108498- . "golang.org/x/tools/gopls/internal/lsp/regtest" 108499- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 108500- "golang.org/x/tools/internal/bug" 108501- 108502- "golang.org/x/tools/gopls/internal/lsp/command" 108503- "golang.org/x/tools/gopls/internal/lsp/protocol" 108504- "golang.org/x/tools/internal/testenv" 108505-) 108506- 108507-func TestMain(m *testing.M) { 108508- bug.PanicOnBugs = true 108509- Main(m, hooks.Options) 108510-} 108511- 108512-func TestDisablingCodeLens(t *testing.T) { 108513- const workspace = ` 108514--- go.mod -- 108515-module codelens.test 108516- 108517-go 1.12 108518--- lib.go -- 108519-package lib 108520- 108521-type Number int 108522- 108523-const ( 108524- Zero Number = iota 108525- One 108526- Two 108527-) 108528- 108529-//` + `go:generate stringer -type=Number 108530-` 108531- tests := []struct { 108532- label string 108533- enabled map[string]bool 108534- wantCodeLens bool 108535- }{ 108536- { 108537- label: "default", 108538- wantCodeLens: true, 108539- }, 108540- { 108541- label: "generate disabled", 108542- enabled: map[string]bool{string(command.Generate): false}, 108543- wantCodeLens: false, 108544- }, 108545- } 108546- for _, test := range tests { 108547- t.Run(test.label, func(t *testing.T) { 108548- WithOptions( 108549- Settings{"codelenses": test.enabled}, 108550- ).Run(t, workspace, func(t *testing.T, env *Env) { 108551- env.OpenFile("lib.go") 108552- lens := env.CodeLens("lib.go") 108553- if gotCodeLens := len(lens) > 0; gotCodeLens != test.wantCodeLens { 108554- t.Errorf("got codeLens: %t, want %t", gotCodeLens, test.wantCodeLens) 108555- } 108556- }) 108557- }) 108558- } 108559-} 108560- 108561-// This test confirms the full functionality of the code lenses for updating 108562-// dependencies in a go.mod file. It checks for the code lens that suggests 108563-// an update and then executes the command associated with that code lens. A 108564-// regression test for golang/go#39446. It also checks that these code lenses 108565-// only affect the diagnostics and contents of the containing go.mod file. 108566-func TestUpgradeCodelens(t *testing.T) { 108567- testenv.NeedsGo1Point(t, 18) // uses go.work 108568- 108569- const proxyWithLatest = ` 108570--- golang.org/x/hello@v1.3.3/go.mod -- 108571-module golang.org/x/hello 108572- 108573-go 1.12 108574--- golang.org/x/hello@v1.3.3/hi/hi.go -- 108575-package hi 108576- 108577-var Goodbye error 108578--- golang.org/x/hello@v1.2.3/go.mod -- 108579-module golang.org/x/hello 108580- 108581-go 1.12 108582--- golang.org/x/hello@v1.2.3/hi/hi.go -- 108583-package hi 108584- 108585-var Goodbye error 108586-` 108587- 108588- const shouldUpdateDep = ` 108589--- go.work -- 108590-go 1.18 108591- 108592-use ( 108593- ./a 108594- ./b 108595-) 108596--- a/go.mod -- 108597-module mod.com/a 108598- 108599-go 1.14 108600- 108601-require golang.org/x/hello v1.2.3 108602--- a/go.sum -- 108603-golang.org/x/hello v1.2.3 h1:7Wesfkx/uBd+eFgPrq0irYj/1XfmbvLV8jZ/W7C2Dwg= 108604-golang.org/x/hello v1.2.3/go.mod h1:OgtlzsxVMUUdsdQCIDYgaauCTH47B8T8vofouNJfzgY= 108605--- a/main.go -- 108606-package main 108607- 108608-import "golang.org/x/hello/hi" 108609- 108610-func main() { 108611- _ = hi.Goodbye 108612-} 108613--- b/go.mod -- 108614-module mod.com/b 108615- 108616-go 1.14 108617- 108618-require golang.org/x/hello v1.2.3 108619--- b/go.sum -- 108620-golang.org/x/hello v1.2.3 h1:7Wesfkx/uBd+eFgPrq0irYj/1XfmbvLV8jZ/W7C2Dwg= 108621-golang.org/x/hello v1.2.3/go.mod h1:OgtlzsxVMUUdsdQCIDYgaauCTH47B8T8vofouNJfzgY= 108622--- b/main.go -- 108623-package main 108624- 108625-import ( 108626- "golang.org/x/hello/hi" 108627-) 108628- 108629-func main() { 108630- _ = hi.Goodbye 108631-} 108632-` 108633- 108634- const wantGoModA = `module mod.com/a 108635- 108636-go 1.14 108637- 108638-require golang.org/x/hello v1.3.3 108639-` 108640- // Applying the diagnostics or running the codelenses for a/go.mod 108641- // should not change the contents of b/go.mod 108642- const wantGoModB = `module mod.com/b 108643- 108644-go 1.14 108645- 108646-require golang.org/x/hello v1.2.3 108647-` 108648- 108649- for _, commandTitle := range []string{ 108650- "Upgrade transitive dependencies", 108651- "Upgrade direct dependencies", 108652- } { 108653- t.Run(commandTitle, func(t *testing.T) { 108654- WithOptions( 108655- ProxyFiles(proxyWithLatest), 108656- ).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) { 108657- env.OpenFile("a/go.mod") 108658- env.OpenFile("b/go.mod") 108659- var lens protocol.CodeLens 108660- var found bool 108661- for _, l := range env.CodeLens("a/go.mod") { 108662- if l.Command.Title == commandTitle { 108663- lens = l 108664- found = true 108665- } 108666- } 108667- if !found { 108668- t.Fatalf("found no command with the title %s", commandTitle) 108669- } 108670- if _, err := env.Editor.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{ 108671- Command: lens.Command.Command, 108672- Arguments: lens.Command.Arguments, 108673- }); err != nil { 108674- t.Fatal(err) 108675- } 108676- env.AfterChange() 108677- if got := env.BufferText("a/go.mod"); got != wantGoModA { 108678- t.Fatalf("a/go.mod upgrade failed:\n%s", compare.Text(wantGoModA, got)) 108679- } 108680- if got := env.BufferText("b/go.mod"); got != wantGoModB { 108681- t.Fatalf("b/go.mod changed unexpectedly:\n%s", compare.Text(wantGoModB, got)) 108682- } 108683- }) 108684- }) 108685- } 108686- for _, vendoring := range []bool{false, true} { 108687- t.Run(fmt.Sprintf("Upgrade individual dependency vendoring=%v", vendoring), func(t *testing.T) { 108688- WithOptions(ProxyFiles(proxyWithLatest)).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) { 108689- if vendoring { 108690- env.RunGoCommandInDir("a", "mod", "vendor") 108691- } 108692- env.AfterChange() 108693- env.OpenFile("a/go.mod") 108694- env.OpenFile("b/go.mod") 108695- env.ExecuteCodeLensCommand("a/go.mod", command.CheckUpgrades, nil) 108696- d := &protocol.PublishDiagnosticsParams{} 108697- env.OnceMet( 108698- Diagnostics(env.AtRegexp("a/go.mod", `require`), WithMessage("can be upgraded")), 108699- ReadDiagnostics("a/go.mod", d), 108700- // We do not want there to be a diagnostic for b/go.mod, 108701- // but there may be some subtlety in timing here, where this 108702- // should always succeed, but may not actually test the correct 108703- // behavior. 108704- NoDiagnostics(env.AtRegexp("b/go.mod", `require`)), 108705- ) 108706- // Check for upgrades in b/go.mod and then clear them. 108707- env.ExecuteCodeLensCommand("b/go.mod", command.CheckUpgrades, nil) 108708- env.Await(Diagnostics(env.AtRegexp("b/go.mod", `require`), WithMessage("can be upgraded"))) 108709- env.ExecuteCodeLensCommand("b/go.mod", command.ResetGoModDiagnostics, nil) 108710- env.Await(NoDiagnostics(ForFile("b/go.mod"))) 108711- 108712- // Apply the diagnostics to a/go.mod. 108713- env.ApplyQuickFixes("a/go.mod", d.Diagnostics) 108714- env.AfterChange() 108715- if got := env.BufferText("a/go.mod"); got != wantGoModA { 108716- t.Fatalf("a/go.mod upgrade failed:\n%s", compare.Text(wantGoModA, got)) 108717- } 108718- if got := env.BufferText("b/go.mod"); got != wantGoModB { 108719- t.Fatalf("b/go.mod changed unexpectedly:\n%s", compare.Text(wantGoModB, got)) 108720- } 108721- }) 108722- }) 108723- } 108724-} 108725- 108726-func TestUnusedDependenciesCodelens(t *testing.T) { 108727- const proxy = ` 108728--- golang.org/x/hello@v1.0.0/go.mod -- 108729-module golang.org/x/hello 108730- 108731-go 1.14 108732--- golang.org/x/hello@v1.0.0/hi/hi.go -- 108733-package hi 108734- 108735-var Goodbye error 108736--- golang.org/x/unused@v1.0.0/go.mod -- 108737-module golang.org/x/unused 108738- 108739-go 1.14 108740--- golang.org/x/unused@v1.0.0/nouse/nouse.go -- 108741-package nouse 108742- 108743-var NotUsed error 108744-` 108745- 108746- const shouldRemoveDep = ` 108747--- go.mod -- 108748-module mod.com 108749- 108750-go 1.14 108751- 108752-require golang.org/x/hello v1.0.0 108753-require golang.org/x/unused v1.0.0 108754--- go.sum -- 108755-golang.org/x/hello v1.0.0 h1:qbzE1/qT0/zojAMd/JcPsO2Vb9K4Bkeyq0vB2JGMmsw= 108756-golang.org/x/hello v1.0.0/go.mod h1:WW7ER2MRNXWA6c8/4bDIek4Hc/+DofTrMaQQitGXcco= 108757-golang.org/x/unused v1.0.0 h1:LecSbCn5P3vTcxubungSt1Pn4D/WocCaiWOPDC0y0rw= 108758-golang.org/x/unused v1.0.0/go.mod h1:ihoW8SgWzugwwj0N2SfLfPZCxTB1QOVfhMfB5PWTQ8U= 108759--- main.go -- 108760-package main 108761- 108762-import "golang.org/x/hello/hi" 108763- 108764-func main() { 108765- _ = hi.Goodbye 108766-} 108767-` 108768- WithOptions(ProxyFiles(proxy)).Run(t, shouldRemoveDep, func(t *testing.T, env *Env) { 108769- env.OpenFile("go.mod") 108770- env.ExecuteCodeLensCommand("go.mod", command.Tidy, nil) 108771- env.Await(env.DoneWithChangeWatchedFiles()) 108772- got := env.BufferText("go.mod") 108773- const wantGoMod = `module mod.com 108774- 108775-go 1.14 108776- 108777-require golang.org/x/hello v1.0.0 108778-` 108779- if got != wantGoMod { 108780- t.Fatalf("go.mod tidy failed:\n%s", compare.Text(wantGoMod, got)) 108781- } 108782- }) 108783-} 108784- 108785-func TestRegenerateCgo(t *testing.T) { 108786- testenv.NeedsTool(t, "cgo") 108787- const workspace = ` 108788--- go.mod -- 108789-module example.com 108790- 108791-go 1.12 108792--- cgo.go -- 108793-package x 108794- 108795-/* 108796-int fortythree() { return 42; } 108797-*/ 108798-import "C" 108799- 108800-func Foo() { 108801- print(C.fortytwo()) 108802-} 108803-` 108804- Run(t, workspace, func(t *testing.T, env *Env) { 108805- // Open the file. We have a nonexistant symbol that will break cgo processing. 108806- env.OpenFile("cgo.go") 108807- env.AfterChange( 108808- Diagnostics(env.AtRegexp("cgo.go", ``), WithMessage("go list failed to return CompiledGoFiles")), 108809- ) 108810- 108811- // Fix the C function name. We haven't regenerated cgo, so nothing should be fixed. 108812- env.RegexpReplace("cgo.go", `int fortythree`, "int fortytwo") 108813- env.SaveBuffer("cgo.go") 108814- env.AfterChange( 108815- Diagnostics(env.AtRegexp("cgo.go", ``), WithMessage("go list failed to return CompiledGoFiles")), 108816- ) 108817- 108818- // Regenerate cgo, fixing the diagnostic. 108819- env.ExecuteCodeLensCommand("cgo.go", command.RegenerateCgo, nil) 108820- env.Await(NoDiagnostics(ForFile("cgo.go"))) 108821- }) 108822-} 108823diff -urN a/gopls/internal/regtest/codelens/gcdetails_test.go b/gopls/internal/regtest/codelens/gcdetails_test.go 108824--- a/gopls/internal/regtest/codelens/gcdetails_test.go 2000-01-01 00:00:00.000000000 -0000 108825+++ b/gopls/internal/regtest/codelens/gcdetails_test.go 1970-01-01 00:00:00.000000000 +0000 108826@@ -1,127 +0,0 @@ 108827-// Copyright 2020 The Go Authors. All rights reserved. 108828-// Use of this source code is governed by a BSD-style 108829-// license that can be found in the LICENSE file. 108830- 108831-package codelens 108832- 108833-import ( 108834- "runtime" 108835- "strings" 108836- "testing" 108837- 108838- "golang.org/x/tools/gopls/internal/lsp/command" 108839- "golang.org/x/tools/gopls/internal/lsp/fake" 108840- "golang.org/x/tools/gopls/internal/lsp/protocol" 108841- . "golang.org/x/tools/gopls/internal/lsp/regtest" 108842- "golang.org/x/tools/internal/bug" 108843-) 108844- 108845-func TestGCDetails_Toggle(t *testing.T) { 108846- if runtime.GOOS == "android" { 108847- t.Skipf("the gc details code lens doesn't work on Android") 108848- } 108849- 108850- const mod = ` 108851--- go.mod -- 108852-module mod.com 108853- 108854-go 1.15 108855--- main.go -- 108856-package main 108857- 108858-import "fmt" 108859- 108860-func main() { 108861- fmt.Println(42) 108862-} 108863-` 108864- WithOptions( 108865- Settings{ 108866- "codelenses": map[string]bool{ 108867- "gc_details": true, 108868- }, 108869- }, 108870- ).Run(t, mod, func(t *testing.T, env *Env) { 108871- env.OpenFile("main.go") 108872- env.ExecuteCodeLensCommand("main.go", command.GCDetails, nil) 108873- d := &protocol.PublishDiagnosticsParams{} 108874- env.OnceMet( 108875- Diagnostics(AtPosition("main.go", 5, 13)), 108876- ReadDiagnostics("main.go", d), 108877- ) 108878- // Confirm that the diagnostics come from the gc details code lens. 108879- var found bool 108880- for _, d := range d.Diagnostics { 108881- if d.Severity != protocol.SeverityInformation { 108882- t.Fatalf("unexpected diagnostic severity %v, wanted Information", d.Severity) 108883- } 108884- if strings.Contains(d.Message, "42 escapes") { 108885- found = true 108886- } 108887- } 108888- if !found { 108889- t.Fatalf(`expected to find diagnostic with message "escape(42 escapes to heap)", found none`) 108890- } 108891- 108892- // Editing a buffer should cause gc_details diagnostics to disappear, since 108893- // they only apply to saved buffers. 108894- env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, "\n\n")) 108895- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 108896- 108897- // Saving a buffer should re-format back to the original state, and 108898- // re-enable the gc_details diagnostics. 108899- env.SaveBuffer("main.go") 108900- env.AfterChange(Diagnostics(AtPosition("main.go", 5, 13))) 108901- 108902- // Toggle the GC details code lens again so now it should be off. 108903- env.ExecuteCodeLensCommand("main.go", command.GCDetails, nil) 108904- env.Await(NoDiagnostics(ForFile("main.go"))) 108905- }) 108906-} 108907- 108908-// Test for the crasher in golang/go#54199 108909-func TestGCDetails_NewFile(t *testing.T) { 108910- bug.PanicOnBugs = false 108911- const src = ` 108912--- go.mod -- 108913-module mod.test 108914- 108915-go 1.12 108916-` 108917- 108918- WithOptions( 108919- Settings{ 108920- "codelenses": map[string]bool{ 108921- "gc_details": true, 108922- }, 108923- }, 108924- ).Run(t, src, func(t *testing.T, env *Env) { 108925- env.CreateBuffer("p_test.go", "") 108926- 108927- const gcDetailsCommand = "gopls." + string(command.GCDetails) 108928- 108929- hasGCDetails := func() bool { 108930- lenses := env.CodeLens("p_test.go") // should not crash 108931- for _, lens := range lenses { 108932- if lens.Command.Command == gcDetailsCommand { 108933- return true 108934- } 108935- } 108936- return false 108937- } 108938- 108939- // With an empty file, we shouldn't get the gc_details codelens because 108940- // there is nowhere to position it (it needs a package name). 108941- if hasGCDetails() { 108942- t.Errorf("got the gc_details codelens for an empty file") 108943- } 108944- 108945- // Edit to provide a package name. 108946- env.EditBuffer("p_test.go", fake.NewEdit(0, 0, 0, 0, "package p")) 108947- 108948- // Now we should get the gc_details codelens. 108949- if !hasGCDetails() { 108950- t.Errorf("didn't get the gc_details codelens for a valid non-empty Go file") 108951- } 108952- }) 108953-} 108954diff -urN a/gopls/internal/regtest/completion/completion18_test.go b/gopls/internal/regtest/completion/completion18_test.go 108955--- a/gopls/internal/regtest/completion/completion18_test.go 2000-01-01 00:00:00.000000000 -0000 108956+++ b/gopls/internal/regtest/completion/completion18_test.go 1970-01-01 00:00:00.000000000 +0000 108957@@ -1,124 +0,0 @@ 108958-// Copyright 2021 The Go Authors. All rights reserved. 108959-// Use of this source code is governed by a BSD-style 108960-// license that can be found in the LICENSE file. 108961- 108962-//go:build go1.18 108963-// +build go1.18 108964- 108965-package completion 108966- 108967-import ( 108968- "testing" 108969- 108970- "golang.org/x/tools/gopls/internal/lsp/protocol" 108971- . "golang.org/x/tools/gopls/internal/lsp/regtest" 108972-) 108973- 108974-// test generic receivers 108975-func TestGenericReceiver(t *testing.T) { 108976- const files = ` 108977--- go.mod -- 108978-module mod.com 108979- 108980-go 1.18 108981--- main.go -- 108982-package main 108983-type SyncMap[K any, V comparable] struct {} 108984-func (s *SyncMap[K,V]) f() {} 108985-type XX[T any] struct {} 108986-type UU[T any] struct {} 108987-func (s SyncMap[XX,string]) g(v UU) {} 108988-` 108989- 108990- tests := []struct { 108991- pat string 108992- want []string 108993- }{ 108994- {"s .Syn", []string{"SyncMap[K, V]"}}, 108995- {"Map.X", []string{}}, // This is probably wrong, Maybe "XX"? 108996- {"v U", []string{"UU", "uint", "uint16", "uint32", "uint64", "uint8", "uintptr"}}, // not U[T] 108997- } 108998- Run(t, files, func(t *testing.T, env *Env) { 108999- env.OpenFile("main.go") 109000- env.Await(env.DoneWithOpen()) 109001- for _, tst := range tests { 109002- loc := env.RegexpSearch("main.go", tst.pat) 109003- loc.Range.Start.Character += uint32(protocol.UTF16Len([]byte(tst.pat))) 109004- completions := env.Completion(loc) 109005- result := compareCompletionLabels(tst.want, completions.Items) 109006- if result != "" { 109007- t.Errorf("%s: wanted %v", result, tst.want) 109008- for i, g := range completions.Items { 109009- t.Errorf("got %d %s %s", i, g.Label, g.Detail) 109010- } 109011- } 109012- } 109013- }) 109014-} 109015-func TestFuzzFunc(t *testing.T) { 109016- // use the example from the package documentation 109017- modfile := ` 109018--- go.mod -- 109019-module mod.com 109020- 109021-go 1.18 109022-` 109023- part0 := `package foo 109024-import "testing" 109025-func FuzzNone(f *testing.F) { 109026- f.Add(12) // better not find this f.Add 109027-} 109028-func FuzzHex(f *testing.F) { 109029- for _, seed := range [][]byte{{}, {0}, {9}, {0xa}, {0xf}, {1, 2, 3, 4}} { 109030- f.Ad` 109031- part1 := `d(seed) 109032- } 109033- f.F` 109034- part2 := `uzz(func(t *testing.T, in []byte) { 109035- enc := hex.EncodeToString(in) 109036- out, err := hex.DecodeString(enc) 109037- if err != nil { 109038- f.Failed() 109039- } 109040- if !bytes.Equal(in, out) { 109041- t.Fatalf("%v: round trip: %v, %s", in, out, f.Name()) 109042- } 109043- }) 109044-} 109045-` 109046- data := modfile + `-- a_test.go -- 109047-` + part0 + ` 109048--- b_test.go -- 109049-` + part0 + part1 + ` 109050--- c_test.go -- 109051-` + part0 + part1 + part2 109052- 109053- tests := []struct { 109054- file string 109055- pat string 109056- offset uint32 // UTF16 length from the beginning of pat to what the user just typed 109057- want []string 109058- }{ 109059- {"a_test.go", "f.Ad", 3, []string{"Add"}}, 109060- {"c_test.go", " f.F", 4, []string{"Failed"}}, 109061- {"c_test.go", "f.N", 3, []string{"Name"}}, 109062- {"b_test.go", "f.F", 3, []string{"Fuzz(func(t *testing.T, a []byte)", "Fail", "FailNow", 109063- "Failed", "Fatal", "Fatalf"}}, 109064- } 109065- Run(t, data, func(t *testing.T, env *Env) { 109066- for _, test := range tests { 109067- env.OpenFile(test.file) 109068- env.Await(env.DoneWithOpen()) 109069- loc := env.RegexpSearch(test.file, test.pat) 109070- loc.Range.Start.Character += test.offset // character user just typed? will type? 109071- completions := env.Completion(loc) 109072- result := compareCompletionLabels(test.want, completions.Items) 109073- if result != "" { 109074- t.Errorf("pat %q %q", test.pat, result) 109075- for i, it := range completions.Items { 109076- t.Errorf("%d got %q %q", i, it.Label, it.Detail) 109077- } 109078- } 109079- } 109080- }) 109081-} 109082diff -urN a/gopls/internal/regtest/completion/completion_test.go b/gopls/internal/regtest/completion/completion_test.go 109083--- a/gopls/internal/regtest/completion/completion_test.go 2000-01-01 00:00:00.000000000 -0000 109084+++ b/gopls/internal/regtest/completion/completion_test.go 1970-01-01 00:00:00.000000000 +0000 109085@@ -1,754 +0,0 @@ 109086-// Copyright 2020 The Go Authors. All rights reserved. 109087-// Use of this source code is governed by a BSD-style 109088-// license that can be found in the LICENSE file. 109089- 109090-package completion 109091- 109092-import ( 109093- "fmt" 109094- "strings" 109095- "testing" 109096- 109097- "github.com/google/go-cmp/cmp" 109098- "golang.org/x/tools/gopls/internal/hooks" 109099- . "golang.org/x/tools/gopls/internal/lsp/regtest" 109100- "golang.org/x/tools/internal/bug" 109101- "golang.org/x/tools/internal/testenv" 109102- 109103- "golang.org/x/tools/gopls/internal/lsp/protocol" 109104-) 109105- 109106-func TestMain(m *testing.M) { 109107- bug.PanicOnBugs = true 109108- Main(m, hooks.Options) 109109-} 109110- 109111-const proxy = ` 109112--- [email protected]/go.mod -- 109113-module example.com 109114- 109115-go 1.12 109116--- [email protected]/blah/blah.go -- 109117-package blah 109118- 109119-const Name = "Blah" 109120--- [email protected]/go.mod -- 109121-module random.org 109122- 109123-go 1.12 109124--- [email protected]/blah/blah.go -- 109125-package hello 109126- 109127-const Name = "Hello" 109128-` 109129- 109130-func TestPackageCompletion(t *testing.T) { 109131- const files = ` 109132--- go.mod -- 109133-module mod.com 109134- 109135-go 1.12 109136--- fruits/apple.go -- 109137-package apple 109138- 109139-fun apple() int { 109140- return 0 109141-} 109142- 109143--- fruits/testfile.go -- 109144-// this is a comment 109145- 109146-/* 109147- this is a multiline comment 109148-*/ 109149- 109150-import "fmt" 109151- 109152-func test() {} 109153- 109154--- fruits/testfile2.go -- 109155-package 109156- 109157--- fruits/testfile3.go -- 109158-pac 109159--- 123f_r.u~its-123/testfile.go -- 109160-package 109161- 109162--- .invalid-dir@-name/testfile.go -- 109163-package 109164-` 109165- var ( 109166- testfile4 = "" 109167- testfile5 = "/*a comment*/ " 109168- testfile6 = "/*a comment*/\n" 109169- ) 109170- for _, tc := range []struct { 109171- name string 109172- filename string 109173- content *string 109174- triggerRegexp string 109175- want []string 109176- editRegexp string 109177- }{ 109178- { 109179- name: "package completion at valid position", 109180- filename: "fruits/testfile.go", 109181- triggerRegexp: "\n()", 109182- want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"}, 109183- editRegexp: "\n()", 109184- }, 109185- { 109186- name: "package completion in a comment", 109187- filename: "fruits/testfile.go", 109188- triggerRegexp: "th(i)s", 109189- want: nil, 109190- }, 109191- { 109192- name: "package completion in a multiline comment", 109193- filename: "fruits/testfile.go", 109194- triggerRegexp: `\/\*\n()`, 109195- want: nil, 109196- }, 109197- { 109198- name: "package completion at invalid position", 109199- filename: "fruits/testfile.go", 109200- triggerRegexp: "import \"fmt\"\n()", 109201- want: nil, 109202- }, 109203- { 109204- name: "package completion after keyword 'package'", 109205- filename: "fruits/testfile2.go", 109206- triggerRegexp: "package()", 109207- want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"}, 109208- editRegexp: "package\n", 109209- }, 109210- { 109211- name: "package completion with 'pac' prefix", 109212- filename: "fruits/testfile3.go", 109213- triggerRegexp: "pac()", 109214- want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"}, 109215- editRegexp: "pac", 109216- }, 109217- { 109218- name: "package completion for empty file", 109219- filename: "fruits/testfile4.go", 109220- triggerRegexp: "^$", 109221- content: &testfile4, 109222- want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"}, 109223- editRegexp: "^$", 109224- }, 109225- { 109226- name: "package completion without terminal newline", 109227- filename: "fruits/testfile5.go", 109228- triggerRegexp: `\*\/ ()`, 109229- content: &testfile5, 109230- want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"}, 109231- editRegexp: `\*\/ ()`, 109232- }, 109233- { 109234- name: "package completion on terminal newline", 109235- filename: "fruits/testfile6.go", 109236- triggerRegexp: `\*\/\n()`, 109237- content: &testfile6, 109238- want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"}, 109239- editRegexp: `\*\/\n()`, 109240- }, 109241- // Issue golang/go#44680 109242- { 109243- name: "package completion for dir name with punctuation", 109244- filename: "123f_r.u~its-123/testfile.go", 109245- triggerRegexp: "package()", 109246- want: []string{"package fruits123", "package fruits123_test", "package main"}, 109247- editRegexp: "package\n", 109248- }, 109249- { 109250- name: "package completion for invalid dir name", 109251- filename: ".invalid-dir@-name/testfile.go", 109252- triggerRegexp: "package()", 109253- want: []string{"package main"}, 109254- editRegexp: "package\n", 109255- }, 109256- } { 109257- t.Run(tc.name, func(t *testing.T) { 109258- Run(t, files, func(t *testing.T, env *Env) { 109259- if tc.content != nil { 109260- env.WriteWorkspaceFile(tc.filename, *tc.content) 109261- env.Await(env.DoneWithChangeWatchedFiles()) 109262- } 109263- env.OpenFile(tc.filename) 109264- completions := env.Completion(env.RegexpSearch(tc.filename, tc.triggerRegexp)) 109265- 109266- // Check that the completion item suggestions are in the range 109267- // of the file. {Start,End}.Line are zero-based. 109268- lineCount := len(strings.Split(env.BufferText(tc.filename), "\n")) 109269- for _, item := range completions.Items { 109270- if start := int(item.TextEdit.Range.Start.Line); start > lineCount { 109271- t.Fatalf("unexpected text edit range start line number: got %d, want <= %d", start, lineCount) 109272- } 109273- if end := int(item.TextEdit.Range.End.Line); end > lineCount { 109274- t.Fatalf("unexpected text edit range end line number: got %d, want <= %d", end, lineCount) 109275- } 109276- } 109277- 109278- if tc.want != nil { 109279- expectedLoc := env.RegexpSearch(tc.filename, tc.editRegexp) 109280- for _, item := range completions.Items { 109281- gotRng := item.TextEdit.Range 109282- if expectedLoc.Range != gotRng { 109283- t.Errorf("unexpected completion range for completion item %s: got %v, want %v", 109284- item.Label, gotRng, expectedLoc.Range) 109285- } 109286- } 109287- } 109288- 109289- diff := compareCompletionLabels(tc.want, completions.Items) 109290- if diff != "" { 109291- t.Error(diff) 109292- } 109293- }) 109294- }) 109295- } 109296-} 109297- 109298-func TestPackageNameCompletion(t *testing.T) { 109299- const files = ` 109300--- go.mod -- 109301-module mod.com 109302- 109303-go 1.12 109304--- math/add.go -- 109305-package ma 109306-` 109307- 109308- want := []string{"ma", "ma_test", "main", "math", "math_test"} 109309- Run(t, files, func(t *testing.T, env *Env) { 109310- env.OpenFile("math/add.go") 109311- completions := env.Completion(env.RegexpSearch("math/add.go", "package ma()")) 109312- 109313- diff := compareCompletionLabels(want, completions.Items) 109314- if diff != "" { 109315- t.Fatal(diff) 109316- } 109317- }) 109318-} 109319- 109320-// TODO(rfindley): audit/clean up call sites for this helper, to ensure 109321-// consistent test errors. 109322-func compareCompletionLabels(want []string, gotItems []protocol.CompletionItem) string { 109323- var got []string 109324- for _, item := range gotItems { 109325- got = append(got, item.Label) 109326- if item.Label != item.InsertText && item.TextEdit == nil { 109327- // Label should be the same as InsertText, if InsertText is to be used 109328- return fmt.Sprintf("label not the same as InsertText %#v", item) 109329- } 109330- } 109331- 109332- if len(got) == 0 && len(want) == 0 { 109333- return "" // treat nil and the empty slice as equivalent 109334- } 109335- 109336- if diff := cmp.Diff(want, got); diff != "" { 109337- return fmt.Sprintf("completion item mismatch (-want +got):\n%s", diff) 109338- } 109339- return "" 109340-} 109341- 109342-func TestUnimportedCompletion(t *testing.T) { 109343- const mod = ` 109344--- go.mod -- 109345-module mod.com 109346- 109347-go 1.14 109348- 109349-require example.com v1.2.3 109350--- go.sum -- 109351-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 109352-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 109353--- main.go -- 109354-package main 109355- 109356-func main() { 109357- _ = blah 109358-} 109359--- main2.go -- 109360-package main 109361- 109362-import "example.com/blah" 109363- 109364-func _() { 109365- _ = blah.Hello 109366-} 109367-` 109368- WithOptions( 109369- ProxyFiles(proxy), 109370- ).Run(t, mod, func(t *testing.T, env *Env) { 109371- // Make sure the dependency is in the module cache and accessible for 109372- // unimported completions, and then remove it before proceeding. 109373- env.RemoveWorkspaceFile("main2.go") 109374- env.RunGoCommand("mod", "tidy") 109375- env.Await(env.DoneWithChangeWatchedFiles()) 109376- 109377- // Trigger unimported completions for the example.com/blah package. 109378- env.OpenFile("main.go") 109379- env.Await(env.DoneWithOpen()) 109380- loc := env.RegexpSearch("main.go", "ah") 109381- completions := env.Completion(loc) 109382- if len(completions.Items) == 0 { 109383- t.Fatalf("no completion items") 109384- } 109385- env.AcceptCompletion(loc, completions.Items[0]) // adds blah import to main.go 109386- env.Await(env.DoneWithChange()) 109387- 109388- // Trigger completions once again for the blah.<> selector. 109389- env.RegexpReplace("main.go", "_ = blah", "_ = blah.") 109390- env.Await(env.DoneWithChange()) 109391- loc = env.RegexpSearch("main.go", "\n}") 109392- completions = env.Completion(loc) 109393- if len(completions.Items) != 1 { 109394- t.Fatalf("expected 1 completion item, got %v", len(completions.Items)) 109395- } 109396- item := completions.Items[0] 109397- if item.Label != "Name" { 109398- t.Fatalf("expected completion item blah.Name, got %v", item.Label) 109399- } 109400- env.AcceptCompletion(loc, item) 109401- 109402- // Await the diagnostics to add example.com/blah to the go.mod file. 109403- env.AfterChange( 109404- Diagnostics(env.AtRegexp("main.go", `"example.com/blah"`)), 109405- ) 109406- }) 109407-} 109408- 109409-// Test that completions still work with an undownloaded module, golang/go#43333. 109410-func TestUndownloadedModule(t *testing.T) { 109411- // mod.com depends on example.com, but only in a file that's hidden by a 109412- // build tag, so the IWL won't download example.com. That will cause errors 109413- // in the go list -m call performed by the imports package. 109414- const files = ` 109415--- go.mod -- 109416-module mod.com 109417- 109418-go 1.14 109419- 109420-require example.com v1.2.3 109421--- go.sum -- 109422-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 109423-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 109424--- useblah.go -- 109425-// +build hidden 109426- 109427-package pkg 109428-import "example.com/blah" 109429-var _ = blah.Name 109430--- mainmod/mainmod.go -- 109431-package mainmod 109432- 109433-const Name = "mainmod" 109434-` 109435- WithOptions(ProxyFiles(proxy)).Run(t, files, func(t *testing.T, env *Env) { 109436- env.CreateBuffer("import.go", "package pkg\nvar _ = mainmod.Name\n") 109437- env.SaveBuffer("import.go") 109438- content := env.ReadWorkspaceFile("import.go") 109439- if !strings.Contains(content, `import "mod.com/mainmod`) { 109440- t.Errorf("expected import of mod.com/mainmod in %q", content) 109441- } 109442- }) 109443-} 109444- 109445-// Test that we can doctor the source code enough so the file is 109446-// parseable and completion works as expected. 109447-func TestSourceFixup(t *testing.T) { 109448- const files = ` 109449--- go.mod -- 109450-module mod.com 109451- 109452-go 1.12 109453--- foo.go -- 109454-package foo 109455- 109456-func _() { 109457- var s S 109458- if s. 109459-} 109460- 109461-type S struct { 109462- i int 109463-} 109464-` 109465- 109466- Run(t, files, func(t *testing.T, env *Env) { 109467- env.OpenFile("foo.go") 109468- completions := env.Completion(env.RegexpSearch("foo.go", `if s\.()`)) 109469- diff := compareCompletionLabels([]string{"i"}, completions.Items) 109470- if diff != "" { 109471- t.Fatal(diff) 109472- } 109473- }) 109474-} 109475- 109476-func TestCompletion_Issue45510(t *testing.T) { 109477- const files = ` 109478--- go.mod -- 109479-module mod.com 109480- 109481-go 1.12 109482--- main.go -- 109483-package main 109484- 109485-func _() { 109486- type a *a 109487- var aaaa1, aaaa2 a 109488- var _ a = aaaa 109489- 109490- type b a 109491- var bbbb1, bbbb2 b 109492- var _ b = bbbb 109493-} 109494- 109495-type ( 109496- c *d 109497- d *e 109498- e **c 109499-) 109500- 109501-func _() { 109502- var ( 109503- xxxxc c 109504- xxxxd d 109505- xxxxe e 109506- ) 109507- 109508- var _ c = xxxx 109509- var _ d = xxxx 109510- var _ e = xxxx 109511-} 109512-` 109513- 109514- Run(t, files, func(t *testing.T, env *Env) { 109515- env.OpenFile("main.go") 109516- 109517- tests := []struct { 109518- re string 109519- want []string 109520- }{ 109521- {`var _ a = aaaa()`, []string{"aaaa1", "aaaa2"}}, 109522- {`var _ b = bbbb()`, []string{"bbbb1", "bbbb2"}}, 109523- {`var _ c = xxxx()`, []string{"xxxxc", "xxxxd", "xxxxe"}}, 109524- {`var _ d = xxxx()`, []string{"xxxxc", "xxxxd", "xxxxe"}}, 109525- {`var _ e = xxxx()`, []string{"xxxxc", "xxxxd", "xxxxe"}}, 109526- } 109527- for _, tt := range tests { 109528- completions := env.Completion(env.RegexpSearch("main.go", tt.re)) 109529- diff := compareCompletionLabels(tt.want, completions.Items) 109530- if diff != "" { 109531- t.Errorf("%s: %s", tt.re, diff) 109532- } 109533- } 109534- }) 109535-} 109536- 109537-func TestCompletionDeprecation(t *testing.T) { 109538- const files = ` 109539--- go.mod -- 109540-module test.com 109541- 109542-go 1.16 109543--- prog.go -- 109544-package waste 109545-// Deprecated, use newFoof 109546-func fooFunc() bool { 109547- return false 109548-} 109549- 109550-// Deprecated 109551-const badPi = 3.14 109552- 109553-func doit() { 109554- if fooF 109555- panic() 109556- x := badP 109557-} 109558-` 109559- Run(t, files, func(t *testing.T, env *Env) { 109560- env.OpenFile("prog.go") 109561- loc := env.RegexpSearch("prog.go", "if fooF") 109562- loc.Range.Start.Character += uint32(protocol.UTF16Len([]byte("if fooF"))) 109563- completions := env.Completion(loc) 109564- diff := compareCompletionLabels([]string{"fooFunc"}, completions.Items) 109565- if diff != "" { 109566- t.Error(diff) 109567- } 109568- if completions.Items[0].Tags == nil { 109569- t.Errorf("expected Tags to show deprecation %#v", completions.Items[0].Tags) 109570- } 109571- loc = env.RegexpSearch("prog.go", "= badP") 109572- loc.Range.Start.Character += uint32(protocol.UTF16Len([]byte("= badP"))) 109573- completions = env.Completion(loc) 109574- diff = compareCompletionLabels([]string{"badPi"}, completions.Items) 109575- if diff != "" { 109576- t.Error(diff) 109577- } 109578- if completions.Items[0].Tags == nil { 109579- t.Errorf("expected Tags to show deprecation %#v", completions.Items[0].Tags) 109580- } 109581- }) 109582-} 109583- 109584-func TestUnimportedCompletion_VSCodeIssue1489(t *testing.T) { 109585- const src = ` 109586--- go.mod -- 109587-module mod.com 109588- 109589-go 1.14 109590- 109591--- main.go -- 109592-package main 109593- 109594-import "fmt" 109595- 109596-func main() { 109597- fmt.Println("a") 109598- math.Sqr 109599-} 109600-` 109601- WithOptions( 109602- WindowsLineEndings(), 109603- ).Run(t, src, func(t *testing.T, env *Env) { 109604- // Trigger unimported completions for the mod.com package. 109605- env.OpenFile("main.go") 109606- env.Await(env.DoneWithOpen()) 109607- loc := env.RegexpSearch("main.go", "Sqr()") 109608- completions := env.Completion(loc) 109609- if len(completions.Items) == 0 { 109610- t.Fatalf("no completion items") 109611- } 109612- env.AcceptCompletion(loc, completions.Items[0]) 109613- env.Await(env.DoneWithChange()) 109614- got := env.BufferText("main.go") 109615- want := "package main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"math\"\r\n)\r\n\r\nfunc main() {\r\n\tfmt.Println(\"a\")\r\n\tmath.Sqrt(${1:})\r\n}\r\n" 109616- if diff := cmp.Diff(want, got); diff != "" { 109617- t.Errorf("unimported completion (-want +got):\n%s", diff) 109618- } 109619- }) 109620-} 109621- 109622-func TestPackageMemberCompletionAfterSyntaxError(t *testing.T) { 109623- // This test documents the current broken behavior due to golang/go#58833. 109624- const src = ` 109625--- go.mod -- 109626-module mod.com 109627- 109628-go 1.14 109629- 109630--- main.go -- 109631-package main 109632- 109633-import "math" 109634- 109635-func main() { 109636- math.Sqrt(,0) 109637- math.Ldex 109638-} 109639-` 109640- Run(t, src, func(t *testing.T, env *Env) { 109641- env.OpenFile("main.go") 109642- env.Await(env.DoneWithOpen()) 109643- loc := env.RegexpSearch("main.go", "Ldex()") 109644- completions := env.Completion(loc) 109645- if len(completions.Items) == 0 { 109646- t.Fatalf("no completion items") 109647- } 109648- env.AcceptCompletion(loc, completions.Items[0]) 109649- env.Await(env.DoneWithChange()) 109650- got := env.BufferText("main.go") 109651- // The completion of math.Ldex after the syntax error on the 109652- // previous line is not "math.Ldexp" but "math.Ldexmath.Abs". 109653- // (In VSCode, "Abs" wrongly appears in the completion menu.) 109654- // This is a consequence of poor error recovery in the parser 109655- // causing "math.Ldex" to become a BadExpr. 109656- want := "package main\n\nimport \"math\"\n\nfunc main() {\n\tmath.Sqrt(,0)\n\tmath.Ldexmath.Abs(${1:})\n}\n" 109657- if diff := cmp.Diff(want, got); diff != "" { 109658- t.Errorf("unimported completion (-want +got):\n%s", diff) 109659- } 109660- }) 109661-} 109662- 109663-func TestDefinition(t *testing.T) { 109664- testenv.NeedsGo1Point(t, 17) // in go1.16, The FieldList in func x is not empty 109665- files := ` 109666--- go.mod -- 109667-module mod.com 109668- 109669-go 1.18 109670--- a_test.go -- 109671-package foo 109672-` 109673- tests := []struct { 109674- line string // the sole line in the buffer after the package statement 109675- pat string // the pattern to search for 109676- want []string // expected completions 109677- }{ 109678- {"func T", "T", []string{"TestXxx(t *testing.T)", "TestMain(m *testing.M)"}}, 109679- {"func T()", "T", []string{"TestMain", "Test"}}, 109680- {"func TestM", "TestM", []string{"TestMain(m *testing.M)", "TestM(t *testing.T)"}}, 109681- {"func TestM()", "TestM", []string{"TestMain"}}, 109682- {"func TestMi", "TestMi", []string{"TestMi(t *testing.T)"}}, 109683- {"func TestMi()", "TestMi", nil}, 109684- {"func TestG", "TestG", []string{"TestG(t *testing.T)"}}, 109685- {"func TestG(", "TestG", nil}, 109686- {"func Ben", "B", []string{"BenchmarkXxx(b *testing.B)"}}, 109687- {"func Ben(", "Ben", []string{"Benchmark"}}, 109688- {"func BenchmarkFoo", "BenchmarkFoo", []string{"BenchmarkFoo(b *testing.B)"}}, 109689- {"func BenchmarkFoo(", "BenchmarkFoo", nil}, 109690- {"func Fuz", "F", []string{"FuzzXxx(f *testing.F)"}}, 109691- {"func Fuz(", "Fuz", []string{"Fuzz"}}, 109692- {"func Testx", "Testx", nil}, 109693- {"func TestMe(t *testing.T)", "TestMe", nil}, 109694- {"func Te(t *testing.T)", "Te", []string{"TestMain", "Test"}}, 109695- } 109696- fname := "a_test.go" 109697- Run(t, files, func(t *testing.T, env *Env) { 109698- env.OpenFile(fname) 109699- env.Await(env.DoneWithOpen()) 109700- for _, test := range tests { 109701- env.SetBufferContent(fname, "package foo\n"+test.line) 109702- loc := env.RegexpSearch(fname, test.pat) 109703- loc.Range.Start.Character += uint32(protocol.UTF16Len([]byte(test.pat))) 109704- completions := env.Completion(loc) 109705- if diff := compareCompletionLabels(test.want, completions.Items); diff != "" { 109706- t.Error(diff) 109707- } 109708- } 109709- }) 109710-} 109711- 109712-// Test that completing a definition replaces source text when applied, golang/go#56852. 109713-// Note: With go <= 1.16 the completions does not add parameters and fails these tests. 109714-func TestDefinitionReplaceRange(t *testing.T) { 109715- testenv.NeedsGo1Point(t, 17) 109716- 109717- const mod = ` 109718--- go.mod -- 109719-module mod.com 109720- 109721-go 1.17 109722-` 109723- 109724- tests := []struct { 109725- name string 109726- before, after string 109727- }{ 109728- { 109729- name: "func TestMa", 109730- before: ` 109731-package foo_test 109732- 109733-func TestMa 109734-`, 109735- after: ` 109736-package foo_test 109737- 109738-func TestMain(m *testing.M) 109739-`, 109740- }, 109741- { 109742- name: "func TestSome", 109743- before: ` 109744-package foo_test 109745- 109746-func TestSome 109747-`, 109748- after: ` 109749-package foo_test 109750- 109751-func TestSome(t *testing.T) 109752-`, 109753- }, 109754- { 109755- name: "func Bench", 109756- before: ` 109757-package foo_test 109758- 109759-func Bench 109760-`, 109761- // Note: Snippet with escaped }. 109762- after: ` 109763-package foo_test 109764- 109765-func Benchmark${1:Xxx}(b *testing.B) { 109766- $0 109767-\} 109768-`, 109769- }, 109770- } 109771- 109772- Run(t, mod, func(t *testing.T, env *Env) { 109773- env.CreateBuffer("foo_test.go", "") 109774- 109775- for _, tst := range tests { 109776- tst.before = strings.Trim(tst.before, "\n") 109777- tst.after = strings.Trim(tst.after, "\n") 109778- env.SetBufferContent("foo_test.go", tst.before) 109779- 109780- loc := env.RegexpSearch("foo_test.go", tst.name) 109781- loc.Range.Start.Character = uint32(protocol.UTF16Len([]byte(tst.name))) 109782- completions := env.Completion(loc) 109783- if len(completions.Items) == 0 { 109784- t.Fatalf("no completion items") 109785- } 109786- 109787- env.AcceptCompletion(loc, completions.Items[0]) 109788- env.Await(env.DoneWithChange()) 109789- if buf := env.BufferText("foo_test.go"); buf != tst.after { 109790- t.Errorf("%s:incorrect completion: got %q, want %q", tst.name, buf, tst.after) 109791- } 109792- } 109793- }) 109794-} 109795- 109796-func TestGoWorkCompletion(t *testing.T) { 109797- const files = ` 109798--- go.work -- 109799-go 1.18 109800- 109801-use ./a 109802-use ./a/ba 109803-use ./a/b/ 109804-use ./dir/foo 109805-use ./dir/foobar/ 109806--- a/go.mod -- 109807--- go.mod -- 109808--- a/bar/go.mod -- 109809--- a/b/c/d/e/f/go.mod -- 109810--- dir/bar -- 109811--- dir/foobar/go.mod -- 109812-` 109813- 109814- Run(t, files, func(t *testing.T, env *Env) { 109815- env.OpenFile("go.work") 109816- 109817- tests := []struct { 109818- re string 109819- want []string 109820- }{ 109821- {`use ()\.`, []string{".", "./a", "./a/bar", "./dir/foobar"}}, 109822- {`use \.()`, []string{"", "/a", "/a/bar", "/dir/foobar"}}, 109823- {`use \./()`, []string{"a", "a/bar", "dir/foobar"}}, 109824- {`use ./a()`, []string{"", "/b/c/d/e/f", "/bar"}}, 109825- {`use ./a/b()`, []string{"/c/d/e/f", "ar"}}, 109826- {`use ./a/b/()`, []string{`c/d/e/f`}}, 109827- {`use ./a/ba()`, []string{"r"}}, 109828- {`use ./dir/foo()`, []string{"bar"}}, 109829- {`use ./dir/foobar/()`, []string{}}, 109830- } 109831- for _, tt := range tests { 109832- completions := env.Completion(env.RegexpSearch("go.work", tt.re)) 109833- diff := compareCompletionLabels(tt.want, completions.Items) 109834- if diff != "" { 109835- t.Errorf("%s: %s", tt.re, diff) 109836- } 109837- } 109838- }) 109839-} 109840diff -urN a/gopls/internal/regtest/completion/postfix_snippet_test.go b/gopls/internal/regtest/completion/postfix_snippet_test.go 109841--- a/gopls/internal/regtest/completion/postfix_snippet_test.go 2000-01-01 00:00:00.000000000 -0000 109842+++ b/gopls/internal/regtest/completion/postfix_snippet_test.go 1970-01-01 00:00:00.000000000 +0000 109843@@ -1,464 +0,0 @@ 109844-// Copyright 2021 The Go Authors. All rights reserved. 109845-// Use of this source code is governed by a BSD-style 109846-// license that can be found in the LICENSE file. 109847- 109848-package completion 109849- 109850-import ( 109851- "strings" 109852- "testing" 109853- 109854- . "golang.org/x/tools/gopls/internal/lsp/regtest" 109855-) 109856- 109857-func TestPostfixSnippetCompletion(t *testing.T) { 109858- const mod = ` 109859--- go.mod -- 109860-module mod.com 109861- 109862-go 1.12 109863-` 109864- 109865- cases := []struct { 109866- name string 109867- before, after string 109868- }{ 109869- { 109870- name: "sort", 109871- before: ` 109872-package foo 109873- 109874-func _() { 109875- var foo []int 109876- foo.sort 109877-} 109878-`, 109879- after: ` 109880-package foo 109881- 109882-import "sort" 109883- 109884-func _() { 109885- var foo []int 109886- sort.Slice(foo, func(i, j int) bool { 109887- $0 109888-}) 109889-} 109890-`, 109891- }, 109892- { 109893- name: "sort_renamed_sort_package", 109894- before: ` 109895-package foo 109896- 109897-import blahsort "sort" 109898- 109899-var j int 109900- 109901-func _() { 109902- var foo []int 109903- foo.sort 109904-} 109905-`, 109906- after: ` 109907-package foo 109908- 109909-import blahsort "sort" 109910- 109911-var j int 109912- 109913-func _() { 109914- var foo []int 109915- blahsort.Slice(foo, func(i, j2 int) bool { 109916- $0 109917-}) 109918-} 109919-`, 109920- }, 109921- { 109922- name: "last", 109923- before: ` 109924-package foo 109925- 109926-func _() { 109927- var s struct { i []int } 109928- s.i.last 109929-} 109930-`, 109931- after: ` 109932-package foo 109933- 109934-func _() { 109935- var s struct { i []int } 109936- s.i[len(s.i)-1] 109937-} 109938-`, 109939- }, 109940- { 109941- name: "reverse", 109942- before: ` 109943-package foo 109944- 109945-func _() { 109946- var foo []int 109947- foo.reverse 109948-} 109949-`, 109950- after: ` 109951-package foo 109952- 109953-func _() { 109954- var foo []int 109955- for i, j := 0, len(foo)-1; i < j; i, j = i+1, j-1 { 109956- foo[i], foo[j] = foo[j], foo[i] 109957-} 109958- 109959-} 109960-`, 109961- }, 109962- { 109963- name: "slice_range", 109964- before: ` 109965-package foo 109966- 109967-func _() { 109968- type myThing struct{} 109969- var foo []myThing 109970- foo.range 109971-} 109972-`, 109973- after: ` 109974-package foo 109975- 109976-func _() { 109977- type myThing struct{} 109978- var foo []myThing 109979- for i, mt := range foo { 109980- $0 109981-} 109982-} 109983-`, 109984- }, 109985- { 109986- name: "append_stmt", 109987- before: ` 109988-package foo 109989- 109990-func _() { 109991- var foo []int 109992- foo.append 109993-} 109994-`, 109995- after: ` 109996-package foo 109997- 109998-func _() { 109999- var foo []int 110000- foo = append(foo, $0) 110001-} 110002-`, 110003- }, 110004- { 110005- name: "append_expr", 110006- before: ` 110007-package foo 110008- 110009-func _() { 110010- var foo []int 110011- var _ []int = foo.append 110012-} 110013-`, 110014- after: ` 110015-package foo 110016- 110017-func _() { 110018- var foo []int 110019- var _ []int = append(foo, $0) 110020-} 110021-`, 110022- }, 110023- { 110024- name: "slice_copy", 110025- before: ` 110026-package foo 110027- 110028-func _() { 110029- var foo []int 110030- foo.copy 110031-} 110032-`, 110033- after: ` 110034-package foo 110035- 110036-func _() { 110037- var foo []int 110038- fooCopy := make([]int, len(foo)) 110039-copy(fooCopy, foo) 110040- 110041-} 110042-`, 110043- }, 110044- { 110045- name: "map_range", 110046- before: ` 110047-package foo 110048- 110049-func _() { 110050- var foo map[string]int 110051- foo.range 110052-} 110053-`, 110054- after: ` 110055-package foo 110056- 110057-func _() { 110058- var foo map[string]int 110059- for k, v := range foo { 110060- $0 110061-} 110062-} 110063-`, 110064- }, 110065- { 110066- name: "map_clear", 110067- before: ` 110068-package foo 110069- 110070-func _() { 110071- var foo map[string]int 110072- foo.clear 110073-} 110074-`, 110075- after: ` 110076-package foo 110077- 110078-func _() { 110079- var foo map[string]int 110080- for k := range foo { 110081- delete(foo, k) 110082-} 110083- 110084-} 110085-`, 110086- }, 110087- { 110088- name: "map_keys", 110089- before: ` 110090-package foo 110091- 110092-func _() { 110093- var foo map[string]int 110094- foo.keys 110095-} 110096-`, 110097- after: ` 110098-package foo 110099- 110100-func _() { 110101- var foo map[string]int 110102- keys := make([]string, 0, len(foo)) 110103-for k := range foo { 110104- keys = append(keys, k) 110105-} 110106- 110107-} 110108-`, 110109- }, 110110- { 110111- name: "channel_range", 110112- before: ` 110113-package foo 110114- 110115-func _() { 110116- foo := make(chan int) 110117- foo.range 110118-} 110119-`, 110120- after: ` 110121-package foo 110122- 110123-func _() { 110124- foo := make(chan int) 110125- for e := range foo { 110126- $0 110127-} 110128-} 110129-`, 110130- }, 110131- { 110132- name: "var", 110133- before: ` 110134-package foo 110135- 110136-func foo() (int, error) { return 0, nil } 110137- 110138-func _() { 110139- foo().var 110140-} 110141-`, 110142- after: ` 110143-package foo 110144- 110145-func foo() (int, error) { return 0, nil } 110146- 110147-func _() { 110148- i, err := foo() 110149-} 110150-`, 110151- }, 110152- { 110153- name: "var_single_value", 110154- before: ` 110155-package foo 110156- 110157-func foo() error { return nil } 110158- 110159-func _() { 110160- foo().var 110161-} 110162-`, 110163- after: ` 110164-package foo 110165- 110166-func foo() error { return nil } 110167- 110168-func _() { 110169- err := foo() 110170-} 110171-`, 110172- }, 110173- { 110174- name: "var_same_type", 110175- before: ` 110176-package foo 110177- 110178-func foo() (int, int) { return 0, 0 } 110179- 110180-func _() { 110181- foo().var 110182-} 110183-`, 110184- after: ` 110185-package foo 110186- 110187-func foo() (int, int) { return 0, 0 } 110188- 110189-func _() { 110190- i, i2 := foo() 110191-} 110192-`, 110193- }, 110194- { 110195- name: "print_scalar", 110196- before: ` 110197-package foo 110198- 110199-func _() { 110200- var foo int 110201- foo.print 110202-} 110203-`, 110204- after: ` 110205-package foo 110206- 110207-import "fmt" 110208- 110209-func _() { 110210- var foo int 110211- fmt.Printf("foo: %v\n", foo) 110212-} 110213-`, 110214- }, 110215- { 110216- name: "print_multi", 110217- before: ` 110218-package foo 110219- 110220-func foo() (int, error) { return 0, nil } 110221- 110222-func _() { 110223- foo().print 110224-} 110225-`, 110226- after: ` 110227-package foo 110228- 110229-import "fmt" 110230- 110231-func foo() (int, error) { return 0, nil } 110232- 110233-func _() { 110234- fmt.Println(foo()) 110235-} 110236-`, 110237- }, 110238- { 110239- name: "string split", 110240- before: ` 110241-package foo 110242- 110243-func foo() []string { 110244- x := "test" 110245- return x.split 110246-}`, 110247- after: ` 110248-package foo 110249- 110250-import "strings" 110251- 110252-func foo() []string { 110253- x := "test" 110254- return strings.Split(x, "$0") 110255-}`, 110256- }, 110257- { 110258- name: "string slice join", 110259- before: ` 110260-package foo 110261- 110262-func foo() string { 110263- x := []string{"a", "test"} 110264- return x.join 110265-}`, 110266- after: ` 110267-package foo 110268- 110269-import "strings" 110270- 110271-func foo() string { 110272- x := []string{"a", "test"} 110273- return strings.Join(x, "$0") 110274-}`, 110275- }, 110276- } 110277- 110278- r := WithOptions( 110279- Settings{ 110280- "experimentalPostfixCompletions": true, 110281- }, 110282- ) 110283- r.Run(t, mod, func(t *testing.T, env *Env) { 110284- env.CreateBuffer("foo.go", "") 110285- 110286- for _, c := range cases { 110287- t.Run(c.name, func(t *testing.T) { 110288- c.before = strings.Trim(c.before, "\n") 110289- c.after = strings.Trim(c.after, "\n") 110290- 110291- env.SetBufferContent("foo.go", c.before) 110292- 110293- loc := env.RegexpSearch("foo.go", "\n}") 110294- completions := env.Completion(loc) 110295- if len(completions.Items) != 1 { 110296- t.Fatalf("expected one completion, got %v", completions.Items) 110297- } 110298- 110299- env.AcceptCompletion(loc, completions.Items[0]) 110300- 110301- if buf := env.BufferText("foo.go"); buf != c.after { 110302- t.Errorf("\nGOT:\n%s\nEXPECTED:\n%s", buf, c.after) 110303- } 110304- }) 110305- } 110306- }) 110307-} 110308diff -urN a/gopls/internal/regtest/debug/debug_test.go b/gopls/internal/regtest/debug/debug_test.go 110309--- a/gopls/internal/regtest/debug/debug_test.go 2000-01-01 00:00:00.000000000 -0000 110310+++ b/gopls/internal/regtest/debug/debug_test.go 1970-01-01 00:00:00.000000000 +0000 110311@@ -1,30 +0,0 @@ 110312-// Copyright 2022 The Go Authors. All rights reserved. 110313-// Use of this source code is governed by a BSD-style 110314-// license that can be found in the LICENSE file. 110315- 110316-package debug 110317- 110318-import ( 110319- "testing" 110320- 110321- "golang.org/x/tools/gopls/internal/hooks" 110322- . "golang.org/x/tools/gopls/internal/lsp/regtest" 110323- "golang.org/x/tools/internal/bug" 110324-) 110325- 110326-func TestMain(m *testing.M) { 110327- Main(m, hooks.Options) 110328-} 110329- 110330-func TestBugNotification(t *testing.T) { 110331- // Verify that a properly configured session gets notified of a bug on the 110332- // server. 110333- WithOptions( 110334- Modes(Default), // must be in-process to receive the bug report below 110335- Settings{"showBugReports": true}, 110336- ).Run(t, "", func(t *testing.T, env *Env) { 110337- const desc = "got a bug" 110338- bug.Report(desc, nil) 110339- env.Await(ShownMessage(desc)) 110340- }) 110341-} 110342diff -urN a/gopls/internal/regtest/diagnostics/analysis_test.go b/gopls/internal/regtest/diagnostics/analysis_test.go 110343--- a/gopls/internal/regtest/diagnostics/analysis_test.go 2000-01-01 00:00:00.000000000 -0000 110344+++ b/gopls/internal/regtest/diagnostics/analysis_test.go 1970-01-01 00:00:00.000000000 +0000 110345@@ -1,49 +0,0 @@ 110346-// Copyright 2022 The Go Authors. All rights reserved. 110347-// Use of this source code is governed by a BSD-style 110348-// license that can be found in the LICENSE file. 110349- 110350-package diagnostics 110351- 110352-import ( 110353- "testing" 110354- 110355- "golang.org/x/tools/gopls/internal/lsp/protocol" 110356- . "golang.org/x/tools/gopls/internal/lsp/regtest" 110357-) 110358- 110359-// Test for the timeformat analyzer, following golang/vscode-go#2406. 110360-// 110361-// This test checks that applying the suggested fix from the analyzer resolves 110362-// the diagnostic warning. 110363-func TestTimeFormatAnalyzer(t *testing.T) { 110364- const files = ` 110365--- go.mod -- 110366-module mod.com 110367- 110368-go 1.18 110369--- main.go -- 110370-package main 110371- 110372-import ( 110373- "fmt" 110374- "time" 110375-) 110376- 110377-func main() { 110378- now := time.Now() 110379- fmt.Println(now.Format("2006-02-01")) 110380-}` 110381- 110382- Run(t, files, func(t *testing.T, env *Env) { 110383- env.OpenFile("main.go") 110384- 110385- var d protocol.PublishDiagnosticsParams 110386- env.AfterChange( 110387- Diagnostics(env.AtRegexp("main.go", "2006-02-01")), 110388- ReadDiagnostics("main.go", &d), 110389- ) 110390- 110391- env.ApplyQuickFixes("main.go", d.Diagnostics) 110392- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 110393- }) 110394-} 110395diff -urN a/gopls/internal/regtest/diagnostics/builtin_test.go b/gopls/internal/regtest/diagnostics/builtin_test.go 110396--- a/gopls/internal/regtest/diagnostics/builtin_test.go 2000-01-01 00:00:00.000000000 -0000 110397+++ b/gopls/internal/regtest/diagnostics/builtin_test.go 1970-01-01 00:00:00.000000000 +0000 110398@@ -1,35 +0,0 @@ 110399-// Copyright 2021 The Go Authors. All rights reserved. 110400-// Use of this source code is governed by a BSD-style 110401-// license that can be found in the LICENSE file. 110402- 110403-package diagnostics 110404- 110405-import ( 110406- "strings" 110407- "testing" 110408- 110409- . "golang.org/x/tools/gopls/internal/lsp/regtest" 110410-) 110411- 110412-func TestIssue44866(t *testing.T) { 110413- src := ` 110414--- go.mod -- 110415-module mod.com 110416- 110417-go 1.12 110418--- a.go -- 110419-package a 110420- 110421-const ( 110422- c = iota 110423-) 110424-` 110425- Run(t, src, func(t *testing.T, env *Env) { 110426- env.OpenFile("a.go") 110427- loc := env.GoToDefinition(env.RegexpSearch("a.go", "iota")) 110428- if !strings.HasSuffix(string(loc.URI), "builtin.go") { 110429- t.Fatalf("jumped to %q, want builtin.go", loc.URI) 110430- } 110431- env.AfterChange(NoDiagnostics(ForFile("builtin.go"))) 110432- }) 110433-} 110434diff -urN a/gopls/internal/regtest/diagnostics/diagnostics_test.go b/gopls/internal/regtest/diagnostics/diagnostics_test.go 110435--- a/gopls/internal/regtest/diagnostics/diagnostics_test.go 2000-01-01 00:00:00.000000000 -0000 110436+++ b/gopls/internal/regtest/diagnostics/diagnostics_test.go 1970-01-01 00:00:00.000000000 +0000 110437@@ -1,2048 +0,0 @@ 110438-// Copyright 2020 The Go Authors. All rights reserved. 110439-// Use of this source code is governed by a BSD-style 110440-// license that can be found in the LICENSE file. 110441- 110442-package diagnostics 110443- 110444-import ( 110445- "context" 110446- "fmt" 110447- "os/exec" 110448- "testing" 110449- 110450- "golang.org/x/tools/gopls/internal/hooks" 110451- "golang.org/x/tools/gopls/internal/lsp" 110452- "golang.org/x/tools/gopls/internal/lsp/fake" 110453- "golang.org/x/tools/gopls/internal/lsp/protocol" 110454- . "golang.org/x/tools/gopls/internal/lsp/regtest" 110455- "golang.org/x/tools/internal/bug" 110456- "golang.org/x/tools/internal/testenv" 110457-) 110458- 110459-func TestMain(m *testing.M) { 110460- bug.PanicOnBugs = true 110461- Main(m, hooks.Options) 110462-} 110463- 110464-// Use mod.com for all go.mod files due to golang/go#35230. 110465-const exampleProgram = ` 110466--- go.mod -- 110467-module mod.com 110468- 110469-go 1.12 110470--- main.go -- 110471-package main 110472- 110473-import "fmt" 110474- 110475-func main() { 110476- fmt.Println("Hello World.") 110477-}` 110478- 110479-func TestDiagnosticErrorInEditedFile(t *testing.T) { 110480- // This test is very basic: start with a clean Go program, make an error, and 110481- // get a diagnostic for that error. However, it also demonstrates how to 110482- // combine Expectations to await more complex state in the editor. 110483- Run(t, exampleProgram, func(t *testing.T, env *Env) { 110484- // Deleting the 'n' at the end of Println should generate a single error 110485- // diagnostic. 110486- env.OpenFile("main.go") 110487- env.RegexpReplace("main.go", "Printl(n)", "") 110488- env.AfterChange( 110489- Diagnostics(env.AtRegexp("main.go", "Printl")), 110490- // Assert that this test has sent no error logs to the client. This is not 110491- // strictly necessary for testing this regression, but is included here 110492- // as an example of using the NoErrorLogs() expectation. Feel free to 110493- // delete. 110494- NoErrorLogs(), 110495- ) 110496- }) 110497-} 110498- 110499-func TestMissingImportDiagsClearOnFirstFile(t *testing.T) { 110500- const onlyMod = ` 110501--- go.mod -- 110502-module mod.com 110503- 110504-go 1.12 110505-` 110506- Run(t, onlyMod, func(t *testing.T, env *Env) { 110507- env.CreateBuffer("main.go", `package main 110508- 110509-func m() { 110510- log.Println() 110511-} 110512-`) 110513- env.AfterChange(Diagnostics(env.AtRegexp("main.go", "log"))) 110514- env.SaveBuffer("main.go") 110515- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 110516- }) 110517-} 110518- 110519-func TestDiagnosticErrorInNewFile(t *testing.T) { 110520- const brokenFile = `package main 110521- 110522-const Foo = "abc 110523-` 110524- Run(t, brokenFile, func(t *testing.T, env *Env) { 110525- env.CreateBuffer("broken.go", brokenFile) 110526- env.AfterChange(Diagnostics(env.AtRegexp("broken.go", "\"abc"))) 110527- }) 110528-} 110529- 110530-// badPackage contains a duplicate definition of the 'a' const. 110531-const badPackage = ` 110532--- go.mod -- 110533-module mod.com 110534- 110535-go 1.12 110536--- a.go -- 110537-package consts 110538- 110539-const a = 1 110540--- b.go -- 110541-package consts 110542- 110543-const a = 2 110544-` 110545- 110546-func TestDiagnosticClearingOnEdit(t *testing.T) { 110547- Run(t, badPackage, func(t *testing.T, env *Env) { 110548- env.OpenFile("b.go") 110549- env.AfterChange( 110550- Diagnostics(env.AtRegexp("a.go", "a = 1")), 110551- Diagnostics(env.AtRegexp("b.go", "a = 2")), 110552- ) 110553- 110554- // Fix the error by editing the const name in b.go to `b`. 110555- env.RegexpReplace("b.go", "(a) = 2", "b") 110556- env.AfterChange( 110557- NoDiagnostics(ForFile("a.go")), 110558- NoDiagnostics(ForFile("b.go")), 110559- ) 110560- }) 110561-} 110562- 110563-func TestDiagnosticClearingOnDelete_Issue37049(t *testing.T) { 110564- Run(t, badPackage, func(t *testing.T, env *Env) { 110565- env.OpenFile("a.go") 110566- env.AfterChange( 110567- Diagnostics(env.AtRegexp("a.go", "a = 1")), 110568- Diagnostics(env.AtRegexp("b.go", "a = 2")), 110569- ) 110570- env.RemoveWorkspaceFile("b.go") 110571- 110572- env.AfterChange( 110573- NoDiagnostics(ForFile("a.go")), 110574- NoDiagnostics(ForFile("b.go")), 110575- ) 110576- }) 110577-} 110578- 110579-func TestDiagnosticClearingOnClose(t *testing.T) { 110580- Run(t, badPackage, func(t *testing.T, env *Env) { 110581- env.CreateBuffer("c.go", `package consts 110582- 110583-const a = 3`) 110584- env.AfterChange( 110585- Diagnostics(env.AtRegexp("a.go", "a = 1")), 110586- Diagnostics(env.AtRegexp("b.go", "a = 2")), 110587- Diagnostics(env.AtRegexp("c.go", "a = 3")), 110588- ) 110589- env.CloseBuffer("c.go") 110590- env.AfterChange( 110591- Diagnostics(env.AtRegexp("a.go", "a = 1")), 110592- Diagnostics(env.AtRegexp("b.go", "a = 2")), 110593- NoDiagnostics(ForFile("c.go")), 110594- ) 110595- }) 110596-} 110597- 110598-// Tests golang/go#37978. 110599-func TestIssue37978(t *testing.T) { 110600- Run(t, exampleProgram, func(t *testing.T, env *Env) { 110601- // Create a new workspace-level directory and empty file. 110602- env.CreateBuffer("c/c.go", "") 110603- 110604- // Write the file contents with a missing import. 110605- env.EditBuffer("c/c.go", protocol.TextEdit{ 110606- NewText: `package c 110607- 110608-const a = http.MethodGet 110609-`, 110610- }) 110611- env.AfterChange( 110612- Diagnostics(env.AtRegexp("c/c.go", "http.MethodGet")), 110613- ) 110614- // Save file, which will organize imports, adding the expected import. 110615- // Expect the diagnostics to clear. 110616- env.SaveBuffer("c/c.go") 110617- env.AfterChange( 110618- NoDiagnostics(ForFile("c/c.go")), 110619- ) 110620- }) 110621-} 110622- 110623-// Tests golang/go#38878: good a.go, bad a_test.go, remove a_test.go but its errors remain 110624-// If the file is open in the editor, this is working as intended 110625-// If the file is not open in the editor, the errors go away 110626-const test38878 = ` 110627--- go.mod -- 110628-module foo 110629- 110630-go 1.12 110631--- a.go -- 110632-package x 110633- 110634-// import "fmt" 110635- 110636-func f() {} 110637- 110638--- a_test.go -- 110639-package x 110640- 110641-import "testing" 110642- 110643-func TestA(t *testing.T) { 110644- f(3) 110645-} 110646-` 110647- 110648-// Tests golang/go#38878: deleting a test file should clear its errors, and 110649-// not break the workspace. 110650-func TestDeleteTestVariant(t *testing.T) { 110651- Run(t, test38878, func(t *testing.T, env *Env) { 110652- env.AfterChange(Diagnostics(env.AtRegexp("a_test.go", `f\((3)\)`))) 110653- env.RemoveWorkspaceFile("a_test.go") 110654- env.AfterChange(NoDiagnostics(ForFile("a_test.go"))) 110655- 110656- // Make sure the test variant has been removed from the workspace by 110657- // triggering a metadata load. 110658- env.OpenFile("a.go") 110659- env.RegexpReplace("a.go", `// import`, "import") 110660- env.AfterChange(Diagnostics(env.AtRegexp("a.go", `"fmt"`))) 110661- }) 110662-} 110663- 110664-// Tests golang/go#38878: deleting a test file on disk while it's still open 110665-// should not clear its errors. 110666-func TestDeleteTestVariant_DiskOnly(t *testing.T) { 110667- Run(t, test38878, func(t *testing.T, env *Env) { 110668- env.OpenFile("a_test.go") 110669- env.AfterChange(Diagnostics(AtPosition("a_test.go", 5, 3))) 110670- env.Sandbox.Workdir.RemoveFile(context.Background(), "a_test.go") 110671- env.AfterChange(Diagnostics(AtPosition("a_test.go", 5, 3))) 110672- }) 110673-} 110674- 110675-// TestNoMod confirms that gopls continues to work when a user adds a go.mod 110676-// file to their workspace. 110677-func TestNoMod(t *testing.T) { 110678- const noMod = ` 110679--- main.go -- 110680-package main 110681- 110682-import "mod.com/bob" 110683- 110684-func main() { 110685- bob.Hello() 110686-} 110687--- bob/bob.go -- 110688-package bob 110689- 110690-func Hello() { 110691- var x int 110692-} 110693-` 110694- 110695- t.Run("manual", func(t *testing.T) { 110696- Run(t, noMod, func(t *testing.T, env *Env) { 110697- env.OnceMet( 110698- InitialWorkspaceLoad, 110699- Diagnostics(env.AtRegexp("main.go", `"mod.com/bob"`)), 110700- ) 110701- env.CreateBuffer("go.mod", `module mod.com 110702- 110703- go 1.12 110704-`) 110705- env.SaveBuffer("go.mod") 110706- var d protocol.PublishDiagnosticsParams 110707- env.AfterChange( 110708- NoDiagnostics(ForFile("main.go")), 110709- Diagnostics(env.AtRegexp("bob/bob.go", "x")), 110710- ReadDiagnostics("bob/bob.go", &d), 110711- ) 110712- if len(d.Diagnostics) != 1 { 110713- t.Fatalf("expected 1 diagnostic, got %v", len(d.Diagnostics)) 110714- } 110715- }) 110716- }) 110717- t.Run("initialized", func(t *testing.T) { 110718- Run(t, noMod, func(t *testing.T, env *Env) { 110719- env.OnceMet( 110720- InitialWorkspaceLoad, 110721- Diagnostics(env.AtRegexp("main.go", `"mod.com/bob"`)), 110722- ) 110723- env.RunGoCommand("mod", "init", "mod.com") 110724- env.AfterChange( 110725- NoDiagnostics(ForFile("main.go")), 110726- Diagnostics(env.AtRegexp("bob/bob.go", "x")), 110727- ) 110728- }) 110729- }) 110730- 110731- t.Run("without workspace module", func(t *testing.T) { 110732- WithOptions( 110733- Modes(Default), 110734- ).Run(t, noMod, func(t *testing.T, env *Env) { 110735- env.OnceMet( 110736- InitialWorkspaceLoad, 110737- Diagnostics(env.AtRegexp("main.go", `"mod.com/bob"`)), 110738- ) 110739- if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}, true); err != nil { 110740- t.Fatal(err) 110741- } 110742- env.AfterChange( 110743- NoDiagnostics(ForFile("main.go")), 110744- Diagnostics(env.AtRegexp("bob/bob.go", "x")), 110745- ) 110746- }) 110747- }) 110748-} 110749- 110750-// Tests golang/go#38267. 110751-func TestIssue38267(t *testing.T) { 110752- const testPackage = ` 110753--- go.mod -- 110754-module mod.com 110755- 110756-go 1.12 110757--- lib.go -- 110758-package lib 110759- 110760-func Hello(x string) { 110761- _ = x 110762-} 110763--- lib_test.go -- 110764-package lib 110765- 110766-import "testing" 110767- 110768-type testStruct struct{ 110769- name string 110770-} 110771- 110772-func TestHello(t *testing.T) { 110773- testStructs := []*testStruct{ 110774- &testStruct{"hello"}, 110775- &testStruct{"goodbye"}, 110776- } 110777- for y := range testStructs { 110778- _ = y 110779- } 110780-} 110781-` 110782- 110783- Run(t, testPackage, func(t *testing.T, env *Env) { 110784- env.OpenFile("lib_test.go") 110785- env.AfterChange( 110786- Diagnostics(AtPosition("lib_test.go", 10, 2)), 110787- Diagnostics(AtPosition("lib_test.go", 11, 2)), 110788- ) 110789- env.OpenFile("lib.go") 110790- env.RegexpReplace("lib.go", "_ = x", "var y int") 110791- env.AfterChange( 110792- Diagnostics(env.AtRegexp("lib.go", "y int")), 110793- NoDiagnostics(ForFile("lib_test.go")), 110794- ) 110795- }) 110796-} 110797- 110798-// Tests golang/go#38328. 110799-func TestPackageChange_Issue38328(t *testing.T) { 110800- const packageChange = ` 110801--- go.mod -- 110802-module fake 110803- 110804-go 1.12 110805--- a.go -- 110806-package foo 110807-func main() {} 110808-` 110809- Run(t, packageChange, func(t *testing.T, env *Env) { 110810- env.OpenFile("a.go") 110811- env.RegexpReplace("a.go", "foo", "foox") 110812- env.AfterChange( 110813- NoDiagnostics(ForFile("a.go")), 110814- ) 110815- }) 110816-} 110817- 110818-const testPackageWithRequire = ` 110819--- go.mod -- 110820-module mod.com 110821- 110822-go 1.12 110823- 110824-require foo.test v1.2.3 110825--- go.sum -- 110826-foo.test v1.2.3 h1:TMA+lyd1ck0TqjSFpNe4T6cf/K6TYkoHwOOcMBMjaEw= 110827-foo.test v1.2.3/go.mod h1:Ij3kyLIe5lzjycjh13NL8I2gX0quZuTdW0MnmlwGBL4= 110828--- print.go -- 110829-package lib 110830- 110831-import ( 110832- "fmt" 110833- 110834- "foo.test/bar" 110835-) 110836- 110837-func PrintAnswer() { 110838- fmt.Printf("answer: %s", bar.Answer) 110839-} 110840-` 110841- 110842-const testPackageWithRequireProxy = ` 110843--- [email protected]/go.mod -- 110844-module foo.test 110845- 110846-go 1.12 110847--- [email protected]/bar/const.go -- 110848-package bar 110849- 110850-const Answer = 42 110851-` 110852- 110853-func TestResolveDiagnosticWithDownload(t *testing.T) { 110854- WithOptions( 110855- ProxyFiles(testPackageWithRequireProxy), 110856- ).Run(t, testPackageWithRequire, func(t *testing.T, env *Env) { 110857- env.OpenFile("print.go") 110858- // Check that gopackages correctly loaded this dependency. We should get a 110859- // diagnostic for the wrong formatting type. 110860- env.AfterChange( 110861- Diagnostics( 110862- env.AtRegexp("print.go", "fmt.Printf"), 110863- WithMessage("wrong type int"), 110864- ), 110865- ) 110866- }) 110867-} 110868- 110869-func TestMissingDependency(t *testing.T) { 110870- Run(t, testPackageWithRequire, func(t *testing.T, env *Env) { 110871- env.OpenFile("print.go") 110872- env.Await(LogMatching(protocol.Error, "initial workspace load failed", 1, false)) 110873- }) 110874-} 110875- 110876-// Tests golang/go#36951. 110877-func TestAdHocPackages_Issue36951(t *testing.T) { 110878- const adHoc = ` 110879--- b/b.go -- 110880-package b 110881- 110882-func Hello() { 110883- var x int 110884-} 110885-` 110886- Run(t, adHoc, func(t *testing.T, env *Env) { 110887- env.OpenFile("b/b.go") 110888- env.AfterChange( 110889- Diagnostics(env.AtRegexp("b/b.go", "x")), 110890- ) 110891- }) 110892-} 110893- 110894-// Tests golang/go#37984: GOPATH should be read from the go command. 110895-func TestNoGOPATH_Issue37984(t *testing.T) { 110896- const files = ` 110897--- main.go -- 110898-package main 110899- 110900-func _() { 110901- fmt.Println("Hello World") 110902-} 110903-` 110904- WithOptions( 110905- EnvVars{ 110906- "GOPATH": "", 110907- "GO111MODULE": "off", 110908- }, 110909- ).Run(t, files, func(t *testing.T, env *Env) { 110910- env.OpenFile("main.go") 110911- env.AfterChange(Diagnostics(env.AtRegexp("main.go", "fmt"))) 110912- env.SaveBuffer("main.go") 110913- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 110914- }) 110915-} 110916- 110917-// Tests golang/go#38669. 110918-func TestEqualInEnv_Issue38669(t *testing.T) { 110919- const files = ` 110920--- go.mod -- 110921-module mod.com 110922- 110923-go 1.12 110924--- main.go -- 110925-package main 110926- 110927-var _ = x.X 110928--- x/x.go -- 110929-package x 110930- 110931-var X = 0 110932-` 110933- WithOptions( 110934- EnvVars{"GOFLAGS": "-tags=foo"}, 110935- ).Run(t, files, func(t *testing.T, env *Env) { 110936- env.OpenFile("main.go") 110937- env.OrganizeImports("main.go") 110938- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 110939- }) 110940-} 110941- 110942-// Tests golang/go#38467. 110943-func TestNoSuggestedFixesForGeneratedFiles_Issue38467(t *testing.T) { 110944- const generated = ` 110945--- go.mod -- 110946-module mod.com 110947- 110948-go 1.12 110949--- main.go -- 110950-package main 110951- 110952-// Code generated by generator.go. DO NOT EDIT. 110953- 110954-func _() { 110955- for i, _ := range []string{} { 110956- _ = i 110957- } 110958-} 110959-` 110960- Run(t, generated, func(t *testing.T, env *Env) { 110961- env.OpenFile("main.go") 110962- var d protocol.PublishDiagnosticsParams 110963- env.AfterChange( 110964- Diagnostics(AtPosition("main.go", 5, 8)), 110965- ReadDiagnostics("main.go", &d), 110966- ) 110967- if fixes := env.GetQuickFixes("main.go", d.Diagnostics); len(fixes) != 0 { 110968- t.Errorf("got quick fixes %v, wanted none", fixes) 110969- } 110970- }) 110971-} 110972- 110973-// Expect a module/GOPATH error if there is an error in the file at startup. 110974-// Tests golang/go#37279. 110975-func TestBrokenWorkspace_OutsideModule(t *testing.T) { 110976- const noModule = ` 110977--- a.go -- 110978-package foo 110979- 110980-import "mod.com/hello" 110981- 110982-func f() { 110983- hello.Goodbye() 110984-} 110985-` 110986- Run(t, noModule, func(t *testing.T, env *Env) { 110987- env.OpenFile("a.go") 110988- env.AfterChange( 110989- // Expect the adHocPackagesWarning. 110990- OutstandingWork(lsp.WorkspaceLoadFailure, "outside of a module"), 110991- ) 110992- // Deleting the import dismisses the warning. 110993- env.RegexpReplace("a.go", `import "mod.com/hello"`, "") 110994- env.AfterChange( 110995- NoOutstandingWork(), 110996- ) 110997- }) 110998-} 110999- 111000-func TestNonGoFolder(t *testing.T) { 111001- const files = ` 111002--- hello.txt -- 111003-hi mom 111004-` 111005- for _, go111module := range []string{"on", "off", ""} { 111006- t.Run(fmt.Sprintf("GO111MODULE_%v", go111module), func(t *testing.T) { 111007- WithOptions( 111008- EnvVars{"GO111MODULE": go111module}, 111009- ).Run(t, files, func(t *testing.T, env *Env) { 111010- env.OnceMet( 111011- InitialWorkspaceLoad, 111012- NoOutstandingWork(), 111013- ) 111014- }) 111015- }) 111016- } 111017-} 111018- 111019-// Tests the repro case from golang/go#38602. Diagnostics are now handled properly, 111020-// which blocks type checking. 111021-func TestConflictingMainPackageErrors(t *testing.T) { 111022- const collision = ` 111023--- x/x.go -- 111024-package x 111025- 111026-import "x/hello" 111027- 111028-func Hello() { 111029- hello.HiThere() 111030-} 111031--- x/main.go -- 111032-package main 111033- 111034-func main() { 111035- fmt.Println("") 111036-} 111037-` 111038- WithOptions( 111039- InGOPATH(), 111040- EnvVars{"GO111MODULE": "off"}, 111041- ).Run(t, collision, func(t *testing.T, env *Env) { 111042- env.OpenFile("x/x.go") 111043- env.AfterChange( 111044- Diagnostics(env.AtRegexp("x/x.go", `^`), WithMessage("found packages main (main.go) and x (x.go)")), 111045- Diagnostics(env.AtRegexp("x/main.go", `^`), WithMessage("found packages main (main.go) and x (x.go)")), 111046- ) 111047- 111048- // We don't recover cleanly from the errors without good overlay support. 111049- if testenv.Go1Point() >= 16 { 111050- env.RegexpReplace("x/x.go", `package x`, `package main`) 111051- env.AfterChange( 111052- Diagnostics(env.AtRegexp("x/main.go", `fmt`)), 111053- ) 111054- } 111055- }) 111056-} 111057- 111058-const ardanLabsProxy = ` 111059--- github.com/ardanlabs/conf@v1.2.3/go.mod -- 111060-module github.com/ardanlabs/conf 111061- 111062-go 1.12 111063--- github.com/ardanlabs/conf@v1.2.3/conf.go -- 111064-package conf 111065- 111066-var ErrHelpWanted error 111067-` 111068- 111069-// Test for golang/go#38211. 111070-func Test_Issue38211(t *testing.T) { 111071- const ardanLabs = ` 111072--- go.mod -- 111073-module mod.com 111074- 111075-go 1.14 111076--- main.go -- 111077-package main 111078- 111079-import "github.com/ardanlabs/conf" 111080- 111081-func main() { 111082- _ = conf.ErrHelpWanted 111083-} 111084-` 111085- WithOptions( 111086- ProxyFiles(ardanLabsProxy), 111087- ).Run(t, ardanLabs, func(t *testing.T, env *Env) { 111088- // Expect a diagnostic with a suggested fix to add 111089- // "github.com/ardanlabs/conf" to the go.mod file. 111090- env.OpenFile("go.mod") 111091- env.OpenFile("main.go") 111092- var d protocol.PublishDiagnosticsParams 111093- env.AfterChange( 111094- Diagnostics(env.AtRegexp("main.go", `"github.com/ardanlabs/conf"`)), 111095- ReadDiagnostics("main.go", &d), 111096- ) 111097- env.ApplyQuickFixes("main.go", d.Diagnostics) 111098- env.SaveBuffer("go.mod") 111099- env.AfterChange( 111100- NoDiagnostics(ForFile("main.go")), 111101- ) 111102- // Comment out the line that depends on conf and expect a 111103- // diagnostic and a fix to remove the import. 111104- env.RegexpReplace("main.go", "_ = conf.ErrHelpWanted", "//_ = conf.ErrHelpWanted") 111105- env.AfterChange( 111106- Diagnostics(env.AtRegexp("main.go", `"github.com/ardanlabs/conf"`)), 111107- ) 111108- env.SaveBuffer("main.go") 111109- // Expect a diagnostic and fix to remove the dependency in the go.mod. 111110- env.AfterChange( 111111- NoDiagnostics(ForFile("main.go")), 111112- Diagnostics(env.AtRegexp("go.mod", "require github.com/ardanlabs/conf"), WithMessage("not used in this module")), 111113- ReadDiagnostics("go.mod", &d), 111114- ) 111115- env.ApplyQuickFixes("go.mod", d.Diagnostics) 111116- env.SaveBuffer("go.mod") 111117- env.AfterChange( 111118- NoDiagnostics(ForFile("go.mod")), 111119- ) 111120- // Uncomment the lines and expect a new diagnostic for the import. 111121- env.RegexpReplace("main.go", "//_ = conf.ErrHelpWanted", "_ = conf.ErrHelpWanted") 111122- env.SaveBuffer("main.go") 111123- env.AfterChange( 111124- Diagnostics(env.AtRegexp("main.go", `"github.com/ardanlabs/conf"`)), 111125- ) 111126- }) 111127-} 111128- 111129-// Test for golang/go#38207. 111130-func TestNewModule_Issue38207(t *testing.T) { 111131- const emptyFile = ` 111132--- go.mod -- 111133-module mod.com 111134- 111135-go 1.12 111136--- main.go -- 111137-` 111138- WithOptions( 111139- ProxyFiles(ardanLabsProxy), 111140- ).Run(t, emptyFile, func(t *testing.T, env *Env) { 111141- env.CreateBuffer("main.go", `package main 111142- 111143-import "github.com/ardanlabs/conf" 111144- 111145-func main() { 111146- _ = conf.ErrHelpWanted 111147-} 111148-`) 111149- env.SaveBuffer("main.go") 111150- var d protocol.PublishDiagnosticsParams 111151- env.AfterChange( 111152- Diagnostics(env.AtRegexp("main.go", `"github.com/ardanlabs/conf"`), WithMessage("no required module")), 111153- ReadDiagnostics("main.go", &d), 111154- ) 111155- env.ApplyQuickFixes("main.go", d.Diagnostics) 111156- env.AfterChange( 111157- NoDiagnostics(ForFile("main.go")), 111158- ) 111159- }) 111160-} 111161- 111162-// Test for golang/go#36960. 111163-func TestNewFileBadImports_Issue36960(t *testing.T) { 111164- const simplePackage = ` 111165--- go.mod -- 111166-module mod.com 111167- 111168-go 1.14 111169--- a/a1.go -- 111170-package a 111171- 111172-import "fmt" 111173- 111174-func _() { 111175- fmt.Println("hi") 111176-} 111177-` 111178- Run(t, simplePackage, func(t *testing.T, env *Env) { 111179- env.OpenFile("a/a1.go") 111180- env.CreateBuffer("a/a2.go", ``) 111181- env.SaveBufferWithoutActions("a/a2.go") 111182- env.AfterChange( 111183- NoDiagnostics(ForFile("a/a1.go")), 111184- ) 111185- env.EditBuffer("a/a2.go", fake.NewEdit(0, 0, 0, 0, `package a`)) 111186- env.AfterChange( 111187- NoDiagnostics(ForFile("a/a1.go")), 111188- ) 111189- }) 111190-} 111191- 111192-// This test tries to replicate the workflow of a user creating a new x test. 111193-// It also tests golang/go#39315. 111194-func TestManuallyCreatingXTest(t *testing.T) { 111195- // Create a package that already has a test variant (in-package test). 111196- const testVariant = ` 111197--- go.mod -- 111198-module mod.com 111199- 111200-go 1.15 111201--- hello/hello.go -- 111202-package hello 111203- 111204-func Hello() { 111205- var x int 111206-} 111207--- hello/hello_test.go -- 111208-package hello 111209- 111210-import "testing" 111211- 111212-func TestHello(t *testing.T) { 111213- var x int 111214- Hello() 111215-} 111216-` 111217- Run(t, testVariant, func(t *testing.T, env *Env) { 111218- // Open the file, triggering the workspace load. 111219- // There are errors in the code to ensure all is working as expected. 111220- env.OpenFile("hello/hello.go") 111221- env.AfterChange( 111222- Diagnostics(env.AtRegexp("hello/hello.go", "x")), 111223- Diagnostics(env.AtRegexp("hello/hello_test.go", "x")), 111224- ) 111225- 111226- // Create an empty file with the intention of making it an x test. 111227- // This resembles a typical flow in an editor like VS Code, in which 111228- // a user would create an empty file and add content, saving 111229- // intermittently. 111230- // TODO(rstambler): There might be more edge cases here, as file 111231- // content can be added incrementally. 111232- env.CreateBuffer("hello/hello_x_test.go", ``) 111233- 111234- // Save the empty file (no actions since formatting will fail). 111235- env.SaveBufferWithoutActions("hello/hello_x_test.go") 111236- 111237- // Add the content. The missing import is for the package under test. 111238- env.EditBuffer("hello/hello_x_test.go", fake.NewEdit(0, 0, 0, 0, `package hello_test 111239- 111240-import ( 111241- "testing" 111242-) 111243- 111244-func TestHello(t *testing.T) { 111245- hello.Hello() 111246-} 111247-`)) 111248- // Expect a diagnostic for the missing import. Save, which should 111249- // trigger import organization. The diagnostic should clear. 111250- env.AfterChange( 111251- Diagnostics(env.AtRegexp("hello/hello_x_test.go", "hello.Hello")), 111252- ) 111253- env.SaveBuffer("hello/hello_x_test.go") 111254- env.AfterChange( 111255- NoDiagnostics(ForFile("hello/hello_x_test.go")), 111256- ) 111257- }) 111258-} 111259- 111260-// Reproduce golang/go#40690. 111261-func TestCreateOnlyXTest(t *testing.T) { 111262- const mod = ` 111263--- go.mod -- 111264-module mod.com 111265- 111266-go 1.12 111267--- foo/foo.go -- 111268-package foo 111269--- foo/bar_test.go -- 111270-` 111271- Run(t, mod, func(t *testing.T, env *Env) { 111272- env.OpenFile("foo/bar_test.go") 111273- env.EditBuffer("foo/bar_test.go", fake.NewEdit(0, 0, 0, 0, "package foo")) 111274- env.Await(env.DoneWithChange()) 111275- env.RegexpReplace("foo/bar_test.go", "package foo", `package foo_test 111276- 111277-import "testing" 111278- 111279-func TestX(t *testing.T) { 111280- var x int 111281-} 111282-`) 111283- env.AfterChange( 111284- Diagnostics(env.AtRegexp("foo/bar_test.go", "x")), 111285- ) 111286- }) 111287-} 111288- 111289-func TestChangePackageName(t *testing.T) { 111290- const mod = ` 111291--- go.mod -- 111292-module mod.com 111293- 111294-go 1.12 111295--- foo/foo.go -- 111296-package foo 111297--- foo/bar_test.go -- 111298-package foo_ 111299-` 111300- Run(t, mod, func(t *testing.T, env *Env) { 111301- env.OpenFile("foo/bar_test.go") 111302- env.AfterChange() 111303- env.RegexpReplace("foo/bar_test.go", "package foo_", "package foo_test") 111304- env.AfterChange( 111305- NoDiagnostics(ForFile("foo/bar_test.go")), 111306- NoDiagnostics(ForFile("foo/foo.go")), 111307- ) 111308- }) 111309-} 111310- 111311-func TestIgnoredFiles(t *testing.T) { 111312- const ws = ` 111313--- go.mod -- 111314-module mod.com 111315- 111316-go 1.12 111317--- _foo/x.go -- 111318-package x 111319- 111320-var _ = foo.Bar 111321-` 111322- Run(t, ws, func(t *testing.T, env *Env) { 111323- env.OpenFile("_foo/x.go") 111324- env.AfterChange( 111325- NoDiagnostics(ForFile("_foo/x.go")), 111326- ) 111327- }) 111328-} 111329- 111330-// Partially reproduces golang/go#38977, moving a file between packages. 111331-// It also gets hit by some go command bug fixed in 1.15, but we don't 111332-// care about that so much here. 111333-func TestDeletePackage(t *testing.T) { 111334- const ws = ` 111335--- go.mod -- 111336-module mod.com 111337- 111338-go 1.15 111339--- a/a.go -- 111340-package a 111341- 111342-const A = 1 111343- 111344--- b/b.go -- 111345-package b 111346- 111347-import "mod.com/a" 111348- 111349-const B = a.A 111350- 111351--- c/c.go -- 111352-package c 111353- 111354-import "mod.com/a" 111355- 111356-const C = a.A 111357-` 111358- Run(t, ws, func(t *testing.T, env *Env) { 111359- env.OpenFile("b/b.go") 111360- env.Await(env.DoneWithOpen()) 111361- // Delete c/c.go, the only file in package c. 111362- env.RemoveWorkspaceFile("c/c.go") 111363- 111364- // We should still get diagnostics for files that exist. 111365- env.RegexpReplace("b/b.go", `a.A`, "a.Nonexistant") 111366- env.AfterChange( 111367- Diagnostics(env.AtRegexp("b/b.go", `Nonexistant`)), 111368- ) 111369- }) 111370-} 111371- 111372-// This is a copy of the scenario_default/quickfix_empty_files.txt test from 111373-// govim. Reproduces golang/go#39646. 111374-func TestQuickFixEmptyFiles(t *testing.T) { 111375- const mod = ` 111376--- go.mod -- 111377-module mod.com 111378- 111379-go 1.12 111380-` 111381- // To fully recreate the govim tests, we create files by inserting 111382- // a newline, adding to the file, and then deleting the newline. 111383- // Wait for each event to process to avoid cancellations and force 111384- // package loads. 111385- writeGoVim := func(env *Env, name, content string) { 111386- env.WriteWorkspaceFile(name, "") 111387- env.Await(env.DoneWithChangeWatchedFiles()) 111388- 111389- env.CreateBuffer(name, "\n") 111390- env.Await(env.DoneWithOpen()) 111391- 111392- env.EditBuffer(name, fake.NewEdit(1, 0, 1, 0, content)) 111393- env.Await(env.DoneWithChange()) 111394- 111395- env.EditBuffer(name, fake.NewEdit(0, 0, 1, 0, "")) 111396- env.Await(env.DoneWithChange()) 111397- } 111398- 111399- const p = `package p; func DoIt(s string) {};` 111400- const main = `package main 111401- 111402-import "mod.com/p" 111403- 111404-func main() { 111405- p.DoIt(5) 111406-} 111407-` 111408- // A simple version of the test that reproduces most of the problems it 111409- // exposes. 111410- t.Run("short", func(t *testing.T) { 111411- Run(t, mod, func(t *testing.T, env *Env) { 111412- writeGoVim(env, "p/p.go", p) 111413- writeGoVim(env, "main.go", main) 111414- env.AfterChange( 111415- Diagnostics(env.AtRegexp("main.go", "5")), 111416- ) 111417- }) 111418- }) 111419- 111420- // A full version that replicates the whole flow of the test. 111421- t.Run("full", func(t *testing.T) { 111422- Run(t, mod, func(t *testing.T, env *Env) { 111423- writeGoVim(env, "p/p.go", p) 111424- writeGoVim(env, "main.go", main) 111425- writeGoVim(env, "p/p_test.go", `package p 111426- 111427-import "testing" 111428- 111429-func TestDoIt(t *testing.T) { 111430- DoIt(5) 111431-} 111432-`) 111433- writeGoVim(env, "p/x_test.go", `package p_test 111434- 111435-import ( 111436- "testing" 111437- 111438- "mod.com/p" 111439-) 111440- 111441-func TestDoIt(t *testing.T) { 111442- p.DoIt(5) 111443-} 111444-`) 111445- env.AfterChange( 111446- Diagnostics(env.AtRegexp("main.go", "5")), 111447- Diagnostics(env.AtRegexp("p/p_test.go", "5")), 111448- Diagnostics(env.AtRegexp("p/x_test.go", "5")), 111449- ) 111450- env.RegexpReplace("p/p.go", "s string", "i int") 111451- env.AfterChange( 111452- NoDiagnostics(ForFile("main.go")), 111453- NoDiagnostics(ForFile("p/p_test.go")), 111454- NoDiagnostics(ForFile("p/x_test.go")), 111455- ) 111456- }) 111457- }) 111458-} 111459- 111460-func TestSingleFile(t *testing.T) { 111461- const mod = ` 111462--- go.mod -- 111463-module mod.com 111464- 111465-go 1.13 111466--- a/a.go -- 111467-package a 111468- 111469-func _() { 111470- var x int 111471-} 111472-` 111473- WithOptions( 111474- // Empty workspace folders. 111475- WorkspaceFolders(), 111476- ).Run(t, mod, func(t *testing.T, env *Env) { 111477- env.OpenFile("a/a.go") 111478- env.AfterChange( 111479- Diagnostics(env.AtRegexp("a/a.go", "x")), 111480- ) 111481- }) 111482-} 111483- 111484-// Reproduces the case described in 111485-// https://github.com/golang/go/issues/39296#issuecomment-652058883. 111486-func TestPkgm(t *testing.T) { 111487- const basic = ` 111488--- go.mod -- 111489-module mod.com 111490- 111491-go 1.15 111492--- foo/foo.go -- 111493-package foo 111494- 111495-import "fmt" 111496- 111497-func Foo() { 111498- fmt.Println("") 111499-} 111500-` 111501- Run(t, basic, func(t *testing.T, env *Env) { 111502- env.WriteWorkspaceFile("foo/foo_test.go", `package main 111503- 111504-func main() { 111505- 111506-}`) 111507- env.OpenFile("foo/foo_test.go") 111508- env.RegexpReplace("foo/foo_test.go", `package main`, `package foo`) 111509- env.AfterChange(NoDiagnostics(ForFile("foo/foo.go"))) 111510- }) 111511-} 111512- 111513-func TestClosingBuffer(t *testing.T) { 111514- const basic = ` 111515--- go.mod -- 111516-module mod.com 111517- 111518-go 1.14 111519--- main.go -- 111520-package main 111521- 111522-func main() {} 111523-` 111524- Run(t, basic, func(t *testing.T, env *Env) { 111525- env.Editor.CreateBuffer(env.Ctx, "foo.go", `package main`) 111526- env.AfterChange() 111527- env.CloseBuffer("foo.go") 111528- env.AfterChange(NoLogMatching(protocol.Info, "packages=0")) 111529- }) 111530-} 111531- 111532-// Reproduces golang/go#38424. 111533-func TestCutAndPaste(t *testing.T) { 111534- const basic = ` 111535--- go.mod -- 111536-module mod.com 111537- 111538-go 1.14 111539--- main2.go -- 111540-package main 111541-` 111542- Run(t, basic, func(t *testing.T, env *Env) { 111543- env.CreateBuffer("main.go", "") 111544- env.Await(env.DoneWithOpen()) 111545- 111546- env.SaveBufferWithoutActions("main.go") 111547- env.Await(env.DoneWithSave(), env.DoneWithChangeWatchedFiles()) 111548- 111549- env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main 111550- 111551-func main() { 111552-} 111553-`)) 111554- env.Await(env.DoneWithChange()) 111555- 111556- env.SaveBuffer("main.go") 111557- env.Await(env.DoneWithSave(), env.DoneWithChangeWatchedFiles()) 111558- 111559- env.EditBuffer("main.go", fake.NewEdit(0, 0, 4, 0, "")) 111560- env.Await(env.DoneWithChange()) 111561- 111562- env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main 111563- 111564-func main() { 111565- var x int 111566-} 111567-`)) 111568- env.AfterChange( 111569- Diagnostics(env.AtRegexp("main.go", "x")), 111570- ) 111571- }) 111572-} 111573- 111574-// Reproduces golang/go#39763. 111575-func TestInvalidPackageName(t *testing.T) { 111576- const pkgDefault = ` 111577--- go.mod -- 111578-module mod.com 111579- 111580-go 1.12 111581--- main.go -- 111582-package default 111583- 111584-func main() {} 111585-` 111586- Run(t, pkgDefault, func(t *testing.T, env *Env) { 111587- env.OpenFile("main.go") 111588- env.AfterChange( 111589- Diagnostics( 111590- env.AtRegexp("main.go", "default"), 111591- WithMessage("expected 'IDENT'"), 111592- ), 111593- ) 111594- }) 111595-} 111596- 111597-// This tests the functionality of the "limitWorkspaceScope" 111598-func TestLimitWorkspaceScope(t *testing.T) { 111599- const mod = ` 111600--- go.mod -- 111601-module mod.com 111602- 111603-go 1.12 111604--- a/main.go -- 111605-package main 111606- 111607-func main() {} 111608--- main.go -- 111609-package main 111610- 111611-func main() { 111612- var x int 111613-} 111614-` 111615- WithOptions( 111616- WorkspaceFolders("a"), 111617- ).Run(t, mod, func(t *testing.T, env *Env) { 111618- env.OpenFile("a/main.go") 111619- env.AfterChange( 111620- Diagnostics(env.AtRegexp("main.go", "x")), 111621- ) 111622- }) 111623- WithOptions( 111624- WorkspaceFolders("a"), 111625- Settings{"expandWorkspaceToModule": false}, 111626- ).Run(t, mod, func(t *testing.T, env *Env) { 111627- env.OpenFile("a/main.go") 111628- env.AfterChange( 111629- NoDiagnostics(ForFile("main.go")), 111630- ) 111631- }) 111632-} 111633- 111634-func TestSimplifyCompositeLitDiagnostic(t *testing.T) { 111635- const files = ` 111636--- go.mod -- 111637-module mod.com 111638- 111639-go 1.12 111640--- main.go -- 111641-package main 111642- 111643-import "fmt" 111644- 111645-type t struct { 111646- msg string 111647-} 111648- 111649-func main() { 111650- x := []t{t{"msg"}} 111651- fmt.Println(x) 111652-} 111653-` 111654- 111655- WithOptions( 111656- Settings{"staticcheck": true}, 111657- ).Run(t, files, func(t *testing.T, env *Env) { 111658- env.OpenFile("main.go") 111659- var d protocol.PublishDiagnosticsParams 111660- env.AfterChange( 111661- Diagnostics(env.AtRegexp("main.go", `t{"msg"}`), WithMessage("redundant type")), 111662- ReadDiagnostics("main.go", &d), 111663- ) 111664- if tags := d.Diagnostics[0].Tags; len(tags) == 0 || tags[0] != protocol.Unnecessary { 111665- t.Errorf("wanted Unnecessary tag on diagnostic, got %v", tags) 111666- } 111667- env.ApplyQuickFixes("main.go", d.Diagnostics) 111668- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 111669- }) 111670-} 111671- 111672-// Test some secondary diagnostics 111673-func TestSecondaryDiagnostics(t *testing.T) { 111674- const dir = ` 111675--- go.mod -- 111676-module mod.com 111677- 111678-go 1.12 111679--- main.go -- 111680-package main 111681-func main() { 111682- panic("not here") 111683-} 111684--- other.go -- 111685-package main 111686-func main() {} 111687-` 111688- Run(t, dir, func(t *testing.T, env *Env) { 111689- env.OpenFile("main.go") 111690- env.OpenFile("other.go") 111691- var mainDiags, otherDiags protocol.PublishDiagnosticsParams 111692- env.AfterChange( 111693- ReadDiagnostics("main.go", &mainDiags), 111694- ReadDiagnostics("other.go", &otherDiags), 111695- ) 111696- if len(mainDiags.Diagnostics) != 1 { 111697- t.Fatalf("main.go, got %d diagnostics, expected 1", len(mainDiags.Diagnostics)) 111698- } 111699- keep := mainDiags.Diagnostics[0] 111700- if len(otherDiags.Diagnostics) != 1 { 111701- t.Fatalf("other.go: got %d diagnostics, expected 1", len(otherDiags.Diagnostics)) 111702- } 111703- if len(otherDiags.Diagnostics[0].RelatedInformation) != 1 { 111704- t.Fatalf("got %d RelatedInformations, expected 1", len(otherDiags.Diagnostics[0].RelatedInformation)) 111705- } 111706- // check that the RelatedInformation matches the error from main.go 111707- c := otherDiags.Diagnostics[0].RelatedInformation[0] 111708- if c.Location.Range != keep.Range { 111709- t.Errorf("locations don't match. Got %v expected %v", c.Location.Range, keep.Range) 111710- } 111711- }) 111712-} 111713- 111714-func TestNotifyOrphanedFiles(t *testing.T) { 111715- const files = ` 111716--- go.mod -- 111717-module mod.com 111718- 111719-go 1.12 111720--- a/a.go -- 111721-package a 111722- 111723-func main() { 111724- var x int 111725-} 111726--- a/a_exclude.go -- 111727-// +build exclude 111728- 111729-package a 111730- 111731-func _() { 111732- var x int 111733-} 111734-` 111735- Run(t, files, func(t *testing.T, env *Env) { 111736- env.OpenFile("a/a.go") 111737- env.AfterChange( 111738- Diagnostics(env.AtRegexp("a/a.go", "x")), 111739- ) 111740- env.OpenFile("a/a_exclude.go") 111741- env.AfterChange( 111742- Diagnostics(env.AtRegexp("a/a_exclude.go", "package (a)")), 111743- ) 111744- }) 111745-} 111746- 111747-func TestEnableAllExperiments(t *testing.T) { 111748- // Before the oldest supported Go version, gopls sends a warning to upgrade 111749- // Go, which fails the expectation below. 111750- testenv.NeedsGo1Point(t, lsp.OldestSupportedGoVersion()) 111751- 111752- const mod = ` 111753--- go.mod -- 111754-module mod.com 111755- 111756-go 1.12 111757--- main.go -- 111758-package main 111759- 111760-import "bytes" 111761- 111762-func b(c bytes.Buffer) { 111763- _ = 1 111764-} 111765-` 111766- WithOptions( 111767- Settings{"allExperiments": true}, 111768- ).Run(t, mod, func(t *testing.T, env *Env) { 111769- // Confirm that the setting doesn't cause any warnings. 111770- env.OnceMet( 111771- InitialWorkspaceLoad, 111772- NoShownMessage(""), // empty substring to match any message 111773- ) 111774- }) 111775-} 111776- 111777-func TestSwig(t *testing.T) { 111778- // This is fixed in Go 1.17, but not earlier. 111779- testenv.NeedsGo1Point(t, 17) 111780- 111781- if _, err := exec.LookPath("swig"); err != nil { 111782- t.Skip("skipping test: swig not available") 111783- } 111784- if _, err := exec.LookPath("g++"); err != nil { 111785- t.Skip("skipping test: g++ not available") 111786- } 111787- 111788- const mod = ` 111789--- go.mod -- 111790-module mod.com 111791- 111792-go 1.12 111793--- pkg/simple/export_swig.go -- 111794-package simple 111795- 111796-func ExportSimple(x, y int) int { 111797- return Gcd(x, y) 111798-} 111799--- pkg/simple/simple.swigcxx -- 111800-%module simple 111801- 111802-%inline %{ 111803-extern int gcd(int x, int y) 111804-{ 111805- int g; 111806- g = y; 111807- while (x > 0) { 111808- g = x; 111809- x = y % x; 111810- y = g; 111811- } 111812- return g; 111813-} 111814-%} 111815--- main.go -- 111816-package a 111817- 111818-func main() { 111819- var x int 111820-} 111821-` 111822- Run(t, mod, func(t *testing.T, env *Env) { 111823- env.OnceMet( 111824- InitialWorkspaceLoad, 111825- NoDiagnostics(WithMessage("illegal character U+0023 '#'")), 111826- ) 111827- }) 111828-} 111829- 111830-// When foo_test.go is opened, gopls will object to the borked package name. 111831-// This test asserts that when the package name is fixed, gopls will soon after 111832-// have no more complaints about it. 111833-// https://github.com/golang/go/issues/41061 111834-func TestRenamePackage(t *testing.T) { 111835- const proxy = ` 111836--- [email protected]/go.mod -- 111837-module example.com 111838- 111839-go 1.12 111840--- [email protected]/blah/blah.go -- 111841-package blah 111842- 111843-const Name = "Blah" 111844--- [email protected]/go.mod -- 111845-module random.org 111846- 111847-go 1.12 111848--- [email protected]/blah/blah.go -- 111849-package hello 111850- 111851-const Name = "Hello" 111852-` 111853- 111854- const contents = ` 111855--- go.mod -- 111856-module mod.com 111857- 111858-go 1.12 111859--- main.go -- 111860-package main 111861- 111862-import "example.com/blah" 111863- 111864-func main() { 111865- blah.Hello() 111866-} 111867--- bob.go -- 111868-package main 111869--- foo/foo.go -- 111870-package foo 111871--- foo/foo_test.go -- 111872-package foo_ 111873-` 111874- 111875- WithOptions( 111876- ProxyFiles(proxy), 111877- InGOPATH(), 111878- EnvVars{"GO111MODULE": "off"}, 111879- ).Run(t, contents, func(t *testing.T, env *Env) { 111880- // Simulate typing character by character. 111881- env.OpenFile("foo/foo_test.go") 111882- env.Await(env.DoneWithOpen()) 111883- env.RegexpReplace("foo/foo_test.go", "_", "_t") 111884- env.Await(env.DoneWithChange()) 111885- env.RegexpReplace("foo/foo_test.go", "_t", "_test") 111886- env.AfterChange( 111887- NoDiagnostics(ForFile("foo/foo_test.go")), 111888- NoOutstandingWork(), 111889- ) 111890- }) 111891-} 111892- 111893-// TestProgressBarErrors confirms that critical workspace load errors are shown 111894-// and updated via progress reports. 111895-func TestProgressBarErrors(t *testing.T) { 111896- const pkg = ` 111897--- go.mod -- 111898-modul mod.com 111899- 111900-go 1.12 111901--- main.go -- 111902-package main 111903-` 111904- Run(t, pkg, func(t *testing.T, env *Env) { 111905- env.OpenFile("go.mod") 111906- env.AfterChange( 111907- OutstandingWork(lsp.WorkspaceLoadFailure, "unknown directive"), 111908- ) 111909- env.EditBuffer("go.mod", fake.NewEdit(0, 0, 3, 0, `module mod.com 111910- 111911-go 1.hello 111912-`)) 111913- // As of golang/go#42529, go.mod changes do not reload the workspace until 111914- // they are saved. 111915- env.SaveBufferWithoutActions("go.mod") 111916- env.AfterChange( 111917- OutstandingWork(lsp.WorkspaceLoadFailure, "invalid go version"), 111918- ) 111919- env.RegexpReplace("go.mod", "go 1.hello", "go 1.12") 111920- env.SaveBufferWithoutActions("go.mod") 111921- env.AfterChange( 111922- NoOutstandingWork(), 111923- ) 111924- }) 111925-} 111926- 111927-func TestDeleteDirectory(t *testing.T) { 111928- const mod = ` 111929--- bob/bob.go -- 111930-package bob 111931- 111932-func Hello() { 111933- var x int 111934-} 111935--- go.mod -- 111936-module mod.com 111937--- cmd/main.go -- 111938-package main 111939- 111940-import "mod.com/bob" 111941- 111942-func main() { 111943- bob.Hello() 111944-} 111945-` 111946- Run(t, mod, func(t *testing.T, env *Env) { 111947- env.OnceMet( 111948- InitialWorkspaceLoad, 111949- FileWatchMatching("bob"), 111950- ) 111951- env.RemoveWorkspaceFile("bob") 111952- env.AfterChange( 111953- Diagnostics(env.AtRegexp("cmd/main.go", `"mod.com/bob"`)), 111954- NoDiagnostics(ForFile("bob/bob.go")), 111955- NoFileWatchMatching("bob"), 111956- ) 111957- }) 111958-} 111959- 111960-// Confirms that circular imports are tested and reported. 111961-func TestCircularImports(t *testing.T) { 111962- const mod = ` 111963--- go.mod -- 111964-module mod.com 111965- 111966-go 1.12 111967--- self/self.go -- 111968-package self 111969- 111970-import _ "mod.com/self" 111971-func Hello() {} 111972--- double/a/a.go -- 111973-package a 111974- 111975-import _ "mod.com/double/b" 111976--- double/b/b.go -- 111977-package b 111978- 111979-import _ "mod.com/double/a" 111980--- triple/a/a.go -- 111981-package a 111982- 111983-import _ "mod.com/triple/b" 111984--- triple/b/b.go -- 111985-package b 111986- 111987-import _ "mod.com/triple/c" 111988--- triple/c/c.go -- 111989-package c 111990- 111991-import _ "mod.com/triple/a" 111992-` 111993- Run(t, mod, func(t *testing.T, env *Env) { 111994- env.OnceMet( 111995- InitialWorkspaceLoad, 111996- Diagnostics(env.AtRegexp("self/self.go", `_ "mod.com/self"`), WithMessage("import cycle not allowed")), 111997- Diagnostics(env.AtRegexp("double/a/a.go", `_ "mod.com/double/b"`), WithMessage("import cycle not allowed")), 111998- Diagnostics(env.AtRegexp("triple/a/a.go", `_ "mod.com/triple/b"`), WithMessage("import cycle not allowed")), 111999- ) 112000- }) 112001-} 112002- 112003-// Tests golang/go#46667: deleting a problematic import path should resolve 112004-// import cycle errors. 112005-func TestResolveImportCycle(t *testing.T) { 112006- const mod = ` 112007--- go.mod -- 112008-module mod.test 112009- 112010-go 1.16 112011--- a/a.go -- 112012-package a 112013- 112014-import "mod.test/b" 112015- 112016-const A = b.A 112017-const B = 2 112018--- b/b.go -- 112019-package b 112020- 112021-import "mod.test/a" 112022- 112023-const A = 1 112024-const B = a.B 112025- ` 112026- Run(t, mod, func(t *testing.T, env *Env) { 112027- env.OpenFile("a/a.go") 112028- env.OpenFile("b/b.go") 112029- env.AfterChange( 112030- // The Go command sometimes tells us about only one of the import cycle 112031- // errors below. For robustness of this test, succeed if we get either. 112032- // 112033- // TODO(golang/go#52904): we should get *both* of these errors. 112034- AnyOf( 112035- Diagnostics(env.AtRegexp("a/a.go", `"mod.test/b"`), WithMessage("import cycle")), 112036- Diagnostics(env.AtRegexp("b/b.go", `"mod.test/a"`), WithMessage("import cycle")), 112037- ), 112038- ) 112039- env.RegexpReplace("b/b.go", `const B = a\.B`, "") 112040- env.SaveBuffer("b/b.go") 112041- env.AfterChange( 112042- NoDiagnostics(ForFile("a/a.go")), 112043- NoDiagnostics(ForFile("b/b.go")), 112044- ) 112045- }) 112046-} 112047- 112048-func TestBadImport(t *testing.T) { 112049- const mod = ` 112050--- go.mod -- 112051-module mod.com 112052- 112053-go 1.12 112054--- main.go -- 112055-package main 112056- 112057-import ( 112058- _ "nosuchpkg" 112059-) 112060-` 112061- t.Run("module", func(t *testing.T) { 112062- Run(t, mod, func(t *testing.T, env *Env) { 112063- env.OnceMet( 112064- InitialWorkspaceLoad, 112065- Diagnostics(env.AtRegexp("main.go", `"nosuchpkg"`), WithMessage(`could not import nosuchpkg (no required module provides package "nosuchpkg"`)), 112066- ) 112067- }) 112068- }) 112069- t.Run("GOPATH", func(t *testing.T) { 112070- WithOptions( 112071- InGOPATH(), 112072- EnvVars{"GO111MODULE": "off"}, 112073- Modes(Default), 112074- ).Run(t, mod, func(t *testing.T, env *Env) { 112075- env.OnceMet( 112076- InitialWorkspaceLoad, 112077- Diagnostics(env.AtRegexp("main.go", `"nosuchpkg"`), WithMessage(`cannot find package "nosuchpkg"`)), 112078- ) 112079- }) 112080- }) 112081-} 112082- 112083-func TestNestedModules(t *testing.T) { 112084- const proxy = ` 112085--- [email protected]/go.mod -- 112086-module nested.com 112087- 112088-go 1.12 112089--- [email protected]/hello/hello.go -- 112090-package hello 112091- 112092-func Hello() {} 112093-` 112094- 112095- const nested = ` 112096--- go.mod -- 112097-module mod.com 112098- 112099-go 1.12 112100- 112101-require nested.com v1.0.0 112102--- go.sum -- 112103-nested.com v1.0.0 h1:I6spLE4CgFqMdBPc+wTV2asDO2QJ3tU0YAT+jkLeN1I= 112104-nested.com v1.0.0/go.mod h1:ly53UzXQgVjSlV7wicdBB4p8BxfytuGT1Xcyv0ReJfI= 112105--- main.go -- 112106-package main 112107- 112108-import "nested.com/hello" 112109- 112110-func main() { 112111- hello.Hello() 112112-} 112113--- nested/go.mod -- 112114-module nested.com 112115- 112116--- nested/hello/hello.go -- 112117-package hello 112118- 112119-func Hello() { 112120- helloHelper() 112121-} 112122--- nested/hello/hello_helper.go -- 112123-package hello 112124- 112125-func helloHelper() {} 112126-` 112127- WithOptions( 112128- ProxyFiles(proxy), 112129- Modes(Default), 112130- ).Run(t, nested, func(t *testing.T, env *Env) { 112131- // Expect a diagnostic in a nested module. 112132- env.OpenFile("nested/hello/hello.go") 112133- env.AfterChange( 112134- Diagnostics(env.AtRegexp("nested/hello/hello.go", "helloHelper")), 112135- Diagnostics(env.AtRegexp("nested/hello/hello.go", "package hello"), WithMessage("nested module")), 112136- OutstandingWork(lsp.WorkspaceLoadFailure, "nested module"), 112137- ) 112138- }) 112139-} 112140- 112141-func TestAdHocPackagesReloading(t *testing.T) { 112142- const nomod = ` 112143--- main.go -- 112144-package main 112145- 112146-func main() {} 112147-` 112148- Run(t, nomod, func(t *testing.T, env *Env) { 112149- env.OpenFile("main.go") 112150- env.RegexpReplace("main.go", "{}", "{ var x int; }") // simulate typing 112151- env.AfterChange(NoLogMatching(protocol.Info, "packages=1")) 112152- }) 112153-} 112154- 112155-func TestBuildTagChange(t *testing.T) { 112156- const files = ` 112157--- go.mod -- 112158-module mod.com 112159- 112160-go 1.12 112161--- foo.go -- 112162-// decoy comment 112163-// +build hidden 112164-// decoy comment 112165- 112166-package foo 112167-var Foo = 1 112168--- bar.go -- 112169-package foo 112170-var Bar = Foo 112171-` 112172- 112173- Run(t, files, func(t *testing.T, env *Env) { 112174- env.OpenFile("foo.go") 112175- env.AfterChange(Diagnostics(env.AtRegexp("bar.go", `Foo`))) 112176- env.RegexpReplace("foo.go", `\+build`, "") 112177- env.AfterChange(NoDiagnostics(ForFile("bar.go"))) 112178- }) 112179- 112180-} 112181- 112182-func TestIssue44736(t *testing.T) { 112183- const files = ` 112184- -- go.mod -- 112185-module blah.com 112186- 112187-go 1.16 112188--- main.go -- 112189-package main 112190- 112191-import "fmt" 112192- 112193-func main() { 112194- asdf 112195- fmt.Printf("This is a test %v") 112196- fdas 112197-} 112198--- other.go -- 112199-package main 112200- 112201-` 112202- Run(t, files, func(t *testing.T, env *Env) { 112203- env.OpenFile("main.go") 112204- env.OpenFile("other.go") 112205- env.AfterChange( 112206- Diagnostics(env.AtRegexp("main.go", "asdf")), 112207- Diagnostics(env.AtRegexp("main.go", "fdas")), 112208- ) 112209- env.SetBufferContent("other.go", "package main\n\nasdf") 112210- // The new diagnostic in other.go should not suppress diagnostics in main.go. 112211- env.AfterChange( 112212- Diagnostics(env.AtRegexp("other.go", "asdf"), WithMessage("expected declaration")), 112213- Diagnostics(env.AtRegexp("main.go", "asdf")), 112214- ) 112215- }) 112216-} 112217- 112218-func TestInitialization(t *testing.T) { 112219- const files = ` 112220--- go.mod -- 112221-module mod.com 112222- 112223-go 1.16 112224--- main.go -- 112225-package main 112226-` 112227- Run(t, files, func(t *testing.T, env *Env) { 112228- env.OpenFile("go.mod") 112229- env.Await(env.DoneWithOpen()) 112230- env.RegexpReplace("go.mod", "module", "modul") 112231- env.SaveBufferWithoutActions("go.mod") 112232- env.AfterChange( 112233- NoLogMatching(protocol.Error, "initial workspace load failed"), 112234- ) 112235- }) 112236-} 112237- 112238-// This test confirms that the view does not reinitialize when a go.mod file is 112239-// opened. 112240-func TestNoReinitialize(t *testing.T) { 112241- const files = ` 112242--- go.mod -- 112243-module mod.com 112244- 112245-go 1.12 112246--- main.go -- 112247-package main 112248- 112249-func main() {} 112250-` 112251- Run(t, files, func(t *testing.T, env *Env) { 112252- env.OpenFile("go.mod") 112253- env.AfterChange( 112254- LogMatching(protocol.Info, `.*query=\[builtin mod.com/...\].*`, 1, false), 112255- ) 112256- }) 112257-} 112258- 112259-func TestLangVersion(t *testing.T) { 112260- testenv.NeedsGo1Point(t, 18) // Requires types.Config.GoVersion, new in 1.18. 112261- const files = ` 112262--- go.mod -- 112263-module mod.com 112264- 112265-go 1.12 112266--- main.go -- 112267-package main 112268- 112269-const C = 0b10 112270-` 112271- Run(t, files, func(t *testing.T, env *Env) { 112272- env.OnceMet( 112273- InitialWorkspaceLoad, 112274- Diagnostics(env.AtRegexp("main.go", `0b10`), WithMessage("go1.13 or later")), 112275- ) 112276- env.WriteWorkspaceFile("go.mod", "module mod.com \n\ngo 1.13\n") 112277- env.AfterChange( 112278- NoDiagnostics(ForFile("main.go")), 112279- ) 112280- }) 112281-} 112282- 112283-func TestNoQuickFixForUndeclaredConstraint(t *testing.T) { 112284- testenv.NeedsGo1Point(t, 18) 112285- const files = ` 112286--- go.mod -- 112287-module mod.com 112288- 112289-go 1.18 112290--- main.go -- 112291-package main 112292- 112293-func F[T C](_ T) { 112294-} 112295-` 112296- 112297- Run(t, files, func(t *testing.T, env *Env) { 112298- var d protocol.PublishDiagnosticsParams 112299- env.OnceMet( 112300- InitialWorkspaceLoad, 112301- Diagnostics(env.AtRegexp("main.go", `C`)), 112302- ReadDiagnostics("main.go", &d), 112303- ) 112304- if fixes := env.GetQuickFixes("main.go", d.Diagnostics); len(fixes) != 0 { 112305- t.Errorf("got quick fixes %v, wanted none", fixes) 112306- } 112307- }) 112308-} 112309- 112310-func TestEditGoDirective(t *testing.T) { 112311- testenv.NeedsGo1Point(t, 18) 112312- const files = ` 112313--- go.mod -- 112314-module mod.com 112315- 112316-go 1.16 112317--- main.go -- 112318-package main 112319- 112320-func F[T any](_ T) { 112321-} 112322-` 112323- Run(t, files, func(_ *testing.T, env *Env) { // Create a new workspace-level directory and empty file. 112324- var d protocol.PublishDiagnosticsParams 112325- env.OnceMet( 112326- InitialWorkspaceLoad, 112327- Diagnostics(env.AtRegexp("main.go", `T any`), WithMessage("type parameter")), 112328- ReadDiagnostics("main.go", &d), 112329- ) 112330- 112331- env.ApplyQuickFixes("main.go", d.Diagnostics) 112332- env.AfterChange( 112333- NoDiagnostics(ForFile("main.go")), 112334- ) 112335- }) 112336-} 112337- 112338-func TestEditGoDirectiveWorkspace(t *testing.T) { 112339- testenv.NeedsGo1Point(t, 18) 112340- const files = ` 112341--- go.mod -- 112342-module mod.com 112343- 112344-go 1.16 112345--- go.work -- 112346-go 1.18 112347- 112348-use . 112349--- main.go -- 112350-package main 112351- 112352-func F[T any](_ T) { 112353-} 112354-` 112355- Run(t, files, func(_ *testing.T, env *Env) { // Create a new workspace-level directory and empty file. 112356- var d protocol.PublishDiagnosticsParams 112357- 112358- // We should have a diagnostic because generics are not supported at 1.16. 112359- env.OnceMet( 112360- InitialWorkspaceLoad, 112361- Diagnostics(env.AtRegexp("main.go", `T any`), WithMessage("type parameter")), 112362- ReadDiagnostics("main.go", &d), 112363- ) 112364- 112365- // This diagnostic should have a quick fix to edit the go version. 112366- env.ApplyQuickFixes("main.go", d.Diagnostics) 112367- 112368- // Once the edit is applied, the problematic diagnostics should be 112369- // resolved. 112370- env.AfterChange( 112371- NoDiagnostics(ForFile("main.go")), 112372- ) 112373- }) 112374-} 112375- 112376-// This test demonstrates that analysis facts are correctly propagated 112377-// across packages. 112378-func TestInterpackageAnalysis(t *testing.T) { 112379- const src = ` 112380--- go.mod -- 112381-module example.com 112382--- a/a.go -- 112383-package a 112384- 112385-import "example.com/b" 112386- 112387-func _() { 112388- new(b.B).Printf("%d", "s") // printf error 112389-} 112390- 112391--- b/b.go -- 112392-package b 112393- 112394-import "example.com/c" 112395- 112396-type B struct{} 112397- 112398-func (B) Printf(format string, args ...interface{}) { 112399- c.MyPrintf(format, args...) 112400-} 112401- 112402--- c/c.go -- 112403-package c 112404- 112405-import "fmt" 112406- 112407-func MyPrintf(format string, args ...interface{}) { 112408- fmt.Printf(format, args...) 112409-} 112410-` 112411- Run(t, src, func(t *testing.T, env *Env) { 112412- env.OpenFile("a/a.go") 112413- env.AfterChange( 112414- Diagnostics( 112415- env.AtRegexp("a/a.go", "new.*Printf"), 112416- WithMessage("format %d has arg \"s\" of wrong type string"), 112417- ), 112418- ) 112419- }) 112420-} 112421- 112422-// This test ensures that only Analyzers with RunDespiteErrors=true 112423-// are invoked on a package that would not compile, even if the errors 112424-// are distant and localized. 112425-func TestErrorsThatPreventAnalysis(t *testing.T) { 112426- const src = ` 112427--- go.mod -- 112428-module example.com 112429--- a/a.go -- 112430-package a 112431- 112432-import "fmt" 112433-import "sync" 112434-import _ "example.com/b" 112435- 112436-func _() { 112437- // The copylocks analyzer (RunDespiteErrors, FactTypes={}) does run. 112438- var mu sync.Mutex 112439- mu2 := mu // copylocks error, reported 112440- _ = &mu2 112441- 112442- // The printf analyzer (!RunDespiteErrors, FactTypes!={}) does not run: 112443- // (c, printf) failed because of type error in c 112444- // (b, printf) and (a, printf) do not run because of failed prerequisites. 112445- fmt.Printf("%d", "s") // printf error, unreported 112446- 112447- // The bools analyzer (!RunDespiteErrors, FactTypes={}) does not run: 112448- var cond bool 112449- _ = cond != true && cond != true // bools error, unreported 112450-} 112451- 112452--- b/b.go -- 112453-package b 112454- 112455-import _ "example.com/c" 112456- 112457--- c/c.go -- 112458-package c 112459- 112460-var _ = 1 / "" // type error 112461- 112462-` 112463- Run(t, src, func(t *testing.T, env *Env) { 112464- var diags protocol.PublishDiagnosticsParams 112465- env.OpenFile("a/a.go") 112466- env.AfterChange( 112467- Diagnostics(env.AtRegexp("a/a.go", "mu2 := (mu)"), WithMessage("assignment copies lock value")), 112468- ReadDiagnostics("a/a.go", &diags)) 112469- 112470- // Assert that there were no other diagnostics. 112471- // In particular: 112472- // - "fmt.Printf" does not trigger a [printf] finding; 112473- // - "cond != true" does not trigger a [bools] finding. 112474- // 112475- // We use this check in preference to NoDiagnosticAtRegexp 112476- // as it is robust in case of minor mistakes in the position 112477- // regexp, and because it reports unexpected diagnostics. 112478- if got, want := len(diags.Diagnostics), 1; got != want { 112479- t.Errorf("got %d diagnostics in a/a.go, want %d:", got, want) 112480- for i, diag := range diags.Diagnostics { 112481- t.Logf("Diagnostics[%d] = %+v", i, diag) 112482- } 112483- } 112484- }) 112485-} 112486diff -urN a/gopls/internal/regtest/diagnostics/golist_test.go b/gopls/internal/regtest/diagnostics/golist_test.go 112487--- a/gopls/internal/regtest/diagnostics/golist_test.go 2000-01-01 00:00:00.000000000 -0000 112488+++ b/gopls/internal/regtest/diagnostics/golist_test.go 1970-01-01 00:00:00.000000000 +0000 112489@@ -1,71 +0,0 @@ 112490-// Copyright 2023 The Go Authors. All rights reserved. 112491-// Use of this source code is governed by a BSD-style 112492-// license that can be found in the LICENSE file. 112493- 112494-package diagnostics 112495- 112496-import ( 112497- "testing" 112498- 112499- . "golang.org/x/tools/gopls/internal/lsp/regtest" 112500- "golang.org/x/tools/gopls/internal/lsp/source" 112501- "golang.org/x/tools/internal/testenv" 112502-) 112503- 112504-func TestGoListErrors(t *testing.T) { 112505- testenv.NeedsTool(t, "cgo") 112506- 112507- const src = ` 112508--- go.mod -- 112509-module a.com 112510- 112511-go 1.18 112512--- a/a.go -- 112513-package a 112514- 112515-import 112516--- c/c.go -- 112517-package c 112518- 112519-/* 112520-int fortythree() { return 42; } 112521-*/ 112522-import "C" 112523- 112524-func Foo() { 112525- print(C.fortytwo()) 112526-} 112527--- p/p.go -- 112528-package p 112529- 112530-import "a.com/q" 112531- 112532-const P = q.Q + 1 112533--- q/q.go -- 112534-package q 112535- 112536-import "a.com/p" 112537- 112538-const Q = p.P + 1 112539-` 112540- 112541- Run(t, src, func(t *testing.T, env *Env) { 112542- env.OnceMet( 112543- InitialWorkspaceLoad, 112544- Diagnostics( 112545- env.AtRegexp("a/a.go", "import\n()"), 112546- FromSource(string(source.ParseError)), 112547- ), 112548- Diagnostics( 112549- AtPosition("c/c.go", 0, 0), 112550- FromSource(string(source.ListError)), 112551- WithMessage("may indicate failure to perform cgo processing"), 112552- ), 112553- Diagnostics( 112554- env.AtRegexp("p/p.go", `"a.com/q"`), 112555- FromSource(string(source.ListError)), 112556- WithMessage("import cycle not allowed"), 112557- ), 112558- ) 112559- }) 112560-} 112561diff -urN a/gopls/internal/regtest/diagnostics/invalidation_test.go b/gopls/internal/regtest/diagnostics/invalidation_test.go 112562--- a/gopls/internal/regtest/diagnostics/invalidation_test.go 2000-01-01 00:00:00.000000000 -0000 112563+++ b/gopls/internal/regtest/diagnostics/invalidation_test.go 1970-01-01 00:00:00.000000000 +0000 112564@@ -1,111 +0,0 @@ 112565-// Copyright 2022 The Go Authors. All rights reserved. 112566-// Use of this source code is governed by a BSD-style 112567-// license that can be found in the LICENSE file. 112568- 112569-package diagnostics 112570- 112571-import ( 112572- "fmt" 112573- "testing" 112574- 112575- "golang.org/x/tools/gopls/internal/lsp/protocol" 112576- . "golang.org/x/tools/gopls/internal/lsp/regtest" 112577-) 112578- 112579-// Test for golang/go#50267: diagnostics should be re-sent after a file is 112580-// opened. 112581-func TestDiagnosticsAreResentAfterCloseOrOpen(t *testing.T) { 112582- const files = ` 112583--- go.mod -- 112584-module mod.com 112585- 112586-go 1.16 112587--- main.go -- 112588-package main 112589- 112590-func _() { 112591- x := 2 112592-} 112593-` 112594- Run(t, files, func(_ *testing.T, env *Env) { // Create a new workspace-level directory and empty file. 112595- env.OpenFile("main.go") 112596- var afterOpen protocol.PublishDiagnosticsParams 112597- env.AfterChange( 112598- ReadDiagnostics("main.go", &afterOpen), 112599- ) 112600- env.CloseBuffer("main.go") 112601- var afterClose protocol.PublishDiagnosticsParams 112602- env.AfterChange( 112603- ReadDiagnostics("main.go", &afterClose), 112604- ) 112605- if afterOpen.Version == afterClose.Version { 112606- t.Errorf("publishDiagnostics: got the same version after closing (%d) as after opening", afterOpen.Version) 112607- } 112608- env.OpenFile("main.go") 112609- var afterReopen protocol.PublishDiagnosticsParams 112610- env.AfterChange( 112611- ReadDiagnostics("main.go", &afterReopen), 112612- ) 112613- if afterReopen.Version == afterClose.Version { 112614- t.Errorf("pubslishDiagnostics: got the same version after reopening (%d) as after closing", afterClose.Version) 112615- } 112616- }) 112617-} 112618- 112619-// Test for the "chattyDiagnostics" setting: we should get re-published 112620-// diagnostics after every file change, even if diagnostics did not change. 112621-func TestChattyDiagnostics(t *testing.T) { 112622- const files = ` 112623--- go.mod -- 112624-module mod.com 112625- 112626-go 1.16 112627--- main.go -- 112628-package main 112629- 112630-func _() { 112631- x := 2 112632-} 112633- 112634-// Irrelevant comment #0 112635-` 112636- 112637- WithOptions( 112638- Settings{ 112639- "chattyDiagnostics": true, 112640- }, 112641- ).Run(t, files, func(_ *testing.T, env *Env) { // Create a new workspace-level directory and empty file. 112642- 112643- env.OpenFile("main.go") 112644- var d protocol.PublishDiagnosticsParams 112645- env.AfterChange( 112646- ReadDiagnostics("main.go", &d), 112647- ) 112648- 112649- if len(d.Diagnostics) != 1 { 112650- t.Fatalf("len(Diagnostics) = %d, want 1", len(d.Diagnostics)) 112651- } 112652- msg := d.Diagnostics[0].Message 112653- 112654- for i := 0; i < 5; i++ { 112655- before := d.Version 112656- env.RegexpReplace("main.go", "Irrelevant comment #.", fmt.Sprintf("Irrelevant comment #%d", i)) 112657- env.AfterChange( 112658- ReadDiagnostics("main.go", &d), 112659- ) 112660- 112661- if d.Version == before { 112662- t.Errorf("after change, got version %d, want new version", d.Version) 112663- } 112664- 112665- // As a sanity check, make sure we have the same diagnostic. 112666- if len(d.Diagnostics) != 1 { 112667- t.Fatalf("len(Diagnostics) = %d, want 1", len(d.Diagnostics)) 112668- } 112669- newMsg := d.Diagnostics[0].Message 112670- if newMsg != msg { 112671- t.Errorf("after change, got message %q, want %q", newMsg, msg) 112672- } 112673- } 112674- }) 112675-} 112676diff -urN a/gopls/internal/regtest/diagnostics/undeclared_test.go b/gopls/internal/regtest/diagnostics/undeclared_test.go 112677--- a/gopls/internal/regtest/diagnostics/undeclared_test.go 2000-01-01 00:00:00.000000000 -0000 112678+++ b/gopls/internal/regtest/diagnostics/undeclared_test.go 1970-01-01 00:00:00.000000000 +0000 112679@@ -1,73 +0,0 @@ 112680-// Copyright 2021 The Go Authors. All rights reserved. 112681-// Use of this source code is governed by a BSD-style 112682-// license that can be found in the LICENSE file. 112683- 112684-package diagnostics 112685- 112686-import ( 112687- "testing" 112688- 112689- "golang.org/x/tools/gopls/internal/lsp/protocol" 112690- . "golang.org/x/tools/gopls/internal/lsp/regtest" 112691-) 112692- 112693-func TestUndeclaredDiagnostics(t *testing.T) { 112694- src := ` 112695--- go.mod -- 112696-module mod.com 112697- 112698-go 1.12 112699--- a/a.go -- 112700-package a 112701- 112702-func _() int { 112703- return x 112704-} 112705--- b/b.go -- 112706-package b 112707- 112708-func _() int { 112709- var y int 112710- y = y 112711- return y 112712-} 112713-` 112714- Run(t, src, func(t *testing.T, env *Env) { 112715- isUnnecessary := func(diag protocol.Diagnostic) bool { 112716- for _, tag := range diag.Tags { 112717- if tag == protocol.Unnecessary { 112718- return true 112719- } 112720- } 112721- return false 112722- } 112723- 112724- // 'x' is undeclared, but still necessary. 112725- env.OpenFile("a/a.go") 112726- var adiags protocol.PublishDiagnosticsParams 112727- env.AfterChange( 112728- Diagnostics(env.AtRegexp("a/a.go", "x")), 112729- ReadDiagnostics("a/a.go", &adiags), 112730- ) 112731- if got := len(adiags.Diagnostics); got != 1 { 112732- t.Errorf("len(Diagnostics) = %d, want 1", got) 112733- } 112734- if diag := adiags.Diagnostics[0]; isUnnecessary(diag) { 112735- t.Errorf("%v tagged unnecessary, want necessary", diag) 112736- } 112737- 112738- // 'y = y' is pointless, and should be detected as unnecessary. 112739- env.OpenFile("b/b.go") 112740- var bdiags protocol.PublishDiagnosticsParams 112741- env.AfterChange( 112742- Diagnostics(env.AtRegexp("b/b.go", "y = y")), 112743- ReadDiagnostics("b/b.go", &bdiags), 112744- ) 112745- if got := len(bdiags.Diagnostics); got != 1 { 112746- t.Errorf("len(Diagnostics) = %d, want 1", got) 112747- } 112748- if diag := bdiags.Diagnostics[0]; !isUnnecessary(diag) { 112749- t.Errorf("%v tagged necessary, want unnecessary", diag) 112750- } 112751- }) 112752-} 112753diff -urN a/gopls/internal/regtest/inlayhints/inlayhints_test.go b/gopls/internal/regtest/inlayhints/inlayhints_test.go 112754--- a/gopls/internal/regtest/inlayhints/inlayhints_test.go 2000-01-01 00:00:00.000000000 -0000 112755+++ b/gopls/internal/regtest/inlayhints/inlayhints_test.go 1970-01-01 00:00:00.000000000 +0000 112756@@ -1,69 +0,0 @@ 112757-// Copyright 2022 The Go Authors. All rights reserved. 112758-// Use of this source code is governed by a BSD-style 112759-// license that can be found in the LICENSE file. 112760-package inlayhint 112761- 112762-import ( 112763- "testing" 112764- 112765- "golang.org/x/tools/gopls/internal/hooks" 112766- . "golang.org/x/tools/gopls/internal/lsp/regtest" 112767- "golang.org/x/tools/gopls/internal/lsp/source" 112768- "golang.org/x/tools/internal/bug" 112769-) 112770- 112771-func TestMain(m *testing.M) { 112772- bug.PanicOnBugs = true 112773- Main(m, hooks.Options) 112774-} 112775- 112776-func TestEnablingInlayHints(t *testing.T) { 112777- const workspace = ` 112778--- go.mod -- 112779-module inlayHint.test 112780-go 1.12 112781--- lib.go -- 112782-package lib 112783-type Number int 112784-const ( 112785- Zero Number = iota 112786- One 112787- Two 112788-) 112789-` 112790- tests := []struct { 112791- label string 112792- enabled map[string]bool 112793- wantInlayHint bool 112794- }{ 112795- { 112796- label: "default", 112797- wantInlayHint: false, 112798- }, 112799- { 112800- label: "enable const", 112801- enabled: map[string]bool{source.ConstantValues: true}, 112802- wantInlayHint: true, 112803- }, 112804- { 112805- label: "enable parameter names", 112806- enabled: map[string]bool{source.ParameterNames: true}, 112807- wantInlayHint: false, 112808- }, 112809- } 112810- for _, test := range tests { 112811- t.Run(test.label, func(t *testing.T) { 112812- WithOptions( 112813- Settings{ 112814- "hints": test.enabled, 112815- }, 112816- ).Run(t, workspace, func(t *testing.T, env *Env) { 112817- env.OpenFile("lib.go") 112818- lens := env.InlayHints("lib.go") 112819- if gotInlayHint := len(lens) > 0; gotInlayHint != test.wantInlayHint { 112820- t.Errorf("got inlayHint: %t, want %t", gotInlayHint, test.wantInlayHint) 112821- } 112822- }) 112823- }) 112824- } 112825-} 112826diff -urN a/gopls/internal/regtest/marker/marker_test.go b/gopls/internal/regtest/marker/marker_test.go 112827--- a/gopls/internal/regtest/marker/marker_test.go 2000-01-01 00:00:00.000000000 -0000 112828+++ b/gopls/internal/regtest/marker/marker_test.go 1970-01-01 00:00:00.000000000 +0000 112829@@ -1,21 +0,0 @@ 112830-// Copyright 2023 The Go Authors. All rights reserved. 112831-// Use of this source code is governed by a BSD-style 112832-// license that can be found in the LICENSE file. 112833- 112834-package marker 112835- 112836-import ( 112837- "testing" 112838- 112839- . "golang.org/x/tools/gopls/internal/lsp/regtest" 112840-) 112841- 112842-// Note: we use a separate package for the marker tests so that we can easily 112843-// compare their performance to the existing marker tests in ./internal/lsp. 112844- 112845-// TestMarkers runs the marker tests from the testdata directory. 112846-// 112847-// See RunMarkerTests for details on how marker tests work. 112848-func TestMarkers(t *testing.T) { 112849- RunMarkerTests(t, "testdata") 112850-} 112851diff -urN a/gopls/internal/regtest/marker/testdata/definition/embed.txt b/gopls/internal/regtest/marker/testdata/definition/embed.txt 112852--- a/gopls/internal/regtest/marker/testdata/definition/embed.txt 2000-01-01 00:00:00.000000000 -0000 112853+++ b/gopls/internal/regtest/marker/testdata/definition/embed.txt 1970-01-01 00:00:00.000000000 +0000 112854@@ -1,254 +0,0 @@ 112855-This test checks definition and hover operations over embedded fields and methods. 112856- 112857--- go.mod -- 112858-module mod.com 112859- 112860-go 1.18 112861- 112862--- a/a.go -- 112863-package a 112864- 112865-type A string //@loc(AString, "A") 112866- 112867-func (_ A) Hi() {} //@loc(AHi, "Hi") 112868- 112869-type S struct { 112870- Field int //@loc(SField, "Field") 112871- R // embed a struct 112872- H // embed an interface 112873-} 112874- 112875-type R struct { 112876- Field2 int //@loc(RField2, "Field2") 112877-} 112878- 112879-func (_ R) Hey() {} //@loc(RHey, "Hey") 112880- 112881-type H interface { //@loc(H, "H") 112882- Goodbye() //@loc(HGoodbye, "Goodbye") 112883-} 112884- 112885-type I interface { //@loc(I, "I") 112886- B() //@loc(IB, "B") 112887- J 112888-} 112889- 112890-type J interface { //@loc(J, "J") 112891- Hello() //@loc(JHello, "Hello") 112892-} 112893- 112894--- b/b.go -- 112895-package b 112896- 112897-import "mod.com/a" //@loc(AImport, re"\".*\"") 112898- 112899-type embed struct { 112900- F int //@loc(F, "F") 112901-} 112902- 112903-func (embed) M() //@loc(M, "M") 112904- 112905-type Embed struct { 112906- embed 112907- *a.A 112908- a.I 112909- a.S 112910-} 112911- 112912-func _() { 112913- e := Embed{} 112914- e.Hi() //@def("Hi", AHi),hover("Hi", "Hi", AHi) 112915- e.B() //@def("B", IB),hover("B", "B", IB) 112916- _ = e.Field //@def("Field", SField),hover("Field", "Field", SField) 112917- _ = e.Field2 //@def("Field2", RField2),hover("Field2", "Field2", RField2) 112918- e.Hello() //@def("Hello", JHello),hover("Hello", "Hello",JHello) 112919- e.Hey() //@def("Hey", RHey),hover("Hey", "Hey", RHey) 112920- e.Goodbye() //@def("Goodbye", HGoodbye),hover("Goodbye", "Goodbye", HGoodbye) 112921- e.M() //@def("M", M),hover("M", "M", M) 112922- _ = e.F //@def("F", F),hover("F", "F", F) 112923-} 112924- 112925-type aAlias = a.A //@loc(aAlias, "aAlias") 112926- 112927-type S1 struct { //@loc(S1, "S1") 112928- F1 int //@loc(S1F1, "F1") 112929- S2 //@loc(S1S2, "S2"),def("S2", S2),hover("S2", "S2", S2) 112930- a.A //@def("A", AString),hover("A", "A", aA) 112931- aAlias //@def("a", aAlias),hover("a", "aAlias", aAlias) 112932-} 112933- 112934-type S2 struct { //@loc(S2, "S2") 112935- F1 string //@loc(S2F1, "F1") 112936- F2 int //@loc(S2F2, "F2") 112937- *a.A //@def("A", AString),def("a",AImport) 112938-} 112939- 112940-type S3 struct { 112941- F1 struct { 112942- a.A //@def("A", AString) 112943- } 112944-} 112945- 112946-func Bar() { 112947- var x S1 //@def("S1", S1),hover("S1", "S1", S1) 112948- _ = x.S2 //@def("S2", S1S2),hover("S2", "S2", S1S2) 112949- _ = x.F1 //@def("F1", S1F1),hover("F1", "F1", S1F1) 112950- _ = x.F2 //@def("F2", S2F2),hover("F2", "F2", S2F2) 112951- _ = x.S2.F1 //@def("F1", S2F1),hover("F1", "F1", S2F1) 112952-} 112953- 112954--- b/c.go -- 112955-package b 112956- 112957-var _ = S1{ //@def("S1", S1),hover("S1", "S1", S1) 112958- F1: 99, //@def("F1", S1F1),hover("F1", "F1", S1F1) 112959-} 112960- 112961--- @AHi/hover.md -- 112962-```go 112963-func (a.A).Hi() 112964-``` 112965- 112966-[`(a.A).Hi` on pkg.go.dev](https://pkg.go.dev/mod.com/a#A.Hi) 112967--- @F/hover.md -- 112968-```go 112969-field F int 112970-``` 112971- 112972-@loc(F, "F") 112973- 112974- 112975-[`(b.Embed).F` on pkg.go.dev](https://pkg.go.dev/mod.com/b#Embed.F) 112976--- @HGoodbye/hover.md -- 112977-```go 112978-func (a.H).Goodbye() 112979-``` 112980- 112981-@loc(HGoodbye, "Goodbye") 112982- 112983- 112984-[`(a.H).Goodbye` on pkg.go.dev](https://pkg.go.dev/mod.com/a#H.Goodbye) 112985--- @IB/hover.md -- 112986-```go 112987-func (a.I).B() 112988-``` 112989- 112990-@loc(IB, "B") 112991- 112992- 112993-[`(a.I).B` on pkg.go.dev](https://pkg.go.dev/mod.com/a#I.B) 112994--- @JHello/hover.md -- 112995-```go 112996-func (a.J).Hello() 112997-``` 112998- 112999-@loc(JHello, "Hello") 113000- 113001- 113002-[`(a.J).Hello` on pkg.go.dev](https://pkg.go.dev/mod.com/a#J.Hello) 113003--- @M/hover.md -- 113004-```go 113005-func (embed).M() 113006-``` 113007- 113008-[`(b.Embed).M` on pkg.go.dev](https://pkg.go.dev/mod.com/b#Embed.M) 113009--- @RField2/hover.md -- 113010-```go 113011-field Field2 int 113012-``` 113013- 113014-@loc(RField2, "Field2") 113015- 113016- 113017-[`(a.R).Field2` on pkg.go.dev](https://pkg.go.dev/mod.com/a#R.Field2) 113018--- @RHey/hover.md -- 113019-```go 113020-func (a.R).Hey() 113021-``` 113022- 113023-[`(a.R).Hey` on pkg.go.dev](https://pkg.go.dev/mod.com/a#R.Hey) 113024--- @S1/hover.md -- 113025-```go 113026-type S1 struct { 113027- F1 int //@loc(S1F1, "F1") 113028- S2 //@loc(S1S2, "S2"),def("S2", S2),hover("S2", "S2", S2) 113029- a.A //@def("A", AString),hover("A", "A", aA) 113030- aAlias //@def("a", aAlias),hover("a", "aAlias", aAlias) 113031-} 113032-``` 113033- 113034-[`b.S1` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S1) 113035--- @S1F1/hover.md -- 113036-```go 113037-field F1 int 113038-``` 113039- 113040-@loc(S1F1, "F1") 113041- 113042- 113043-[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S1.F1) 113044--- @S1S2/hover.md -- 113045-```go 113046-field S2 S2 113047-``` 113048- 113049-@loc(S1S2, "S2"),def("S2", S2),hover("S2", "S2", S2) 113050- 113051- 113052-[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S1.S2) 113053--- @S2/hover.md -- 113054-```go 113055-type S2 struct { 113056- F1 string //@loc(S2F1, "F1") 113057- F2 int //@loc(S2F2, "F2") 113058- *a.A //@def("A", AString),def("a",AImport) 113059-} 113060-``` 113061- 113062-[`b.S2` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S2) 113063--- @S2F1/hover.md -- 113064-```go 113065-field F1 string 113066-``` 113067- 113068-@loc(S2F1, "F1") 113069- 113070- 113071-[`(b.S2).F1` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S2.F1) 113072--- @S2F2/hover.md -- 113073-```go 113074-field F2 int 113075-``` 113076- 113077-@loc(S2F2, "F2") 113078- 113079- 113080-[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S2.F2) 113081--- @SField/hover.md -- 113082-```go 113083-field Field int 113084-``` 113085- 113086-@loc(SField, "Field") 113087- 113088- 113089-[`(a.S).Field` on pkg.go.dev](https://pkg.go.dev/mod.com/a#S.Field) 113090--- @aA/hover.md -- 113091-```go 113092-type A string 113093- 113094-func (a.A).Hi() 113095-``` 113096- 113097-@loc(AString, "A") 113098- 113099- 113100-[`a.A` on pkg.go.dev](https://pkg.go.dev/mod.com/a#A) 113101--- @aAlias/hover.md -- 113102-```go 113103-type aAlias = a.A 113104- 113105-func (a.A).Hi() 113106-``` 113107- 113108-@loc(aAlias, "aAlias") 113109diff -urN a/gopls/internal/regtest/marker/testdata/definition/import.txt b/gopls/internal/regtest/marker/testdata/definition/import.txt 113110--- a/gopls/internal/regtest/marker/testdata/definition/import.txt 2000-01-01 00:00:00.000000000 -0000 113111+++ b/gopls/internal/regtest/marker/testdata/definition/import.txt 1970-01-01 00:00:00.000000000 +0000 113112@@ -1,52 +0,0 @@ 113113-This test checks definition and hover over imports. 113114--- go.mod -- 113115-module mod.com 113116- 113117-go 1.18 113118--- foo/foo.go -- 113119-package foo 113120- 113121-type Foo struct{} 113122- 113123-// DoFoo does foo. 113124-func DoFoo() {} //@loc(DoFoo, "DoFoo") 113125--- bar/bar.go -- 113126-package bar 113127- 113128-import ( 113129- myFoo "mod.com/foo" //@loc(myFoo, "myFoo") 113130-) 113131- 113132-var _ *myFoo.Foo //@def("myFoo", myFoo),hover("myFoo", "myFoo", myFoo) 113133--- bar/dotimport.go -- 113134-package bar 113135- 113136-import . "mod.com/foo" 113137- 113138-func _() { 113139- // variable of type foo.Foo 113140- var _ Foo //@hover("_", "_", FooVar) 113141- 113142- DoFoo() //@hover("DoFoo", "DoFoo", DoFoo) 113143-} 113144--- @DoFoo/hover.md -- 113145-```go 113146-func DoFoo() 113147-``` 113148- 113149-DoFoo does foo. 113150- 113151- 113152-[`foo.DoFoo` on pkg.go.dev](https://pkg.go.dev/mod.com/foo#DoFoo) 113153--- @FooVar/hover.md -- 113154-```go 113155-var _ Foo 113156-``` 113157- 113158-variable of type foo.Foo 113159--- @myFoo/hover.md -- 113160-```go 113161-package myFoo ("mod.com/foo") 113162-``` 113163- 113164-[`myFoo` on pkg.go.dev](https://pkg.go.dev/mod.com/foo) 113165diff -urN a/gopls/internal/regtest/marker/testdata/definition/misc.txt b/gopls/internal/regtest/marker/testdata/definition/misc.txt 113166--- a/gopls/internal/regtest/marker/testdata/definition/misc.txt 2000-01-01 00:00:00.000000000 -0000 113167+++ b/gopls/internal/regtest/marker/testdata/definition/misc.txt 1970-01-01 00:00:00.000000000 +0000 113168@@ -1,230 +0,0 @@ 113169-This test exercises miscellaneous definition and hover requests. 113170--- go.mod -- 113171-module mod.com 113172- 113173-go 1.16 113174--- a.go -- 113175-package a //@loc(aPackage, re"package (a)"),hover(aPackage, aPackage, aPackage) 113176- 113177-var ( 113178- // x is a variable. 113179- x string //@loc(x, "x"),hover(x, x, hoverx) 113180-) 113181- 113182-// Constant block. When I hover on h, I should see this comment. 113183-const ( 113184- // When I hover on g, I should see this comment. 113185- g = 1 //@hover("g", "g", hoverg) 113186- 113187- h = 2 //@hover("h", "h", hoverh) 113188-) 113189- 113190-// z is a variable too. 113191-var z string //@loc(z, "z"),hover(z, z, hoverz) 113192- 113193-func AStuff() { //@loc(AStuff, "AStuff") 113194- x := 5 113195- Random2(x) //@def("dom2", Random2) 113196- Random() //@def("()", Random) 113197-} 113198- 113199-type H interface { //@loc(H, "H") 113200- Goodbye() 113201-} 113202- 113203-type I interface { //@loc(I, "I") 113204- B() 113205- J 113206-} 113207- 113208-type J interface { //@loc(J, "J") 113209- Hello() 113210-} 113211- 113212-func _() { 113213- // 1st type declaration block 113214- type ( 113215- a struct { //@hover("a", "a", hoverDeclBlocka) 113216- x string 113217- } 113218- ) 113219- 113220- // 2nd type declaration block 113221- type ( 113222- // b has a comment 113223- b struct{} //@hover("b", "b", hoverDeclBlockb) 113224- ) 113225- 113226- // 3rd type declaration block 113227- type ( 113228- // c is a struct 113229- c struct { //@hover("c", "c", hoverDeclBlockc) 113230- f string 113231- } 113232- 113233- d string //@hover("d", "d", hoverDeclBlockd) 113234- ) 113235- 113236- type ( 113237- e struct { //@hover("e", "e", hoverDeclBlocke) 113238- f float64 113239- } // e has a comment 113240- ) 113241-} 113242- 113243-var ( 113244- hh H //@hover("H", "H", hoverH) 113245- ii I //@hover("I", "I", hoverI) 113246- jj J //@hover("J", "J", hoverJ) 113247-) 113248--- a_test.go -- 113249-package a 113250- 113251-import ( 113252- "testing" 113253-) 113254- 113255-func TestA(t *testing.T) { //@hover("TestA", "TestA", hoverTestA) 113256-} 113257--- random.go -- 113258-package a 113259- 113260-func Random() int { //@loc(Random, "Random") 113261- y := 6 + 7 113262- return y 113263-} 113264- 113265-func Random2(y int) int { //@loc(Random2, "Random2"),loc(RandomParamY, "y") 113266- return y //@def("y", RandomParamY),hover("y", "y", hovery) 113267-} 113268- 113269-type Pos struct { 113270- x, y int //@loc(PosX, "x"),loc(PosY, "y") 113271-} 113272- 113273-// Typ has a comment. Its fields do not. 113274-type Typ struct{ field string } //@loc(TypField, "field") 113275- 113276-func _() { 113277- x := &Typ{} 113278- _ = x.field //@def("field", TypField),hover("field", "field", hoverfield) 113279-} 113280- 113281-func (p *Pos) Sum() int { //@loc(PosSum, "Sum") 113282- return p.x + p.y //@hover("x", "x", hoverpx) 113283-} 113284- 113285-func _() { 113286- var p Pos 113287- _ = p.Sum() //@def("()", PosSum),hover("()", `Sum`, hoverSum) 113288-} 113289--- @aPackage/hover.md -- 113290--- @hoverDeclBlocka/hover.md -- 113291-```go 113292-type a struct { 113293- x string 113294-} 113295-``` 113296- 113297-1st type declaration block 113298--- @hoverDeclBlockb/hover.md -- 113299-```go 113300-type b struct{} 113301-``` 113302- 113303-b has a comment 113304--- @hoverDeclBlockc/hover.md -- 113305-```go 113306-type c struct { 113307- f string 113308-} 113309-``` 113310- 113311-c is a struct 113312--- @hoverDeclBlockd/hover.md -- 113313-```go 113314-type d string 113315-``` 113316- 113317-3rd type declaration block 113318--- @hoverDeclBlocke/hover.md -- 113319-```go 113320-type e struct { 113321- f float64 113322-} 113323-``` 113324- 113325-e has a comment 113326--- @hoverH/hover.md -- 113327-```go 113328-type H interface { 113329- Goodbye() 113330-} 113331-``` 113332- 113333-[`a.H` on pkg.go.dev](https://pkg.go.dev/mod.com#H) 113334--- @hoverI/hover.md -- 113335-```go 113336-type I interface { 113337- B() 113338- J 113339-} 113340-``` 113341- 113342-[`a.I` on pkg.go.dev](https://pkg.go.dev/mod.com#I) 113343--- @hoverJ/hover.md -- 113344-```go 113345-type J interface { 113346- Hello() 113347-} 113348-``` 113349- 113350-[`a.J` on pkg.go.dev](https://pkg.go.dev/mod.com#J) 113351--- @hoverSum/hover.md -- 113352-```go 113353-func (*Pos).Sum() int 113354-``` 113355- 113356-[`(a.Pos).Sum` on pkg.go.dev](https://pkg.go.dev/mod.com#Pos.Sum) 113357--- @hoverTestA/hover.md -- 113358-```go 113359-func TestA(t *testing.T) 113360-``` 113361--- @hoverfield/hover.md -- 113362-```go 113363-field field string 113364-``` 113365--- @hoverg/hover.md -- 113366-```go 113367-const g untyped int = 1 113368-``` 113369- 113370-When I hover on g, I should see this comment. 113371--- @hoverh/hover.md -- 113372-```go 113373-const h untyped int = 2 113374-``` 113375- 113376-Constant block. When I hover on h, I should see this comment. 113377--- @hoverpx/hover.md -- 113378-```go 113379-field x int 113380-``` 113381- 113382-@loc(PosX, "x"),loc(PosY, "y") 113383--- @hoverx/hover.md -- 113384-```go 113385-var x string 113386-``` 113387- 113388-x is a variable. 113389--- @hovery/hover.md -- 113390-```go 113391-var y int 113392-``` 113393--- @hoverz/hover.md -- 113394-```go 113395-var z string 113396-``` 113397- 113398-z is a variable too. 113399diff -urN a/gopls/internal/regtest/marker/testdata/hover/basiclit.txt b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt 113400--- a/gopls/internal/regtest/marker/testdata/hover/basiclit.txt 2000-01-01 00:00:00.000000000 -0000 113401+++ b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt 1970-01-01 00:00:00.000000000 +0000 113402@@ -1,60 +0,0 @@ 113403-This test checks gopls behavior when hovering over basic literals. 113404--- basiclit.go -- 113405-package basiclit 113406- 113407-func _() { 113408- _ = 'a' //@hover("'a'", "'a'", latinA) 113409- _ = 0x61 //@hover("0x61", "0x61", latinA) 113410- 113411- _ = '\u2211' //@hover("'\\u2211'", "'\\u2211'", summation) 113412- _ = 0x2211 //@hover("0x2211", "0x2211", summation) 113413- _ = "foo \u2211 bar" //@hover("\\u2211", "\\u2211", summation) 113414- 113415- _ = '\a' //@hover("'\\a'", "'\\a'", control) 113416- _ = "foo \a bar" //@hover("\\a", "\\a", control) 113417- 113418- _ = '\U0001F30A' //@hover("'\\U0001F30A'", "'\\U0001F30A'", waterWave) 113419- _ = 0x0001F30A //@hover("0x0001F30A", "0x0001F30A", waterWave) 113420- _ = "foo \U0001F30A bar" //@hover("\\U0001F30A", "\\U0001F30A", waterWave) 113421- 113422- _ = '\x7E' //@hover("'\\x7E'", "'\\x7E'", tilde) 113423- _ = "foo \x7E bar" //@hover("\\x7E", "\\x7E", tilde) 113424- _ = "foo \a bar" //@hover("\\a", "\\a", control) 113425- 113426- _ = '\173' //@hover("'\\173'", "'\\173'", leftCurly) 113427- _ = "foo \173 bar" //@hover("\\173","\\173", leftCurly) 113428- _ = "foo \173 bar \u2211 baz" //@hover("\\173","\\173", leftCurly) 113429- _ = "foo \173 bar \u2211 baz" //@hover("\\u2211","\\u2211", summation) 113430- _ = "foo\173bar\u2211baz" //@hover("\\173","\\173", leftCurly) 113431- _ = "foo\173bar\u2211baz" //@hover("\\u2211","\\u2211", summation) 113432- 113433- // search for runes in string only if there is an escaped sequence 113434- _ = "hello" //@hover(`"hello"`, _, _) 113435- 113436- // incorrect escaped rune sequences 113437- _ = '\0' //@hover("'\\0'", _, _),diag(re`\\0()'`, re"illegal character") 113438- _ = '\u22111' //@hover("'\\u22111'", _, _) 113439- _ = '\U00110000' //@hover("'\\U00110000'", _, _) 113440- _ = '\u12e45'//@hover("'\\u12e45'", _, _) 113441- _ = '\xa' //@hover("'\\xa'", _, _) 113442- _ = 'aa' //@hover("'aa'", _, _) 113443- 113444- // other basic lits 113445- _ = 1 //@hover("1", _, _) 113446- _ = 1.2 //@hover("1.2", _, _) 113447- _ = 1.2i //@hover("1.2i", _, _) 113448- _ = 0123 //@hover("0123", _, _) 113449- _ = 0x1234567890 //@hover("0x1234567890", _, _) 113450-) 113451--- @control/hover.md -- 113452-U+0007, control 113453--- @latinA/hover.md -- 113454-'a', U+0061, LATIN SMALL LETTER A 113455--- @leftCurly/hover.md -- 113456-'{', U+007B, LEFT CURLY BRACKET 113457--- @summation/hover.md -- 113458-'∑', U+2211, N-ARY SUMMATION 113459--- @tilde/hover.md -- 113460-'~', U+007E, TILDE 113461--- @waterWave/hover.md -- 113462-'', U+1F30A, WATER WAVE 113463diff -urN a/gopls/internal/regtest/marker/testdata/hover/const.txt b/gopls/internal/regtest/marker/testdata/hover/const.txt 113464--- a/gopls/internal/regtest/marker/testdata/hover/const.txt 2000-01-01 00:00:00.000000000 -0000 113465+++ b/gopls/internal/regtest/marker/testdata/hover/const.txt 1970-01-01 00:00:00.000000000 +0000 113466@@ -1,18 +0,0 @@ 113467-This test checks hovering over constants. 113468--- go.mod -- 113469-module mod.com 113470- 113471-go 1.18 113472--- c.go -- 113473-package c 113474- 113475-const X = 0 //@hover("X", "X", bX) 113476--- @bX/hover.md -- 113477-```go 113478-const X untyped int = 0 113479-``` 113480- 113481-@hover("X", "X", bX) 113482- 113483- 113484-[`c.X` on pkg.go.dev](https://pkg.go.dev/mod.com#X) 113485diff -urN a/gopls/internal/regtest/marker/testdata/hover/generics.txt b/gopls/internal/regtest/marker/testdata/hover/generics.txt 113486--- a/gopls/internal/regtest/marker/testdata/hover/generics.txt 2000-01-01 00:00:00.000000000 -0000 113487+++ b/gopls/internal/regtest/marker/testdata/hover/generics.txt 1970-01-01 00:00:00.000000000 +0000 113488@@ -1,77 +0,0 @@ 113489-This file contains tests for hovering over generic Go code. 113490- 113491--- flags -- 113492--min_go=go1.18 113493- 113494--- go.mod -- 113495-// A go.mod is require for correct pkgsite links. 113496-// TODO(rfindley): don't link to ad-hoc or command-line-arguments packages! 113497-module mod.com 113498- 113499-go 1.18 113500- 113501--- generics.go -- 113502-package generics 113503- 113504-type value[T any] struct { //hover("lue", "value", value),hover("T", "T", valueT) 113505- val T //@hover("T", "T", valuevalT) 113506- Q int //@hover("Q", "Q", valueQ) 113507-} 113508- 113509-type Value[T any] struct { //@hover("T", "T", ValueT) 113510- val T //@hover("T", "T", ValuevalT) 113511- Q int //@hover("Q", "Q", ValueQ) 113512-} 113513- 113514-// disabled - see issue #54822 113515-func F[P interface{ ~int | string }]() { // hover("P","P",Ptparam) 113516- // disabled - see issue #54822 113517- var _ P // hover("P","P",Pvar) 113518-} 113519- 113520--- inferred.go -- 113521-package generics 113522- 113523-func app[S interface{ ~[]E }, E interface{}](s S, e E) S { 113524- return append(s, e) 113525-} 113526- 113527-func _() { 113528- _ = app[[]int] //@hover("app", "app", appint) 113529- _ = app[[]int, int] //@hover("app", "app", appint) 113530- // TODO(rfindley): eliminate this diagnostic. 113531- _ = app[[]int]([]int{}, 0) //@hover("app", "app", appint),diag("[[]int]", re"unnecessary type arguments") 113532- _ = app([]int{}, 0) //@hover("app", "app", appint) 113533-} 113534- 113535--- @ValueQ/hover.md -- 113536-```go 113537-field Q int 113538-``` 113539- 113540-@hover("Q", "Q", ValueQ) 113541- 113542- 113543-[`(generics.Value).Q` on pkg.go.dev](https://pkg.go.dev/mod.com#Value.Q) 113544--- @ValueT/hover.md -- 113545-```go 113546-type parameter T any 113547-``` 113548--- @ValuevalT/hover.md -- 113549-```go 113550-type parameter T any 113551-``` 113552--- @appint/hover.md -- 113553-```go 113554-func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S 113555-``` 113556--- @valueQ/hover.md -- 113557-```go 113558-field Q int 113559-``` 113560- 113561-@hover("Q", "Q", valueQ) 113562--- @valuevalT/hover.md -- 113563-```go 113564-type parameter T any 113565-``` 113566diff -urN a/gopls/internal/regtest/marker/testdata/hover/goprivate.txt b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt 113567--- a/gopls/internal/regtest/marker/testdata/hover/goprivate.txt 2000-01-01 00:00:00.000000000 -0000 113568+++ b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt 1970-01-01 00:00:00.000000000 +0000 113569@@ -1,27 +0,0 @@ 113570-This test checks that links in hover obey GOPRIVATE. 113571--- env -- 113572-GOPRIVATE=mod.com 113573--- go.mod -- 113574-module mod.com 113575--- p.go -- 113576-package p 113577- 113578-// T should not be linked, as it is private. 113579-type T struct{} //@hover("T", "T", T) 113580--- lib/lib.go -- 113581-package lib 113582- 113583-// GOPRIVATE should also match nested packages. 113584-type L struct{} //@hover("L", "L", L) 113585--- @L/hover.md -- 113586-```go 113587-type L struct{} 113588-``` 113589- 113590-GOPRIVATE should also match nested packages. 113591--- @T/hover.md -- 113592-```go 113593-type T struct{} 113594-``` 113595- 113596-T should not be linked, as it is private. 113597diff -urN a/gopls/internal/regtest/marker/testdata/hover/hover.txt b/gopls/internal/regtest/marker/testdata/hover/hover.txt 113598--- a/gopls/internal/regtest/marker/testdata/hover/hover.txt 2000-01-01 00:00:00.000000000 -0000 113599+++ b/gopls/internal/regtest/marker/testdata/hover/hover.txt 1970-01-01 00:00:00.000000000 +0000 113600@@ -1,29 +0,0 @@ 113601-This test demonstrates some features of the new marker test runner. 113602--- a.go -- 113603-package a 113604- 113605-const abc = 0x2a //@hover("b", "abc", abc),hover(" =", "abc", abc) 113606--- typeswitch.go -- 113607-package a 113608- 113609-func _() { 113610- var y interface{} 113611- switch x := y.(type) { //@hover("x", "x", x) 113612- case int: 113613- println(x) //@hover("x", "x", xint),hover(")", "x", xint) 113614- } 113615-} 113616--- @abc/hover.md -- 113617-```go 113618-const abc untyped int = 42 113619-``` 113620- 113621-@hover("b", "abc", abc),hover(" =", "abc", abc) 113622--- @x/hover.md -- 113623-```go 113624-var x interface{} 113625-``` 113626--- @xint/hover.md -- 113627-```go 113628-var x int 113629-``` 113630diff -urN a/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt 113631--- a/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt 2000-01-01 00:00:00.000000000 -0000 113632+++ b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt 1970-01-01 00:00:00.000000000 +0000 113633@@ -1,145 +0,0 @@ 113634-This file contains tests for documentation links to generic code in hover. 113635- 113636--- flags -- 113637--min_go=go1.18 113638- 113639--- go.mod -- 113640-module mod.com 113641- 113642-go 1.19 113643- 113644--- a.go -- 113645-package a 113646- 113647-import "mod.com/generic" 113648- 113649-func _() { 113650- // Hovering over instantiated object should produce accurate type 113651- // information, but link to the generic declarations. 113652- 113653- var x generic.GT[int] //@hover("GT", "GT", xGT) 113654- _ = x.F //@hover("x", "x", x),hover("F", "F", xF) 113655- 113656- f := generic.GF[int] //@hover("GF", "GF", fGF) 113657- _ = f //@hover("f", "f", f) 113658-} 113659- 113660--- generic/generic.go -- 113661-package generic 113662- 113663-// Hovering over type parameters should link to documentation. 113664-// 113665-// TODO(rfindley): should it? We should probably link to the type. 113666-type GT[P any] struct{ //@hover("GT", "GT", GT),hover("P", "P", GTP) 113667- F P //@hover("F", "F", F),hover("P", "P", FP) 113668-} 113669- 113670-func (GT[P]) M(p P) { //@hover("GT", "GT", GTrecv),hover("M","M", M),hover(re"p (P)", re"p (P)", pP) 113671-} 113672- 113673-func GF[P any] (p P) { //@hover("GF", "GF", GF) 113674-} 113675- 113676--- @F/hover.md -- 113677-```go 113678-field F P 113679-``` 113680- 113681-@hover("F", "F", F),hover("P", "P", FP) 113682- 113683- 113684-[`(generic.GT).F` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT.F) 113685--- @FP/hover.md -- 113686-```go 113687-type parameter P any 113688-``` 113689--- @GF/hover.md -- 113690-```go 113691-func GF[P any](p P) 113692-``` 113693- 113694-[`generic.GF` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GF) 113695--- @GT/hover.md -- 113696-```go 113697-type GT[P any] struct { 113698- F P //@hover("F", "F", F),hover("P", "P", FP) 113699-} 113700- 113701-func (GT[P]).M(p P) 113702-``` 113703- 113704-Hovering over type parameters should link to documentation. 113705- 113706-TODO(rfindley): should it? We should probably link to the type. 113707- 113708- 113709-[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT) 113710--- @GTP/hover.md -- 113711-```go 113712-type parameter P any 113713-``` 113714--- @GTrecv/hover.md -- 113715-```go 113716-type GT[P any] struct { 113717- F P //@hover("F", "F", F),hover("P", "P", FP) 113718-} 113719- 113720-func (GT[P]).M(p P) 113721-``` 113722- 113723-Hovering over type parameters should link to documentation. 113724- 113725-TODO(rfindley): should it? We should probably link to the type. 113726- 113727- 113728-[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT) 113729--- @M/hover.md -- 113730-```go 113731-func (GT[P]).M(p P) 113732-``` 113733- 113734-[`(generic.GT).M` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT.M) 113735--- @f/hover.md -- 113736-```go 113737-var f func(p int) 113738-``` 113739--- @fGF/hover.md -- 113740-```go 113741-func generic.GF(p int) // func[P any](p P) 113742-``` 113743- 113744-[`generic.GF` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GF) 113745--- @pP/hover.md -- 113746-```go 113747-type parameter P any 113748-``` 113749--- @x/hover.md -- 113750-```go 113751-var x generic.GT[int] 113752-``` 113753- 113754-@hover("GT", "GT", xGT) 113755--- @xF/hover.md -- 113756-```go 113757-field F int 113758-``` 113759- 113760-@hover("F", "F", F),hover("P", "P", FP) 113761- 113762- 113763-[`(generic.GT).F` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT.F) 113764--- @xGT/hover.md -- 113765-```go 113766-type GT[P any] struct { 113767- F P //@hover("F", "F", F),hover("P", "P", FP) 113768-} 113769- 113770-func (generic.GT[P]).M(p P) 113771-``` 113772- 113773-Hovering over type parameters should link to documentation. 113774- 113775-TODO(rfindley): should it? We should probably link to the type. 113776- 113777- 113778-[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT) 113779diff -urN a/gopls/internal/regtest/marker/testdata/hover/linkable.txt b/gopls/internal/regtest/marker/testdata/hover/linkable.txt 113780--- a/gopls/internal/regtest/marker/testdata/hover/linkable.txt 2000-01-01 00:00:00.000000000 -0000 113781+++ b/gopls/internal/regtest/marker/testdata/hover/linkable.txt 1970-01-01 00:00:00.000000000 +0000 113782@@ -1,120 +0,0 @@ 113783-This test checks that we correctly determine pkgsite links for various 113784-identifiers. 113785- 113786-We should only produce links that work, meaning the object is reachable via the 113787-package's public API. 113788--- go.mod -- 113789-module mod.com 113790- 113791-go 1.18 113792--- p.go -- 113793-package p 113794- 113795-type E struct { 113796- Embed int 113797-} 113798- 113799-// T is in the package scope, and so should be linkable. 113800-type T struct{ //@hover("T", "T", T) 113801- // Only exported fields should be linkable 113802- 113803- f int //@hover("f", "f", f) 113804- F int //@hover("F", "F", F) 113805- 113806- E 113807- 113808- // TODO(rfindley): is the link here correct? It ignores N. 113809- N struct { 113810- // Nested fields should also be linkable. 113811- Nested int //@hover("Nested", "Nested", Nested) 113812- } 113813-} 113814-// M is an exported method, and so should be linkable. 113815-func (T) M() {} 113816- 113817-// m is not exported, and so should not be linkable. 113818-func (T) m() {} 113819- 113820-func _() { 113821- var t T 113822- 113823- // Embedded fields should be linkable. 113824- _ = t.Embed //@hover("Embed", "Embed", Embed) 113825- 113826- // Local variables should not be linkable, even if they are capitalized. 113827- var X int //@hover("X", "X", X) 113828- _ = X 113829- 113830- // Local types should not be linkable, even if they are capitalized. 113831- type Local struct { //@hover("Local", "Local", Local) 113832- E 113833- } 113834- 113835- // But the embedded field should still be linkable. 113836- var l Local 113837- _ = l.Embed //@hover("Embed", "Embed", Embed) 113838-} 113839--- @Embed/hover.md -- 113840-```go 113841-field Embed int 113842-``` 113843- 113844-[`(p.E).Embed` on pkg.go.dev](https://pkg.go.dev/mod.com#E.Embed) 113845--- @F/hover.md -- 113846-```go 113847-field F int 113848-``` 113849- 113850-@hover("F", "F", F) 113851- 113852- 113853-[`(p.T).F` on pkg.go.dev](https://pkg.go.dev/mod.com#T.F) 113854--- @Local/hover.md -- 113855-```go 113856-type Local struct { 113857- E 113858-} 113859-``` 113860- 113861-Local types should not be linkable, even if they are capitalized. 113862--- @Nested/hover.md -- 113863-```go 113864-field Nested int 113865-``` 113866- 113867-Nested fields should also be linkable. 113868--- @T/hover.md -- 113869-```go 113870-type T struct { 113871- f int //@hover("f", "f", f) 113872- F int //@hover("F", "F", F) 113873- 113874- E 113875- 113876- // TODO(rfindley): is the link here correct? It ignores N. 113877- N struct { 113878- // Nested fields should also be linkable. 113879- Nested int //@hover("Nested", "Nested", Nested) 113880- } 113881-} 113882- 113883-func (T).M() 113884-func (T).m() 113885-``` 113886- 113887-T is in the package scope, and so should be linkable. 113888- 113889- 113890-[`p.T` on pkg.go.dev](https://pkg.go.dev/mod.com#T) 113891--- @X/hover.md -- 113892-```go 113893-var X int 113894-``` 113895- 113896-Local variables should not be linkable, even if they are capitalized. 113897--- @f/hover.md -- 113898-```go 113899-field f int 113900-``` 113901- 113902-@hover("f", "f", f) 113903diff -urN a/gopls/internal/regtest/marker/testdata/hover/std.txt b/gopls/internal/regtest/marker/testdata/hover/std.txt 113904--- a/gopls/internal/regtest/marker/testdata/hover/std.txt 2000-01-01 00:00:00.000000000 -0000 113905+++ b/gopls/internal/regtest/marker/testdata/hover/std.txt 1970-01-01 00:00:00.000000000 +0000 113906@@ -1,80 +0,0 @@ 113907-This test checks hover results for built-in or standard library symbols. 113908- 113909-It uses synopsis documentation as full documentation for some of these 113910-built-ins varies across Go versions, where as it just so happens that the 113911-synopsis does not. 113912- 113913-In the future we may need to limit this test to the latest Go version to avoid 113914-documentation churn. 113915--- settings.json -- 113916-{ 113917- "hoverKind": "SynopsisDocumentation" 113918-} 113919--- go.mod -- 113920-module mod.com 113921- 113922-go 1.18 113923--- std.go -- 113924-package std 113925- 113926-import ( 113927- "fmt" 113928- "go/types" 113929- "sync" 113930-) 113931- 113932-func _() { 113933- var err error //@loc(err, "err") 113934- fmt.Printf("%v", err) //@def("err", err) 113935- 113936- var _ string //@hover("string", "string", hoverstring) 113937- _ = make([]int, 0) //@hover("make", "make", hovermake) 113938- 113939- var mu sync.Mutex 113940- mu.Lock() //@hover("Lock", "Lock", hoverLock) 113941- 113942- var typ *types.Named //@hover("types", "types", hoverTypes) 113943- typ.Obj().Name() //@hover("Name", "Name", hoverName) 113944-} 113945--- @hoverLock/hover.md -- 113946-```go 113947-func (*sync.Mutex).Lock() 113948-``` 113949- 113950-Lock locks m. 113951- 113952- 113953-[`(sync.Mutex).Lock` on pkg.go.dev](https://pkg.go.dev/sync#Mutex.Lock) 113954--- @hoverName/hover.md -- 113955-```go 113956-func (*types.object).Name() string 113957-``` 113958- 113959-Name returns the object's (package-local, unqualified) name. 113960- 113961- 113962-[`(types.TypeName).Name` on pkg.go.dev](https://pkg.go.dev/go/types#TypeName.Name) 113963--- @hoverTypes/hover.md -- 113964-```go 113965-package types ("go/types") 113966-``` 113967- 113968-[`types` on pkg.go.dev](https://pkg.go.dev/go/types) 113969--- @hovermake/hover.md -- 113970-```go 113971-func make(t Type, size ...int) Type 113972-``` 113973- 113974-The make built-in function allocates and initializes an object of type slice, map, or chan (only). 113975- 113976- 113977-[`make` on pkg.go.dev](https://pkg.go.dev/builtin#make) 113978--- @hoverstring/hover.md -- 113979-```go 113980-type string string 113981-``` 113982- 113983-string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text. 113984- 113985- 113986-[`string` on pkg.go.dev](https://pkg.go.dev/builtin#string) 113987diff -urN a/gopls/internal/regtest/marker/testdata/rename/basic.txt b/gopls/internal/regtest/marker/testdata/rename/basic.txt 113988--- a/gopls/internal/regtest/marker/testdata/rename/basic.txt 2000-01-01 00:00:00.000000000 -0000 113989+++ b/gopls/internal/regtest/marker/testdata/rename/basic.txt 1970-01-01 00:00:00.000000000 +0000 113990@@ -1,22 +0,0 @@ 113991-This test performs basic coverage of 'rename' within a single package. 113992- 113993--- basic.go -- 113994-package p 113995- 113996-func f(x int) { println(x) } //@rename("x", y, param_x) 113997- 113998--- @param_x/basic.go -- 113999-package p 114000- 114001-func f(y int) { println(y) } //@rename("x", y, param_x) 114002- 114003--- errors.go -- 114004-package p 114005- 114006-func _(x []int) { //@renameerr("_", blank, `can't rename "_"`) 114007- x = append(x, 1) //@renameerr("append", blank, "built in and cannot be renamed") 114008- x = nil //@renameerr("nil", blank, "built in and cannot be renamed") 114009- x = nil //@renameerr("x", x, "old and new names are the same: x") 114010- _ = 1 //@renameerr("1", x, "no identifier found") 114011-} 114012- 114013diff -urN a/gopls/internal/regtest/marker/testdata/rename/conflict.txt b/gopls/internal/regtest/marker/testdata/rename/conflict.txt 114014--- a/gopls/internal/regtest/marker/testdata/rename/conflict.txt 2000-01-01 00:00:00.000000000 -0000 114015+++ b/gopls/internal/regtest/marker/testdata/rename/conflict.txt 1970-01-01 00:00:00.000000000 +0000 114016@@ -1,59 +0,0 @@ 114017-This test exercises some renaming conflict scenarios 114018-and ensures that the errors are informative. 114019- 114020--- go.mod -- 114021-module example.com 114022-go 1.12 114023- 114024--- super/p.go -- 114025-package super 114026- 114027-var x int 114028- 114029-func f(y int) { 114030- println(x) 114031- println(y) //@renameerr("y", x, errSuperBlockConflict) 114032-} 114033- 114034--- @errSuperBlockConflict -- 114035-super/p.go:5:8: renaming this var "y" to "x" 114036-super/p.go:6:10: would shadow this reference 114037-super/p.go:3:5: to the var declared here 114038--- sub/p.go -- 114039-package sub 114040- 114041-var a int 114042- 114043-func f2(b int) { 114044- println(a) //@renameerr("a", b, errSubBlockConflict) 114045- println(b) 114046-} 114047- 114048--- @errSubBlockConflict -- 114049-sub/p.go:3:5: renaming this var "a" to "b" 114050-sub/p.go:6:10: would cause this reference to become shadowed 114051-sub/p.go:5:9: by this intervening var definition 114052--- pkgname/p.go -- 114053-package pkgname 114054- 114055-import e1 "errors" //@renameerr("e1", errors, errImportConflict) 114056-import "errors" 114057- 114058-var _ = errors.New 114059-var _ = e1.New 114060- 114061--- @errImportConflict -- 114062-pkgname/p.go:3:8: renaming this imported package name "e1" to "errors" 114063-pkgname/p.go:4:8: conflicts with imported package name in same block 114064--- pkgname2/p1.go -- 114065-package pkgname2 114066-var x int 114067- 114068--- pkgname2/p2.go -- 114069-package pkgname2 114070-import "errors" //@renameerr("errors", x, errImportConflict2) 114071-var _ = errors.New 114072- 114073--- @errImportConflict2 -- 114074-pkgname2/p2.go:2:8: renaming this imported package name "errors" to "x" would conflict 114075-pkgname2/p1.go:2:5: with this package member var 114076diff -urN a/gopls/internal/regtest/marker/testdata/rename/embed.txt b/gopls/internal/regtest/marker/testdata/rename/embed.txt 114077--- a/gopls/internal/regtest/marker/testdata/rename/embed.txt 2000-01-01 00:00:00.000000000 -0000 114078+++ b/gopls/internal/regtest/marker/testdata/rename/embed.txt 1970-01-01 00:00:00.000000000 +0000 114079@@ -1,36 +0,0 @@ 114080-This test exercises renaming of types used as embedded fields. 114081- 114082--- go.mod -- 114083-module example.com 114084-go 1.12 114085- 114086--- a/a.go -- 114087-package a 114088- 114089-type A int //@rename("A", A2, type) 114090- 114091--- b/b.go -- 114092-package b 114093- 114094-import "example.com/a" 114095- 114096-type B struct { a.A } //@renameerr("A", A3, errAnonField) 114097- 114098-var _ = new(B).A //@renameerr("A", A4, errAnonField) 114099- 114100--- @errAnonField -- 114101-can't rename embedded fields: rename the type directly or name the field 114102--- @type/a/a.go -- 114103-package a 114104- 114105-type A2 int //@rename("A", A2, type) 114106- 114107--- @type/b/b.go -- 114108-package b 114109- 114110-import "example.com/a" 114111- 114112-type B struct { a.A2 } //@renameerr("A", A3, errAnonField) 114113- 114114-var _ = new(B).A2 //@renameerr("A", A4, errAnonField) 114115- 114116diff -urN a/gopls/internal/regtest/marker/testdata/rename/methods.txt b/gopls/internal/regtest/marker/testdata/rename/methods.txt 114117--- a/gopls/internal/regtest/marker/testdata/rename/methods.txt 2000-01-01 00:00:00.000000000 -0000 114118+++ b/gopls/internal/regtest/marker/testdata/rename/methods.txt 1970-01-01 00:00:00.000000000 +0000 114119@@ -1,67 +0,0 @@ 114120-This test exercises renaming of interface methods. 114121- 114122-The golden is currently wrong due to https://github.com/golang/go/issues/58506: 114123-the reference to B.F in package b should be renamed too. 114124- 114125--- go.mod -- 114126-module example.com 114127-go 1.12 114128- 114129--- a/a.go -- 114130-package a 114131- 114132-type A int 114133- 114134-func (A) F() {} //@renameerr("F", G, errAfToG) 114135- 114136--- b/b.go -- 114137-package b 114138- 114139-import "example.com/a" 114140-import "example.com/c" 114141- 114142-type B interface { F() } //@rename("F", G, BfToG) 114143- 114144-var _ B = a.A(0) 114145-var _ B = c.C(0) 114146- 114147--- c/c.go -- 114148-package c 114149- 114150-type C int 114151- 114152-func (C) F() {} //@renameerr("F", G, errCfToG) 114153- 114154--- d/d.go -- 114155-package d 114156- 114157-import "example.com/b" 114158- 114159-var _ = b.B.F 114160- 114161--- @errAfToG -- 114162-a/a.go:5:10: renaming this method "F" to "G" 114163-b/b.go:6:6: would make example.com/a.A no longer assignable to interface B 114164-b/b.go:6:20: (rename example.com/b.B.F if you intend to change both types) 114165--- @BfToG/b/b.go -- 114166-package b 114167- 114168-import "example.com/a" 114169-import "example.com/c" 114170- 114171-type B interface { G() } //@rename("F", G, BfToG) 114172- 114173-var _ B = a.A(0) 114174-var _ B = c.C(0) 114175- 114176--- @BfToG/d/d.go -- 114177-package d 114178- 114179-import "example.com/b" 114180- 114181-var _ = b.B.G 114182- 114183--- @errCfToG -- 114184-c/c.go:5:10: renaming this method "F" to "G" 114185-b/b.go:6:6: would make example.com/c.C no longer assignable to interface B 114186-b/b.go:6:20: (rename example.com/b.B.F if you intend to change both types) 114187diff -urN a/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt 114188--- a/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt 2000-01-01 00:00:00.000000000 -0000 114189+++ b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt 1970-01-01 00:00:00.000000000 +0000 114190@@ -1,26 +0,0 @@ 114191-This test covers the special case of renaming a type switch var. 114192- 114193--- p.go -- 114194-package p 114195- 114196-func _(x interface{}) { 114197- switch y := x.(type) { //@rename("y", z, yToZ) 114198- case string: 114199- print(y) //@rename("y", z, yToZ) 114200- default: 114201- print(y) //@rename("y", z, yToZ) 114202- } 114203-} 114204- 114205--- @yToZ/p.go -- 114206-package p 114207- 114208-func _(x interface{}) { 114209- switch z := x.(type) { //@rename("y", z, yToZ) 114210- case string: 114211- print(z) //@rename("y", z, yToZ) 114212- default: 114213- print(z) //@rename("y", z, yToZ) 114214- } 114215-} 114216- 114217diff -urN a/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt 114218--- a/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt 2000-01-01 00:00:00.000000000 -0000 114219+++ b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt 1970-01-01 00:00:00.000000000 +0000 114220@@ -1,24 +0,0 @@ 114221-This test exercises basic 'stub methods' functionality. 114222- 114223--- go.mod -- 114224-module example.com 114225-go 1.12 114226- 114227--- a/a.go -- 114228-package a 114229- 114230-type C int 114231- 114232-var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "refactor.rewrite", stub) 114233- 114234--- @stub/a/a.go -- 114235-package a 114236- 114237-type C int 114238- 114239-// Error implements error 114240-func (C) Error() string { 114241- panic("unimplemented") 114242-} 114243- 114244-var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "refactor.rewrite", stub) 114245diff -urN a/gopls/internal/regtest/misc/call_hierarchy_test.go b/gopls/internal/regtest/misc/call_hierarchy_test.go 114246--- a/gopls/internal/regtest/misc/call_hierarchy_test.go 2000-01-01 00:00:00.000000000 -0000 114247+++ b/gopls/internal/regtest/misc/call_hierarchy_test.go 1970-01-01 00:00:00.000000000 +0000 114248@@ -1,35 +0,0 @@ 114249-// Copyright 2021 The Go Authors. All rights reserved. 114250-// Use of this source code is governed by a BSD-style 114251-// license that can be found in the LICENSE file. 114252-package misc 114253- 114254-import ( 114255- "testing" 114256- 114257- "golang.org/x/tools/gopls/internal/lsp/protocol" 114258- . "golang.org/x/tools/gopls/internal/lsp/regtest" 114259-) 114260- 114261-// Test for golang/go#49125 114262-func TestCallHierarchy_Issue49125(t *testing.T) { 114263- const files = ` 114264--- go.mod -- 114265-module mod.com 114266- 114267-go 1.12 114268--- p.go -- 114269-package pkg 114270-` 114271- // TODO(rfindley): this could probably just be a marker test. 114272- Run(t, files, func(t *testing.T, env *Env) { 114273- env.OpenFile("p.go") 114274- loc := env.RegexpSearch("p.go", "pkg") 114275- 114276- var params protocol.CallHierarchyPrepareParams 114277- params.TextDocument.URI = loc.URI 114278- params.Position = loc.Range.Start 114279- 114280- // Check that this doesn't panic. 114281- env.Editor.Server.PrepareCallHierarchy(env.Ctx, ¶ms) 114282- }) 114283-} 114284diff -urN a/gopls/internal/regtest/misc/configuration_test.go b/gopls/internal/regtest/misc/configuration_test.go 114285--- a/gopls/internal/regtest/misc/configuration_test.go 2000-01-01 00:00:00.000000000 -0000 114286+++ b/gopls/internal/regtest/misc/configuration_test.go 1970-01-01 00:00:00.000000000 +0000 114287@@ -1,159 +0,0 @@ 114288-// Copyright 2020 The Go Authors. All rights reserved. 114289-// Use of this source code is governed by a BSD-style 114290-// license that can be found in the LICENSE file. 114291- 114292-package misc 114293- 114294-import ( 114295- "testing" 114296- 114297- . "golang.org/x/tools/gopls/internal/lsp/regtest" 114298- 114299- "golang.org/x/tools/internal/testenv" 114300-) 114301- 114302-// Test that enabling and disabling produces the expected results of showing 114303-// and hiding staticcheck analysis results. 114304-func TestChangeConfiguration(t *testing.T) { 114305- // Staticcheck only supports Go versions >= 1.19. 114306- // Note: keep this in sync with TestStaticcheckWarning. Below this version we 114307- // should get an error when setting staticcheck configuration. 114308- testenv.NeedsGo1Point(t, 19) 114309- 114310- const files = ` 114311--- go.mod -- 114312-module mod.com 114313- 114314-go 1.12 114315--- a/a.go -- 114316-package a 114317- 114318-import "errors" 114319- 114320-// FooErr should be called ErrFoo (ST1012) 114321-var FooErr = errors.New("foo") 114322-` 114323- Run(t, files, func(t *testing.T, env *Env) { 114324- env.OpenFile("a/a.go") 114325- env.AfterChange( 114326- NoDiagnostics(ForFile("a/a.go")), 114327- ) 114328- cfg := env.Editor.Config() 114329- cfg.Settings = map[string]interface{}{ 114330- "staticcheck": true, 114331- } 114332- // TODO(rfindley): support waiting on diagnostics following a configuration 114333- // change. 114334- env.ChangeConfiguration(cfg) 114335- env.Await( 114336- Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)")), 114337- ) 114338- }) 114339-} 114340- 114341-// TestMajorOptionsChange is like TestChangeConfiguration, but modifies an 114342-// an open buffer before making a major (but inconsequential) change that 114343-// causes gopls to recreate the view. 114344-// 114345-// Gopls should not get confused about buffer content when recreating the view. 114346-func TestMajorOptionsChange(t *testing.T) { 114347- t.Skip("broken due to golang/go#57934") 114348- 114349- testenv.NeedsGo1Point(t, 17) 114350- 114351- const files = ` 114352--- go.mod -- 114353-module mod.com 114354- 114355-go 1.12 114356--- a/a.go -- 114357-package a 114358- 114359-import "errors" 114360- 114361-var ErrFoo = errors.New("foo") 114362-` 114363- Run(t, files, func(t *testing.T, env *Env) { 114364- env.OpenFile("a/a.go") 114365- // Introduce a staticcheck diagnostic. It should be detected when we enable 114366- // staticcheck later. 114367- env.RegexpReplace("a/a.go", "ErrFoo", "FooErr") 114368- env.AfterChange( 114369- NoDiagnostics(ForFile("a/a.go")), 114370- ) 114371- cfg := env.Editor.Config() 114372- // Any change to environment recreates the view, but this should not cause 114373- // gopls to get confused about the content of a/a.go: we should get the 114374- // staticcheck diagnostic below. 114375- cfg.Env = map[string]string{ 114376- "AN_ARBITRARY_VAR": "FOO", 114377- } 114378- cfg.Settings = map[string]interface{}{ 114379- "staticcheck": true, 114380- } 114381- // TODO(rfindley): support waiting on diagnostics following a configuration 114382- // change. 114383- env.ChangeConfiguration(cfg) 114384- env.Await( 114385- Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)")), 114386- ) 114387- }) 114388-} 114389- 114390-func TestStaticcheckWarning(t *testing.T) { 114391- // Note: keep this in sync with TestChangeConfiguration. 114392- testenv.SkipAfterGo1Point(t, 16) 114393- 114394- const files = ` 114395--- go.mod -- 114396-module mod.com 114397- 114398-go 1.12 114399--- a/a.go -- 114400-package a 114401- 114402-import "errors" 114403- 114404-// FooErr should be called ErrFoo (ST1012) 114405-var FooErr = errors.New("foo") 114406-` 114407- 114408- WithOptions( 114409- Settings{"staticcheck": true}, 114410- ).Run(t, files, func(t *testing.T, env *Env) { 114411- env.OnceMet( 114412- InitialWorkspaceLoad, 114413- ShownMessage("staticcheck is not supported"), 114414- ) 114415- }) 114416-} 114417- 114418-func TestGofumptWarning(t *testing.T) { 114419- testenv.SkipAfterGo1Point(t, 17) 114420- 114421- WithOptions( 114422- Settings{"gofumpt": true}, 114423- ).Run(t, "", func(t *testing.T, env *Env) { 114424- env.OnceMet( 114425- InitialWorkspaceLoad, 114426- ShownMessage("gofumpt is not supported"), 114427- ) 114428- }) 114429-} 114430- 114431-func TestDeprecatedSettings(t *testing.T) { 114432- WithOptions( 114433- Settings{ 114434- "experimentalUseInvalidMetadata": true, 114435- "experimentalWatchedFileDelay": "1s", 114436- "experimentalWorkspaceModule": true, 114437- }, 114438- ).Run(t, "", func(t *testing.T, env *Env) { 114439- env.OnceMet( 114440- InitialWorkspaceLoad, 114441- ShownMessage("experimentalWorkspaceModule"), 114442- ShownMessage("experimentalUseInvalidMetadata"), 114443- ShownMessage("experimentalWatchedFileDelay"), 114444- ) 114445- }) 114446-} 114447diff -urN a/gopls/internal/regtest/misc/debugserver_test.go b/gopls/internal/regtest/misc/debugserver_test.go 114448--- a/gopls/internal/regtest/misc/debugserver_test.go 2000-01-01 00:00:00.000000000 -0000 114449+++ b/gopls/internal/regtest/misc/debugserver_test.go 1970-01-01 00:00:00.000000000 +0000 114450@@ -1,46 +0,0 @@ 114451-// Copyright 2021 The Go Authors. All rights reserved. 114452-// Use of this source code is governed by a BSD-style 114453-// license that can be found in the LICENSE file. 114454- 114455-package misc 114456- 114457-import ( 114458- "net/http" 114459- "testing" 114460- 114461- "golang.org/x/tools/gopls/internal/lsp/command" 114462- "golang.org/x/tools/gopls/internal/lsp/protocol" 114463- 114464- . "golang.org/x/tools/gopls/internal/lsp/regtest" 114465-) 114466- 114467-func TestStartDebugging(t *testing.T) { 114468- WithOptions( 114469- Modes(Forwarded), 114470- ).Run(t, "", func(t *testing.T, env *Env) { 114471- args, err := command.MarshalArgs(command.DebuggingArgs{}) 114472- if err != nil { 114473- t.Fatal(err) 114474- } 114475- params := &protocol.ExecuteCommandParams{ 114476- Command: command.StartDebugging.ID(), 114477- Arguments: args, 114478- } 114479- var result command.DebuggingResult 114480- env.ExecuteCommand(params, &result) 114481- if got, want := len(result.URLs), 2; got != want { 114482- t.Fatalf("got %d urls, want %d; urls: %#v", got, want, result.URLs) 114483- } 114484- for i, u := range result.URLs { 114485- resp, err := http.Get(u) 114486- if err != nil { 114487- t.Errorf("getting url #%d (%q): %v", i, u, err) 114488- continue 114489- } 114490- defer resp.Body.Close() 114491- if got, want := resp.StatusCode, http.StatusOK; got != want { 114492- t.Errorf("debug server #%d returned HTTP %d, want %d", i, got, want) 114493- } 114494- } 114495- }) 114496-} 114497diff -urN a/gopls/internal/regtest/misc/definition_test.go b/gopls/internal/regtest/misc/definition_test.go 114498--- a/gopls/internal/regtest/misc/definition_test.go 2000-01-01 00:00:00.000000000 -0000 114499+++ b/gopls/internal/regtest/misc/definition_test.go 1970-01-01 00:00:00.000000000 +0000 114500@@ -1,512 +0,0 @@ 114501-// Copyright 2020 The Go Authors. All rights reserved. 114502-// Use of this source code is governed by a BSD-style 114503-// license that can be found in the LICENSE file. 114504- 114505-package misc 114506- 114507-import ( 114508- "os" 114509- "path" 114510- "path/filepath" 114511- "strings" 114512- "testing" 114513- 114514- "golang.org/x/tools/gopls/internal/lsp/protocol" 114515- . "golang.org/x/tools/gopls/internal/lsp/regtest" 114516- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 114517-) 114518- 114519-const internalDefinition = ` 114520--- go.mod -- 114521-module mod.com 114522- 114523-go 1.12 114524--- main.go -- 114525-package main 114526- 114527-import "fmt" 114528- 114529-func main() { 114530- fmt.Println(message) 114531-} 114532--- const.go -- 114533-package main 114534- 114535-const message = "Hello World." 114536-` 114537- 114538-func TestGoToInternalDefinition(t *testing.T) { 114539- Run(t, internalDefinition, func(t *testing.T, env *Env) { 114540- env.OpenFile("main.go") 114541- loc := env.GoToDefinition(env.RegexpSearch("main.go", "message")) 114542- name := env.Sandbox.Workdir.URIToPath(loc.URI) 114543- if want := "const.go"; name != want { 114544- t.Errorf("GoToDefinition: got file %q, want %q", name, want) 114545- } 114546- if want := env.RegexpSearch("const.go", "message"); loc != want { 114547- t.Errorf("GoToDefinition: got location %v, want %v", loc, want) 114548- } 114549- }) 114550-} 114551- 114552-const linknameDefinition = ` 114553--- go.mod -- 114554-module mod.com 114555- 114556--- upper/upper.go -- 114557-package upper 114558- 114559-import ( 114560- _ "unsafe" 114561- 114562- _ "mod.com/middle" 114563-) 114564- 114565-//go:linkname foo mod.com/lower.bar 114566-func foo() string 114567- 114568--- middle/middle.go -- 114569-package middle 114570- 114571-import ( 114572- _ "mod.com/lower" 114573-) 114574- 114575--- lower/lower.s -- 114576- 114577--- lower/lower.go -- 114578-package lower 114579- 114580-func bar() string { 114581- return "bar as foo" 114582-}` 114583- 114584-func TestGoToLinknameDefinition(t *testing.T) { 114585- Run(t, linknameDefinition, func(t *testing.T, env *Env) { 114586- env.OpenFile("upper/upper.go") 114587- 114588- // Jump from directives 2nd arg. 114589- start := env.RegexpSearch("upper/upper.go", `lower.bar`) 114590- loc := env.GoToDefinition(start) 114591- name := env.Sandbox.Workdir.URIToPath(loc.URI) 114592- if want := "lower/lower.go"; name != want { 114593- t.Errorf("GoToDefinition: got file %q, want %q", name, want) 114594- } 114595- if want := env.RegexpSearch("lower/lower.go", `bar`); loc != want { 114596- t.Errorf("GoToDefinition: got position %v, want %v", loc, want) 114597- } 114598- }) 114599-} 114600- 114601-const linknameDefinitionReverse = ` 114602--- go.mod -- 114603-module mod.com 114604- 114605--- upper/upper.s -- 114606- 114607--- upper/upper.go -- 114608-package upper 114609- 114610-import ( 114611- _ "mod.com/middle" 114612-) 114613- 114614-func foo() string 114615- 114616--- middle/middle.go -- 114617-package middle 114618- 114619-import ( 114620- _ "mod.com/lower" 114621-) 114622- 114623--- lower/lower.go -- 114624-package lower 114625- 114626-import _ "unsafe" 114627- 114628-//go:linkname bar mod.com/upper.foo 114629-func bar() string { 114630- return "bar as foo" 114631-}` 114632- 114633-func TestGoToLinknameDefinitionInReverseDep(t *testing.T) { 114634- Run(t, linknameDefinitionReverse, func(t *testing.T, env *Env) { 114635- env.OpenFile("lower/lower.go") 114636- 114637- // Jump from directives 2nd arg. 114638- start := env.RegexpSearch("lower/lower.go", `upper.foo`) 114639- loc := env.GoToDefinition(start) 114640- name := env.Sandbox.Workdir.URIToPath(loc.URI) 114641- if want := "upper/upper.go"; name != want { 114642- t.Errorf("GoToDefinition: got file %q, want %q", name, want) 114643- } 114644- if want := env.RegexpSearch("upper/upper.go", `foo`); loc != want { 114645- t.Errorf("GoToDefinition: got position %v, want %v", loc, want) 114646- } 114647- }) 114648-} 114649- 114650-// The linkname directive connects two packages not related in the import graph. 114651-const linknameDefinitionDisconnected = ` 114652--- go.mod -- 114653-module mod.com 114654- 114655--- a/a.go -- 114656-package a 114657- 114658-import ( 114659- _ "unsafe" 114660-) 114661- 114662-//go:linkname foo mod.com/b.bar 114663-func foo() string 114664- 114665--- b/b.go -- 114666-package b 114667- 114668-func bar() string { 114669- return "bar as foo" 114670-}` 114671- 114672-func TestGoToLinknameDefinitionDisconnected(t *testing.T) { 114673- Run(t, linknameDefinitionDisconnected, func(t *testing.T, env *Env) { 114674- env.OpenFile("a/a.go") 114675- 114676- // Jump from directives 2nd arg. 114677- start := env.RegexpSearch("a/a.go", `b.bar`) 114678- loc := env.GoToDefinition(start) 114679- name := env.Sandbox.Workdir.URIToPath(loc.URI) 114680- if want := "b/b.go"; name != want { 114681- t.Errorf("GoToDefinition: got file %q, want %q", name, want) 114682- } 114683- if want := env.RegexpSearch("b/b.go", `bar`); loc != want { 114684- t.Errorf("GoToDefinition: got position %v, want %v", loc, want) 114685- } 114686- }) 114687-} 114688- 114689-const stdlibDefinition = ` 114690--- go.mod -- 114691-module mod.com 114692- 114693-go 1.12 114694--- main.go -- 114695-package main 114696- 114697-import "fmt" 114698- 114699-func main() { 114700- fmt.Printf() 114701-}` 114702- 114703-func TestGoToStdlibDefinition_Issue37045(t *testing.T) { 114704- Run(t, stdlibDefinition, func(t *testing.T, env *Env) { 114705- env.OpenFile("main.go") 114706- loc := env.GoToDefinition(env.RegexpSearch("main.go", `fmt.(Printf)`)) 114707- name := env.Sandbox.Workdir.URIToPath(loc.URI) 114708- if got, want := path.Base(name), "print.go"; got != want { 114709- t.Errorf("GoToDefinition: got file %q, want %q", name, want) 114710- } 114711- 114712- // Test that we can jump to definition from outside our workspace. 114713- // See golang.org/issues/37045. 114714- newLoc := env.GoToDefinition(loc) 114715- newName := env.Sandbox.Workdir.URIToPath(newLoc.URI) 114716- if newName != name { 114717- t.Errorf("GoToDefinition is not idempotent: got %q, want %q", newName, name) 114718- } 114719- if newLoc != loc { 114720- t.Errorf("GoToDefinition is not idempotent: got %v, want %v", newLoc, loc) 114721- } 114722- }) 114723-} 114724- 114725-func TestUnexportedStdlib_Issue40809(t *testing.T) { 114726- Run(t, stdlibDefinition, func(t *testing.T, env *Env) { 114727- env.OpenFile("main.go") 114728- loc := env.GoToDefinition(env.RegexpSearch("main.go", `fmt.(Printf)`)) 114729- name := env.Sandbox.Workdir.URIToPath(loc.URI) 114730- 114731- loc = env.RegexpSearch(name, `:=\s*(newPrinter)\(\)`) 114732- 114733- // Check that we can find references on a reference 114734- refs := env.References(loc) 114735- if len(refs) < 5 { 114736- t.Errorf("expected 5+ references to newPrinter, found: %#v", refs) 114737- } 114738- 114739- loc = env.GoToDefinition(loc) 114740- content, _ := env.Hover(loc) 114741- if !strings.Contains(content.Value, "newPrinter") { 114742- t.Fatal("definition of newPrinter went to the incorrect place") 114743- } 114744- // And on the definition too. 114745- refs = env.References(loc) 114746- if len(refs) < 5 { 114747- t.Errorf("expected 5+ references to newPrinter, found: %#v", refs) 114748- } 114749- }) 114750-} 114751- 114752-// Test the hover on an error's Error function. 114753-// This can't be done via the marker tests because Error is a builtin. 114754-func TestHoverOnError(t *testing.T) { 114755- const mod = ` 114756--- go.mod -- 114757-module mod.com 114758- 114759-go 1.12 114760--- main.go -- 114761-package main 114762- 114763-func main() { 114764- var err error 114765- err.Error() 114766-}` 114767- Run(t, mod, func(t *testing.T, env *Env) { 114768- env.OpenFile("main.go") 114769- content, _ := env.Hover(env.RegexpSearch("main.go", "Error")) 114770- if content == nil { 114771- t.Fatalf("nil hover content for Error") 114772- } 114773- want := "```go\nfunc (error).Error() string\n```" 114774- if content.Value != want { 114775- t.Fatalf("hover failed:\n%s", compare.Text(want, content.Value)) 114776- } 114777- }) 114778-} 114779- 114780-func TestImportShortcut(t *testing.T) { 114781- const mod = ` 114782--- go.mod -- 114783-module mod.com 114784- 114785-go 1.12 114786--- main.go -- 114787-package main 114788- 114789-import "fmt" 114790- 114791-func main() {} 114792-` 114793- for _, tt := range []struct { 114794- wantLinks int 114795- importShortcut string 114796- }{ 114797- {1, "Link"}, 114798- {0, "Definition"}, 114799- {1, "Both"}, 114800- } { 114801- t.Run(tt.importShortcut, func(t *testing.T) { 114802- WithOptions( 114803- Settings{"importShortcut": tt.importShortcut}, 114804- ).Run(t, mod, func(t *testing.T, env *Env) { 114805- env.OpenFile("main.go") 114806- loc := env.GoToDefinition(env.RegexpSearch("main.go", `"fmt"`)) 114807- if loc == (protocol.Location{}) { 114808- t.Fatalf("expected definition, got none") 114809- } 114810- links := env.DocumentLink("main.go") 114811- if len(links) != tt.wantLinks { 114812- t.Fatalf("expected %v links, got %v", tt.wantLinks, len(links)) 114813- } 114814- }) 114815- }) 114816- } 114817-} 114818- 114819-func TestGoToTypeDefinition_Issue38589(t *testing.T) { 114820- const mod = ` 114821--- go.mod -- 114822-module mod.com 114823- 114824-go 1.12 114825--- main.go -- 114826-package main 114827- 114828-type Int int 114829- 114830-type Struct struct{} 114831- 114832-func F1() {} 114833-func F2() (int, error) { return 0, nil } 114834-func F3() (**Struct, bool, *Int, error) { return nil, false, nil, nil } 114835-func F4() (**Struct, bool, *float64, error) { return nil, false, nil, nil } 114836- 114837-func main() {} 114838-` 114839- 114840- for _, tt := range []struct { 114841- re string 114842- wantError bool 114843- wantTypeRe string 114844- }{ 114845- {re: `F1`, wantError: true}, 114846- {re: `F2`, wantError: true}, 114847- {re: `F3`, wantError: true}, 114848- {re: `F4`, wantError: false, wantTypeRe: `type (Struct)`}, 114849- } { 114850- t.Run(tt.re, func(t *testing.T) { 114851- Run(t, mod, func(t *testing.T, env *Env) { 114852- env.OpenFile("main.go") 114853- 114854- loc, err := env.Editor.GoToTypeDefinition(env.Ctx, env.RegexpSearch("main.go", tt.re)) 114855- if tt.wantError { 114856- if err == nil { 114857- t.Fatal("expected error, got nil") 114858- } 114859- return 114860- } 114861- if err != nil { 114862- t.Fatalf("expected nil error, got %s", err) 114863- } 114864- 114865- typeLoc := env.RegexpSearch("main.go", tt.wantTypeRe) 114866- if loc != typeLoc { 114867- t.Errorf("invalid pos: want %+v, got %+v", typeLoc, loc) 114868- } 114869- }) 114870- }) 114871- } 114872-} 114873- 114874-// Test for golang/go#47825. 114875-func TestImportTestVariant(t *testing.T) { 114876- const mod = ` 114877--- go.mod -- 114878-module mod.com 114879- 114880-go 1.12 114881--- client/test/role.go -- 114882-package test 114883- 114884-import _ "mod.com/client" 114885- 114886-type RoleSetup struct{} 114887--- client/client_role_test.go -- 114888-package client_test 114889- 114890-import ( 114891- "testing" 114892- _ "mod.com/client" 114893- ctest "mod.com/client/test" 114894-) 114895- 114896-func TestClient(t *testing.T) { 114897- _ = ctest.RoleSetup{} 114898-} 114899--- client/client_test.go -- 114900-package client 114901- 114902-import "testing" 114903- 114904-func TestClient(t *testing.T) {} 114905--- client.go -- 114906-package client 114907-` 114908- Run(t, mod, func(t *testing.T, env *Env) { 114909- env.OpenFile("client/client_role_test.go") 114910- env.GoToDefinition(env.RegexpSearch("client/client_role_test.go", "RoleSetup")) 114911- }) 114912-} 114913- 114914-// This test exercises a crashing pattern from golang/go#49223. 114915-func TestGoToCrashingDefinition_Issue49223(t *testing.T) { 114916- Run(t, "", func(t *testing.T, env *Env) { 114917- params := &protocol.DefinitionParams{} 114918- params.TextDocument.URI = protocol.DocumentURI("fugitive%3A///Users/user/src/mm/ems/.git//0/pkg/domain/treasury/provider.go") 114919- params.Position.Character = 18 114920- params.Position.Line = 0 114921- env.Editor.Server.Definition(env.Ctx, params) 114922- }) 114923-} 114924- 114925-// TestVendoringInvalidatesMetadata ensures that gopls uses the 114926-// correct metadata even after an external 'go mod vendor' command 114927-// causes packages to move; see issue #55995. 114928-// See also TestImplementationsInVendor, which tests the same fix. 114929-func TestVendoringInvalidatesMetadata(t *testing.T) { 114930- t.Skip("golang/go#56169: file watching does not capture vendor dirs") 114931- 114932- const proxy = ` 114933--- other.com/[email protected]/go.mod -- 114934-module other.com/b 114935-go 1.14 114936- 114937--- other.com/[email protected]/b.go -- 114938-package b 114939-const K = 0 114940-` 114941- const src = ` 114942--- go.mod -- 114943-module example.com/a 114944-go 1.14 114945-require other.com/b v1.0.0 114946- 114947--- go.sum -- 114948-other.com/b v1.0.0 h1:1wb3PMGdet5ojzrKl+0iNksRLnOM9Jw+7amBNqmYwqk= 114949-other.com/b v1.0.0/go.mod h1:TgHQFucl04oGT+vrUm/liAzukYHNxCwKNkQZEyn3m9g= 114950- 114951--- a.go -- 114952-package a 114953-import "other.com/b" 114954-const _ = b.K 114955- 114956-` 114957- WithOptions( 114958- ProxyFiles(proxy), 114959- Modes(Default), // fails in 'experimental' mode 114960- ).Run(t, src, func(t *testing.T, env *Env) { 114961- // Enable to debug go.sum mismatch, which may appear as 114962- // "module lookup disabled by GOPROXY=off", confusingly. 114963- if false { 114964- env.DumpGoSum(".") 114965- } 114966- 114967- env.OpenFile("a.go") 114968- refLoc := env.RegexpSearch("a.go", "K") // find "b.K" reference 114969- 114970- // Initially, b.K is defined in the module cache. 114971- gotLoc := env.GoToDefinition(refLoc) 114972- gotFile := env.Sandbox.Workdir.URIToPath(gotLoc.URI) 114973- wantCache := filepath.ToSlash(env.Sandbox.GOPATH()) + "/pkg/mod/other.com/[email protected]/b.go" 114974- if gotFile != wantCache { 114975- t.Errorf("GoToDefinition, before: got file %q, want %q", gotFile, wantCache) 114976- } 114977- 114978- // Run 'go mod vendor' outside the editor. 114979- if err := env.Sandbox.RunGoCommand(env.Ctx, ".", "mod", []string{"vendor"}, true); err != nil { 114980- t.Fatalf("go mod vendor: %v", err) 114981- } 114982- 114983- // Synchronize changes to watched files. 114984- env.Await(env.DoneWithChangeWatchedFiles()) 114985- 114986- // Now, b.K is defined in the vendor tree. 114987- gotLoc = env.GoToDefinition(refLoc) 114988- wantVendor := "vendor/other.com/b/b.go" 114989- if gotFile != wantVendor { 114990- t.Errorf("GoToDefinition, after go mod vendor: got file %q, want %q", gotFile, wantVendor) 114991- } 114992- 114993- // Delete the vendor tree. 114994- if err := os.RemoveAll(env.Sandbox.Workdir.AbsPath("vendor")); err != nil { 114995- t.Fatal(err) 114996- } 114997- // Notify the server of the deletion. 114998- if err := env.Sandbox.Workdir.CheckForFileChanges(env.Ctx); err != nil { 114999- t.Fatal(err) 115000- } 115001- 115002- // Synchronize again. 115003- env.Await(env.DoneWithChangeWatchedFiles()) 115004- 115005- // b.K is once again defined in the module cache. 115006- gotLoc = env.GoToDefinition(gotLoc) 115007- gotFile = env.Sandbox.Workdir.URIToPath(gotLoc.URI) 115008- if gotFile != wantCache { 115009- t.Errorf("GoToDefinition, after rm -rf vendor: got file %q, want %q", gotFile, wantCache) 115010- } 115011- }) 115012-} 115013diff -urN a/gopls/internal/regtest/misc/embed_test.go b/gopls/internal/regtest/misc/embed_test.go 115014--- a/gopls/internal/regtest/misc/embed_test.go 2000-01-01 00:00:00.000000000 -0000 115015+++ b/gopls/internal/regtest/misc/embed_test.go 1970-01-01 00:00:00.000000000 +0000 115016@@ -1,40 +0,0 @@ 115017-// Copyright 2021 The Go Authors. All rights reserved. 115018-// Use of this source code is governed by a BSD-style 115019-// license that can be found in the LICENSE file. 115020-package misc 115021- 115022-import ( 115023- "testing" 115024- 115025- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115026-) 115027- 115028-func TestMissingPatternDiagnostic(t *testing.T) { 115029- const files = ` 115030--- go.mod -- 115031-module example.com 115032--- x.go -- 115033-package x 115034- 115035-import ( 115036- _ "embed" 115037-) 115038- 115039-// Issue 47436 115040-func F() {} 115041- 115042-//go:embed NONEXISTENT 115043-var foo string 115044-` 115045- Run(t, files, func(t *testing.T, env *Env) { 115046- env.OpenFile("x.go") 115047- env.AfterChange( 115048- Diagnostics( 115049- env.AtRegexp("x.go", `NONEXISTENT`), 115050- WithMessage("no matching files found"), 115051- ), 115052- ) 115053- env.RegexpReplace("x.go", `NONEXISTENT`, "x.go") 115054- env.AfterChange(NoDiagnostics(ForFile("x.go"))) 115055- }) 115056-} 115057diff -urN a/gopls/internal/regtest/misc/extract_test.go b/gopls/internal/regtest/misc/extract_test.go 115058--- a/gopls/internal/regtest/misc/extract_test.go 2000-01-01 00:00:00.000000000 -0000 115059+++ b/gopls/internal/regtest/misc/extract_test.go 1970-01-01 00:00:00.000000000 +0000 115060@@ -1,65 +0,0 @@ 115061-// Copyright 2022 The Go Authors. All rights reserved. 115062-// Use of this source code is governed by a BSD-style 115063-// license that can be found in the LICENSE file. 115064-package misc 115065- 115066-import ( 115067- "testing" 115068- 115069- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115070- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 115071- 115072- "golang.org/x/tools/gopls/internal/lsp/protocol" 115073-) 115074- 115075-func TestExtractFunction(t *testing.T) { 115076- const files = ` 115077--- go.mod -- 115078-module mod.com 115079- 115080-go 1.12 115081--- main.go -- 115082-package main 115083- 115084-func Foo() int { 115085- a := 5 115086- return a 115087-} 115088-` 115089- Run(t, files, func(t *testing.T, env *Env) { 115090- env.OpenFile("main.go") 115091- loc := env.RegexpSearch("main.go", `a := 5\n.*return a`) 115092- actions, err := env.Editor.CodeAction(env.Ctx, loc, nil) 115093- if err != nil { 115094- t.Fatal(err) 115095- } 115096- 115097- // Find the extract function code action. 115098- var extractFunc *protocol.CodeAction 115099- for _, action := range actions { 115100- if action.Kind == protocol.RefactorExtract && action.Title == "Extract function" { 115101- extractFunc = &action 115102- break 115103- } 115104- } 115105- if extractFunc == nil { 115106- t.Fatal("could not find extract function action") 115107- } 115108- 115109- env.ApplyCodeAction(*extractFunc) 115110- want := `package main 115111- 115112-func Foo() int { 115113- return newFunction() 115114-} 115115- 115116-func newFunction() int { 115117- a := 5 115118- return a 115119-} 115120-` 115121- if got := env.BufferText("main.go"); got != want { 115122- t.Fatalf("TestFillStruct failed:\n%s", compare.Text(want, got)) 115123- } 115124- }) 115125-} 115126diff -urN a/gopls/internal/regtest/misc/failures_test.go b/gopls/internal/regtest/misc/failures_test.go 115127--- a/gopls/internal/regtest/misc/failures_test.go 2000-01-01 00:00:00.000000000 -0000 115128+++ b/gopls/internal/regtest/misc/failures_test.go 1970-01-01 00:00:00.000000000 +0000 115129@@ -1,84 +0,0 @@ 115130-// Copyright 2020 The Go Authors. All rights reserved. 115131-// Use of this source code is governed by a BSD-style 115132-// license that can be found in the LICENSE file. 115133- 115134-package misc 115135- 115136-import ( 115137- "testing" 115138- 115139- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115140- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 115141-) 115142- 115143-// This is a slight variant of TestHoverOnError in definition_test.go 115144-// that includes a line directive, which makes no difference since 115145-// gopls ignores line directives. 115146-func TestHoverFailure(t *testing.T) { 115147- t.Skip("line directives //line ") 115148- const mod = ` 115149--- go.mod -- 115150-module mod.com 115151- 115152-go 1.12 115153--- a.y -- 115154-DWIM(main) 115155- 115156--- main.go -- 115157-//line a.y:1 115158-package main 115159- 115160-func main() { 115161- var err error 115162- err.Error() 115163-}` 115164- Run(t, mod, func(t *testing.T, env *Env) { 115165- env.OpenFile("main.go") 115166- content, _ := env.Hover(env.RegexpSearch("main.go", "Error")) 115167- if content == nil { 115168- t.Fatalf("Hover('Error') returned nil") 115169- } 115170- want := "```go\nfunc (error).Error() string\n```" 115171- if content.Value != want { 115172- t.Fatalf("wrong Hover('Error') content:\n%s", compare.Text(want, content.Value)) 115173- } 115174- }) 115175-} 115176- 115177-// This test demonstrates a case where gopls is not at all confused by 115178-// line directives, because it completely ignores them. 115179-func TestFailingDiagnosticClearingOnEdit(t *testing.T) { 115180- t.Skip("line directives //line ") 115181- // badPackageDup contains a duplicate definition of the 'a' const. 115182- // This is a minor variant of TestDiagnosticClearingOnEdit from 115183- // diagnostics_test.go, with a line directive, which makes no difference. 115184- const badPackageDup = ` 115185--- go.mod -- 115186-module mod.com 115187- 115188-go 1.12 115189--- a.go -- 115190-package consts 115191- 115192-const a = 1 115193--- b.go -- 115194-package consts 115195-//line gen.go:5 115196-const a = 2 115197-` 115198- 115199- Run(t, badPackageDup, func(t *testing.T, env *Env) { 115200- env.OpenFile("b.go") 115201- env.AfterChange( 115202- Diagnostics(env.AtRegexp("b.go", `a = 2`), WithMessage("a redeclared")), 115203- Diagnostics(env.AtRegexp("a.go", `a = 1`), WithMessage("other declaration")), 115204- ) 115205- 115206- // Fix the error by editing the const name in b.go to `b`. 115207- env.RegexpReplace("b.go", "(a) = 2", "b") 115208- env.AfterChange( 115209- NoDiagnostics(ForFile("a.go")), 115210- NoDiagnostics(ForFile("b.go")), 115211- ) 115212- }) 115213-} 115214diff -urN a/gopls/internal/regtest/misc/fix_test.go b/gopls/internal/regtest/misc/fix_test.go 115215--- a/gopls/internal/regtest/misc/fix_test.go 2000-01-01 00:00:00.000000000 -0000 115216+++ b/gopls/internal/regtest/misc/fix_test.go 1970-01-01 00:00:00.000000000 +0000 115217@@ -1,103 +0,0 @@ 115218-// Copyright 2020 The Go Authors. All rights reserved. 115219-// Use of this source code is governed by a BSD-style 115220-// license that can be found in the LICENSE file. 115221- 115222-package misc 115223- 115224-import ( 115225- "testing" 115226- 115227- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115228- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 115229- 115230- "golang.org/x/tools/gopls/internal/lsp/protocol" 115231-) 115232- 115233-// A basic test for fillstruct, now that it uses a command. 115234-func TestFillStruct(t *testing.T) { 115235- const basic = ` 115236--- go.mod -- 115237-module mod.com 115238- 115239-go 1.14 115240--- main.go -- 115241-package main 115242- 115243-type Info struct { 115244- WordCounts map[string]int 115245- Words []string 115246-} 115247- 115248-func Foo() { 115249- _ = Info{} 115250-} 115251-` 115252- Run(t, basic, func(t *testing.T, env *Env) { 115253- env.OpenFile("main.go") 115254- if err := env.Editor.RefactorRewrite(env.Ctx, env.RegexpSearch("main.go", "Info{}")); err != nil { 115255- t.Fatal(err) 115256- } 115257- want := `package main 115258- 115259-type Info struct { 115260- WordCounts map[string]int 115261- Words []string 115262-} 115263- 115264-func Foo() { 115265- _ = Info{ 115266- WordCounts: map[string]int{}, 115267- Words: []string{}, 115268- } 115269-} 115270-` 115271- if got := env.BufferText("main.go"); got != want { 115272- t.Fatalf("TestFillStruct failed:\n%s", compare.Text(want, got)) 115273- } 115274- }) 115275-} 115276- 115277-func TestFillReturns(t *testing.T) { 115278- const files = ` 115279--- go.mod -- 115280-module mod.com 115281- 115282-go 1.12 115283--- main.go -- 115284-package main 115285- 115286-func Foo() error { 115287- return 115288-} 115289-` 115290- Run(t, files, func(t *testing.T, env *Env) { 115291- env.OpenFile("main.go") 115292- var d protocol.PublishDiagnosticsParams 115293- env.AfterChange( 115294- // The error message here changed in 1.18; "return values" covers both forms. 115295- Diagnostics(env.AtRegexp("main.go", `return`), WithMessage("return values")), 115296- ReadDiagnostics("main.go", &d), 115297- ) 115298- codeActions := env.CodeAction("main.go", d.Diagnostics) 115299- if len(codeActions) != 2 { 115300- t.Fatalf("expected 2 code actions, got %v", len(codeActions)) 115301- } 115302- var foundQuickFix, foundFixAll bool 115303- for _, a := range codeActions { 115304- if a.Kind == protocol.QuickFix { 115305- foundQuickFix = true 115306- } 115307- if a.Kind == protocol.SourceFixAll { 115308- foundFixAll = true 115309- } 115310- } 115311- if !foundQuickFix { 115312- t.Fatalf("expected quickfix code action, got none") 115313- } 115314- if !foundFixAll { 115315- t.Fatalf("expected fixall code action, got none") 115316- } 115317- env.ApplyQuickFixes("main.go", d.Diagnostics) 115318- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 115319- }) 115320-} 115321diff -urN a/gopls/internal/regtest/misc/formatting_test.go b/gopls/internal/regtest/misc/formatting_test.go 115322--- a/gopls/internal/regtest/misc/formatting_test.go 2000-01-01 00:00:00.000000000 -0000 115323+++ b/gopls/internal/regtest/misc/formatting_test.go 1970-01-01 00:00:00.000000000 +0000 115324@@ -1,368 +0,0 @@ 115325-// Copyright 2020 The Go Authors. All rights reserved. 115326-// Use of this source code is governed by a BSD-style 115327-// license that can be found in the LICENSE file. 115328- 115329-package misc 115330- 115331-import ( 115332- "strings" 115333- "testing" 115334- 115335- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115336- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 115337- "golang.org/x/tools/internal/testenv" 115338-) 115339- 115340-const unformattedProgram = ` 115341--- main.go -- 115342-package main 115343-import "fmt" 115344-func main( ) { 115345- fmt.Println("Hello World.") 115346-} 115347--- main.go.golden -- 115348-package main 115349- 115350-import "fmt" 115351- 115352-func main() { 115353- fmt.Println("Hello World.") 115354-} 115355-` 115356- 115357-func TestFormatting(t *testing.T) { 115358- Run(t, unformattedProgram, func(t *testing.T, env *Env) { 115359- env.OpenFile("main.go") 115360- env.FormatBuffer("main.go") 115361- got := env.BufferText("main.go") 115362- want := env.ReadWorkspaceFile("main.go.golden") 115363- if got != want { 115364- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115365- } 115366- }) 115367-} 115368- 115369-// Tests golang/go#36824. 115370-func TestFormattingOneLine36824(t *testing.T) { 115371- const onelineProgram = ` 115372--- a.go -- 115373-package main; func f() {} 115374- 115375--- a.go.formatted -- 115376-package main 115377- 115378-func f() {} 115379-` 115380- Run(t, onelineProgram, func(t *testing.T, env *Env) { 115381- env.OpenFile("a.go") 115382- env.FormatBuffer("a.go") 115383- got := env.BufferText("a.go") 115384- want := env.ReadWorkspaceFile("a.go.formatted") 115385- if got != want { 115386- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115387- } 115388- }) 115389-} 115390- 115391-// Tests golang/go#36824. 115392-func TestFormattingOneLineImports36824(t *testing.T) { 115393- const onelineProgramA = ` 115394--- a.go -- 115395-package x; func f() {fmt.Println()} 115396- 115397--- a.go.imported -- 115398-package x 115399- 115400-import "fmt" 115401- 115402-func f() { fmt.Println() } 115403-` 115404- Run(t, onelineProgramA, func(t *testing.T, env *Env) { 115405- env.OpenFile("a.go") 115406- env.OrganizeImports("a.go") 115407- got := env.BufferText("a.go") 115408- want := env.ReadWorkspaceFile("a.go.imported") 115409- if got != want { 115410- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115411- } 115412- }) 115413-} 115414- 115415-func TestFormattingOneLineRmImports36824(t *testing.T) { 115416- const onelineProgramB = ` 115417--- a.go -- 115418-package x; import "os"; func f() {} 115419- 115420--- a.go.imported -- 115421-package x 115422- 115423-func f() {} 115424-` 115425- Run(t, onelineProgramB, func(t *testing.T, env *Env) { 115426- env.OpenFile("a.go") 115427- env.OrganizeImports("a.go") 115428- got := env.BufferText("a.go") 115429- want := env.ReadWorkspaceFile("a.go.imported") 115430- if got != want { 115431- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115432- } 115433- }) 115434-} 115435- 115436-const disorganizedProgram = ` 115437--- main.go -- 115438-package main 115439- 115440-import ( 115441- "fmt" 115442- "errors" 115443-) 115444-func main( ) { 115445- fmt.Println(errors.New("bad")) 115446-} 115447--- main.go.organized -- 115448-package main 115449- 115450-import ( 115451- "errors" 115452- "fmt" 115453-) 115454-func main( ) { 115455- fmt.Println(errors.New("bad")) 115456-} 115457--- main.go.formatted -- 115458-package main 115459- 115460-import ( 115461- "errors" 115462- "fmt" 115463-) 115464- 115465-func main() { 115466- fmt.Println(errors.New("bad")) 115467-} 115468-` 115469- 115470-func TestOrganizeImports(t *testing.T) { 115471- Run(t, disorganizedProgram, func(t *testing.T, env *Env) { 115472- env.OpenFile("main.go") 115473- env.OrganizeImports("main.go") 115474- got := env.BufferText("main.go") 115475- want := env.ReadWorkspaceFile("main.go.organized") 115476- if got != want { 115477- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115478- } 115479- }) 115480-} 115481- 115482-func TestFormattingOnSave(t *testing.T) { 115483- Run(t, disorganizedProgram, func(t *testing.T, env *Env) { 115484- env.OpenFile("main.go") 115485- env.SaveBuffer("main.go") 115486- got := env.BufferText("main.go") 115487- want := env.ReadWorkspaceFile("main.go.formatted") 115488- if got != want { 115489- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115490- } 115491- }) 115492-} 115493- 115494-// Tests various possibilities for comments in files with CRLF line endings. 115495-// Import organization in these files has historically been a source of bugs. 115496-func TestCRLFLineEndings(t *testing.T) { 115497- for _, tt := range []struct { 115498- issue, input, want string 115499- }{ 115500- { 115501- issue: "41057", 115502- want: `package main 115503- 115504-/* 115505-Hi description 115506-*/ 115507-func Hi() { 115508-} 115509-`, 115510- }, 115511- { 115512- issue: "42646", 115513- want: `package main 115514- 115515-import ( 115516- "fmt" 115517-) 115518- 115519-/* 115520-func upload(c echo.Context) error { 115521- if err := r.ParseForm(); err != nil { 115522- fmt.Fprintf(w, "ParseForm() err: %v", err) 115523- return 115524- } 115525- fmt.Fprintf(w, "POST request successful") 115526- path_ver := r.FormValue("path_ver") 115527- ukclin_ver := r.FormValue("ukclin_ver") 115528- 115529- fmt.Fprintf(w, "Name = %s\n", path_ver) 115530- fmt.Fprintf(w, "Address = %s\n", ukclin_ver) 115531-} 115532-*/ 115533- 115534-func main() { 115535- const server_port = 8080 115536- fmt.Printf("port: %d\n", server_port) 115537-} 115538-`, 115539- }, 115540- { 115541- issue: "42923", 115542- want: `package main 115543- 115544-// Line 1. 115545-// aa 115546-type Tree struct { 115547- arr []string 115548-} 115549-`, 115550- }, 115551- { 115552- issue: "47200", 115553- input: `package main 115554- 115555-import "fmt" 115556- 115557-func main() { 115558- math.Sqrt(9) 115559- fmt.Println("hello") 115560-} 115561-`, 115562- want: `package main 115563- 115564-import ( 115565- "fmt" 115566- "math" 115567-) 115568- 115569-func main() { 115570- math.Sqrt(9) 115571- fmt.Println("hello") 115572-} 115573-`, 115574- }, 115575- } { 115576- t.Run(tt.issue, func(t *testing.T) { 115577- Run(t, "-- main.go --", func(t *testing.T, env *Env) { 115578- input := tt.input 115579- if input == "" { 115580- input = tt.want 115581- } 115582- crlf := strings.ReplaceAll(input, "\n", "\r\n") 115583- env.CreateBuffer("main.go", crlf) 115584- env.Await(env.DoneWithOpen()) 115585- env.OrganizeImports("main.go") 115586- got := env.BufferText("main.go") 115587- got = strings.ReplaceAll(got, "\r\n", "\n") // convert everything to LF for simplicity 115588- if tt.want != got { 115589- t.Errorf("unexpected content after save:\n%s", compare.Text(tt.want, got)) 115590- } 115591- }) 115592- }) 115593- } 115594-} 115595- 115596-func TestFormattingOfGeneratedFile_Issue49555(t *testing.T) { 115597- const input = ` 115598--- main.go -- 115599-// Code generated by generator.go. DO NOT EDIT. 115600- 115601-package main 115602- 115603-import "fmt" 115604- 115605-func main() { 115606- 115607- 115608- 115609- 115610- fmt.Print("hello") 115611-} 115612-` 115613- 115614- Run(t, input, func(t *testing.T, env *Env) { 115615- wantErrSuffix := "file is generated" 115616- 115617- env.OpenFile("main.go") 115618- err := env.Editor.FormatBuffer(env.Ctx, "main.go") 115619- if err == nil { 115620- t.Fatal("expected error, got nil") 115621- } 115622- // Check only the suffix because an error contains a dynamic path to main.go 115623- if !strings.HasSuffix(err.Error(), wantErrSuffix) { 115624- t.Fatalf("unexpected error %q, want suffix %q", err.Error(), wantErrSuffix) 115625- } 115626- }) 115627-} 115628- 115629-func TestGofumptFormatting(t *testing.T) { 115630- testenv.NeedsGo1Point(t, 18) 115631- 115632- // Exercise some gofumpt formatting rules: 115633- // - No empty lines following an assignment operator 115634- // - Octal integer literals should use the 0o prefix on modules using Go 115635- // 1.13 and later. Requires LangVersion to be correctly resolved. 115636- // - std imports must be in a separate group at the top. Requires ModulePath 115637- // to be correctly resolved. 115638- const input = ` 115639--- go.mod -- 115640-module foo 115641- 115642-go 1.17 115643--- foo.go -- 115644-package foo 115645- 115646-import ( 115647- "foo/bar" 115648- "fmt" 115649-) 115650- 115651-const perm = 0755 115652- 115653-func foo() { 115654- foo := 115655- "bar" 115656- fmt.Println(foo, bar.Bar) 115657-} 115658--- foo.go.formatted -- 115659-package foo 115660- 115661-import ( 115662- "fmt" 115663- 115664- "foo/bar" 115665-) 115666- 115667-const perm = 0o755 115668- 115669-func foo() { 115670- foo := "bar" 115671- fmt.Println(foo, bar.Bar) 115672-} 115673--- bar/bar.go -- 115674-package bar 115675- 115676-const Bar = 42 115677-` 115678- 115679- WithOptions( 115680- Settings{ 115681- "gofumpt": true, 115682- }, 115683- ).Run(t, input, func(t *testing.T, env *Env) { 115684- env.OpenFile("foo.go") 115685- env.FormatBuffer("foo.go") 115686- got := env.BufferText("foo.go") 115687- want := env.ReadWorkspaceFile("foo.go.formatted") 115688- if got != want { 115689- t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got)) 115690- } 115691- }) 115692-} 115693diff -urN a/gopls/internal/regtest/misc/generate_test.go b/gopls/internal/regtest/misc/generate_test.go 115694--- a/gopls/internal/regtest/misc/generate_test.go 2000-01-01 00:00:00.000000000 -0000 115695+++ b/gopls/internal/regtest/misc/generate_test.go 1970-01-01 00:00:00.000000000 +0000 115696@@ -1,72 +0,0 @@ 115697-// Copyright 2020 The Go Authors. All rights reserved. 115698-// Use of this source code is governed by a BSD-style 115699-// license that can be found in the LICENSE file. 115700- 115701-// TODO(rfindley): figure out why go generate fails on android builders. 115702- 115703-//go:build !android 115704-// +build !android 115705- 115706-package misc 115707- 115708-import ( 115709- "testing" 115710- 115711- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115712-) 115713- 115714-func TestGenerateProgress(t *testing.T) { 115715- const generatedWorkspace = ` 115716--- go.mod -- 115717-module fake.test 115718- 115719-go 1.14 115720--- generate.go -- 115721-// +build ignore 115722- 115723-package main 115724- 115725-import ( 115726- "io/ioutil" 115727- "os" 115728-) 115729- 115730-func main() { 115731- ioutil.WriteFile("generated.go", []byte("package " + os.Args[1] + "\n\nconst Answer = 21"), 0644) 115732-} 115733- 115734--- lib1/lib.go -- 115735-package lib1 115736- 115737-//` + `go:generate go run ../generate.go lib1 115738- 115739--- lib2/lib.go -- 115740-package lib2 115741- 115742-//` + `go:generate go run ../generate.go lib2 115743- 115744--- main.go -- 115745-package main 115746- 115747-import ( 115748- "fake.test/lib1" 115749- "fake.test/lib2" 115750-) 115751- 115752-func main() { 115753- println(lib1.Answer + lib2.Answer) 115754-} 115755-` 115756- 115757- Run(t, generatedWorkspace, func(t *testing.T, env *Env) { 115758- env.OnceMet( 115759- InitialWorkspaceLoad, 115760- Diagnostics(env.AtRegexp("main.go", "lib1.(Answer)")), 115761- ) 115762- env.RunGenerate("./lib1") 115763- env.RunGenerate("./lib2") 115764- env.AfterChange( 115765- NoDiagnostics(ForFile("main.go")), 115766- ) 115767- }) 115768-} 115769diff -urN a/gopls/internal/regtest/misc/highlight_test.go b/gopls/internal/regtest/misc/highlight_test.go 115770--- a/gopls/internal/regtest/misc/highlight_test.go 2000-01-01 00:00:00.000000000 -0000 115771+++ b/gopls/internal/regtest/misc/highlight_test.go 1970-01-01 00:00:00.000000000 +0000 115772@@ -1,153 +0,0 @@ 115773-// Copyright 2021 The Go Authors. All rights reserved. 115774-// Use of this source code is governed by a BSD-style 115775-// license that can be found in the LICENSE file. 115776- 115777-package misc 115778- 115779-import ( 115780- "sort" 115781- "testing" 115782- 115783- "golang.org/x/tools/gopls/internal/lsp/protocol" 115784- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115785-) 115786- 115787-func TestWorkspacePackageHighlight(t *testing.T) { 115788- const mod = ` 115789--- go.mod -- 115790-module mod.com 115791- 115792-go 1.12 115793--- main.go -- 115794-package main 115795- 115796-func main() { 115797- var A string = "A" 115798- x := "x-" + A 115799- println(A, x) 115800-}` 115801- 115802- Run(t, mod, func(t *testing.T, env *Env) { 115803- const file = "main.go" 115804- env.OpenFile(file) 115805- loc := env.GoToDefinition(env.RegexpSearch(file, `var (A) string`)) 115806- 115807- checkHighlights(env, loc, 3) 115808- }) 115809-} 115810- 115811-func TestStdPackageHighlight_Issue43511(t *testing.T) { 115812- const mod = ` 115813--- go.mod -- 115814-module mod.com 115815- 115816-go 1.12 115817--- main.go -- 115818-package main 115819- 115820-import "fmt" 115821- 115822-func main() { 115823- fmt.Printf() 115824-}` 115825- 115826- Run(t, mod, func(t *testing.T, env *Env) { 115827- env.OpenFile("main.go") 115828- defLoc := env.GoToDefinition(env.RegexpSearch("main.go", `fmt\.(Printf)`)) 115829- file := env.Sandbox.Workdir.URIToPath(defLoc.URI) 115830- loc := env.RegexpSearch(file, `func Printf\((format) string`) 115831- 115832- checkHighlights(env, loc, 2) 115833- }) 115834-} 115835- 115836-func TestThirdPartyPackageHighlight_Issue43511(t *testing.T) { 115837- const proxy = ` 115838--- [email protected]/go.mod -- 115839-module example.com 115840- 115841-go 1.12 115842--- [email protected]/global/global.go -- 115843-package global 115844- 115845-const A = 1 115846- 115847-func foo() { 115848- _ = A 115849-} 115850- 115851-func bar() int { 115852- return A + A 115853-} 115854--- [email protected]/local/local.go -- 115855-package local 115856- 115857-func foo() int { 115858- const b = 2 115859- 115860- return b * b * (b+1) + b 115861-}` 115862- 115863- const mod = ` 115864--- go.mod -- 115865-module mod.com 115866- 115867-go 1.12 115868- 115869-require example.com v1.2.3 115870--- go.sum -- 115871-example.com v1.2.3 h1:WFzrgiQJwEDJNLDUOV1f9qlasQkvzXf2UNLaNIqbWsI= 115872-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 115873--- main.go -- 115874-package main 115875- 115876-import ( 115877- _ "example.com/global" 115878- _ "example.com/local" 115879-) 115880- 115881-func main() {}` 115882- 115883- WithOptions( 115884- ProxyFiles(proxy), 115885- ).Run(t, mod, func(t *testing.T, env *Env) { 115886- env.OpenFile("main.go") 115887- 115888- defLoc := env.GoToDefinition(env.RegexpSearch("main.go", `"example.com/global"`)) 115889- file := env.Sandbox.Workdir.URIToPath(defLoc.URI) 115890- loc := env.RegexpSearch(file, `const (A)`) 115891- checkHighlights(env, loc, 4) 115892- 115893- defLoc = env.GoToDefinition(env.RegexpSearch("main.go", `"example.com/local"`)) 115894- file = env.Sandbox.Workdir.URIToPath(defLoc.URI) 115895- loc = env.RegexpSearch(file, `const (b)`) 115896- checkHighlights(env, loc, 5) 115897- }) 115898-} 115899- 115900-func checkHighlights(env *Env, loc protocol.Location, highlightCount int) { 115901- t := env.T 115902- t.Helper() 115903- 115904- highlights := env.DocumentHighlight(loc) 115905- if len(highlights) != highlightCount { 115906- t.Fatalf("expected %v highlight(s), got %v", highlightCount, len(highlights)) 115907- } 115908- 115909- references := env.References(loc) 115910- if len(highlights) != len(references) { 115911- t.Fatalf("number of highlights and references is expected to be equal: %v != %v", len(highlights), len(references)) 115912- } 115913- 115914- sort.Slice(highlights, func(i, j int) bool { 115915- return protocol.CompareRange(highlights[i].Range, highlights[j].Range) < 0 115916- }) 115917- sort.Slice(references, func(i, j int) bool { 115918- return protocol.CompareRange(references[i].Range, references[j].Range) < 0 115919- }) 115920- for i := range highlights { 115921- if highlights[i].Range != references[i].Range { 115922- t.Errorf("highlight and reference ranges are expected to be equal: %v != %v", highlights[i].Range, references[i].Range) 115923- } 115924- } 115925-} 115926diff -urN a/gopls/internal/regtest/misc/hover_test.go b/gopls/internal/regtest/misc/hover_test.go 115927--- a/gopls/internal/regtest/misc/hover_test.go 2000-01-01 00:00:00.000000000 -0000 115928+++ b/gopls/internal/regtest/misc/hover_test.go 1970-01-01 00:00:00.000000000 +0000 115929@@ -1,384 +0,0 @@ 115930-// Copyright 2021 The Go Authors. All rights reserved. 115931-// Use of this source code is governed by a BSD-style 115932-// license that can be found in the LICENSE file. 115933- 115934-package misc 115935- 115936-import ( 115937- "fmt" 115938- "strings" 115939- "testing" 115940- 115941- "golang.org/x/tools/gopls/internal/lsp/fake" 115942- "golang.org/x/tools/gopls/internal/lsp/protocol" 115943- . "golang.org/x/tools/gopls/internal/lsp/regtest" 115944- "golang.org/x/tools/internal/testenv" 115945-) 115946- 115947-func TestHoverUnexported(t *testing.T) { 115948- const proxy = ` 115949--- golang.org/x/structs@v1.0.0/go.mod -- 115950-module golang.org/x/structs 115951- 115952-go 1.12 115953- 115954--- golang.org/x/structs@v1.0.0/types.go -- 115955-package structs 115956- 115957-type Mixed struct { 115958- // Exported comment 115959- Exported int 115960- unexported string 115961-} 115962- 115963-func printMixed(m Mixed) { 115964- println(m) 115965-} 115966-` 115967- const mod = ` 115968--- go.mod -- 115969-module mod.com 115970- 115971-go 1.12 115972- 115973-require golang.org/x/structs v1.0.0 115974--- go.sum -- 115975-golang.org/x/structs v1.0.0 h1:Ito/a7hBYZaNKShFrZKjfBA/SIPvmBrcPCBWPx5QeKk= 115976-golang.org/x/structs v1.0.0/go.mod h1:47gkSIdo5AaQaWJS0upVORsxfEr1LL1MWv9dmYF3iq4= 115977--- main.go -- 115978-package main 115979- 115980-import "golang.org/x/structs" 115981- 115982-func main() { 115983- var m structs.Mixed 115984- _ = m.Exported 115985-} 115986-` 115987- 115988- // TODO: use a nested workspace folder here. 115989- WithOptions( 115990- ProxyFiles(proxy), 115991- ).Run(t, mod, func(t *testing.T, env *Env) { 115992- env.OpenFile("main.go") 115993- mixedLoc := env.RegexpSearch("main.go", "Mixed") 115994- got, _ := env.Hover(mixedLoc) 115995- if !strings.Contains(got.Value, "unexported") { 115996- t.Errorf("Workspace hover: missing expected field 'unexported'. Got:\n%q", got.Value) 115997- } 115998- 115999- cacheLoc := env.GoToDefinition(mixedLoc) 116000- cacheFile := env.Sandbox.Workdir.URIToPath(cacheLoc.URI) 116001- argLoc := env.RegexpSearch(cacheFile, "printMixed.*(Mixed)") 116002- got, _ = env.Hover(argLoc) 116003- if !strings.Contains(got.Value, "unexported") { 116004- t.Errorf("Non-workspace hover: missing expected field 'unexported'. Got:\n%q", got.Value) 116005- } 116006- 116007- exportedFieldLoc := env.RegexpSearch("main.go", "Exported") 116008- got, _ = env.Hover(exportedFieldLoc) 116009- if !strings.Contains(got.Value, "comment") { 116010- t.Errorf("Workspace hover: missing comment for field 'Exported'. Got:\n%q", got.Value) 116011- } 116012- }) 116013-} 116014- 116015-func TestHoverIntLiteral(t *testing.T) { 116016- // TODO(rfindley): this behavior doesn't actually make sense for vars. It is 116017- // misleading to format their value when it is (of course) variable. 116018- // 116019- // Instead, we should allow hovering on numeric literals. 116020- t.Skip("golang/go#58220: broken due to new hover logic") 116021- 116022- const source = ` 116023--- main.go -- 116024-package main 116025- 116026-var ( 116027- bigBin = 0b1001001 116028-) 116029- 116030-var hex = 0xe34e 116031- 116032-func main() { 116033-} 116034-` 116035- Run(t, source, func(t *testing.T, env *Env) { 116036- env.OpenFile("main.go") 116037- hexExpected := "58190" 116038- got, _ := env.Hover(env.RegexpSearch("main.go", "hex")) 116039- if got != nil && !strings.Contains(got.Value, hexExpected) { 116040- t.Errorf("Hover: missing expected field '%s'. Got:\n%q", hexExpected, got.Value) 116041- } 116042- 116043- binExpected := "73" 116044- got, _ = env.Hover(env.RegexpSearch("main.go", "bigBin")) 116045- if got != nil && !strings.Contains(got.Value, binExpected) { 116046- t.Errorf("Hover: missing expected field '%s'. Got:\n%q", binExpected, got.Value) 116047- } 116048- }) 116049-} 116050- 116051-// Tests that hovering does not trigger the panic in golang/go#48249. 116052-func TestPanicInHoverBrokenCode(t *testing.T) { 116053- // Note: this test can not be expressed as a marker test, as it must use 116054- // content without a trailing newline. 116055- const source = ` 116056--- main.go -- 116057-package main 116058- 116059-type Example struct` 116060- Run(t, source, func(t *testing.T, env *Env) { 116061- env.OpenFile("main.go") 116062- env.Editor.Hover(env.Ctx, env.RegexpSearch("main.go", "Example")) 116063- }) 116064-} 116065- 116066-func TestHoverRune_48492(t *testing.T) { 116067- const files = ` 116068--- go.mod -- 116069-module mod.com 116070- 116071-go 1.18 116072--- main.go -- 116073-package main 116074-` 116075- Run(t, files, func(t *testing.T, env *Env) { 116076- env.OpenFile("main.go") 116077- env.EditBuffer("main.go", fake.NewEdit(0, 0, 1, 0, "package main\nfunc main() {\nconst x = `\nfoo\n`\n}")) 116078- env.Editor.Hover(env.Ctx, env.RegexpSearch("main.go", "foo")) 116079- }) 116080-} 116081- 116082-func TestHoverImport(t *testing.T) { 116083- const packageDoc1 = "Package lib1 hover documentation" 116084- const packageDoc2 = "Package lib2 hover documentation" 116085- tests := []struct { 116086- hoverPackage string 116087- want string 116088- wantError bool 116089- }{ 116090- { 116091- "mod.com/lib1", 116092- packageDoc1, 116093- false, 116094- }, 116095- { 116096- "mod.com/lib2", 116097- packageDoc2, 116098- false, 116099- }, 116100- { 116101- "mod.com/lib3", 116102- "", 116103- false, 116104- }, 116105- { 116106- "mod.com/lib4", 116107- "", 116108- true, 116109- }, 116110- } 116111- source := fmt.Sprintf(` 116112--- go.mod -- 116113-module mod.com 116114- 116115-go 1.12 116116--- lib1/a.go -- 116117-// %s 116118-package lib1 116119- 116120-const C = 1 116121- 116122--- lib1/b.go -- 116123-package lib1 116124- 116125-const D = 1 116126- 116127--- lib2/a.go -- 116128-// %s 116129-package lib2 116130- 116131-const E = 1 116132- 116133--- lib3/a.go -- 116134-package lib3 116135- 116136-const F = 1 116137- 116138--- main.go -- 116139-package main 116140- 116141-import ( 116142- "mod.com/lib1" 116143- "mod.com/lib2" 116144- "mod.com/lib3" 116145- "mod.com/lib4" 116146-) 116147- 116148-func main() { 116149- println("Hello") 116150-} 116151- `, packageDoc1, packageDoc2) 116152- Run(t, source, func(t *testing.T, env *Env) { 116153- env.OpenFile("main.go") 116154- for _, test := range tests { 116155- got, _, err := env.Editor.Hover(env.Ctx, env.RegexpSearch("main.go", test.hoverPackage)) 116156- if test.wantError { 116157- if err == nil { 116158- t.Errorf("Hover(%q) succeeded unexpectedly", test.hoverPackage) 116159- } 116160- } else if !strings.Contains(got.Value, test.want) { 116161- t.Errorf("Hover(%q): got:\n%q\nwant:\n%q", test.hoverPackage, got.Value, test.want) 116162- } 116163- } 116164- }) 116165-} 116166- 116167-// for x/tools/gopls: unhandled named anchor on the hover #57048 116168-func TestHoverTags(t *testing.T) { 116169- const source = ` 116170--- go.mod -- 116171-module mod.com 116172- 116173-go 1.19 116174- 116175--- lib/a.go -- 116176- 116177-// variety of execution modes. 116178-// 116179-// # Test package setup 116180-// 116181-// The regression test package uses a couple of uncommon patterns to reduce 116182-package lib 116183- 116184--- a.go -- 116185- package main 116186- import "mod.com/lib" 116187- 116188- const A = 1 116189- 116190-} 116191-` 116192- Run(t, source, func(t *testing.T, env *Env) { 116193- t.Run("tags", func(t *testing.T) { 116194- env.OpenFile("a.go") 116195- z := env.RegexpSearch("a.go", "lib") 116196- t.Logf("%#v", z) 116197- got, _ := env.Hover(env.RegexpSearch("a.go", "lib")) 116198- if strings.Contains(got.Value, "{#hdr-") { 116199- t.Errorf("Hover: got {#hdr- tag:\n%q", got) 116200- } 116201- }) 116202- }) 116203-} 116204- 116205-// This is a regression test for Go issue #57625. 116206-func TestHoverModMissingModuleStmt(t *testing.T) { 116207- const source = ` 116208--- go.mod -- 116209-go 1.16 116210-` 116211- Run(t, source, func(t *testing.T, env *Env) { 116212- env.OpenFile("go.mod") 116213- env.Hover(env.RegexpSearch("go.mod", "go")) // no panic 116214- }) 116215-} 116216- 116217-func TestHoverCompletionMarkdown(t *testing.T) { 116218- testenv.NeedsGo1Point(t, 19) 116219- const source = ` 116220--- go.mod -- 116221-module mod.com 116222-go 1.19 116223--- main.go -- 116224-package main 116225-// Just says [hello]. 116226-// 116227-// [hello]: https://en.wikipedia.org/wiki/Hello 116228-func Hello() string { 116229- Hello() //Here 116230- return "hello" 116231-} 116232-` 116233- Run(t, source, func(t *testing.T, env *Env) { 116234- // Hover, Completion, and SignatureHelp should all produce markdown 116235- // check that the markdown for SignatureHelp and Completion are 116236- // the same, and contained in that for Hover (up to trailing \n) 116237- env.OpenFile("main.go") 116238- loc := env.RegexpSearch("main.go", "func (Hello)") 116239- hover, _ := env.Hover(loc) 116240- hoverContent := hover.Value 116241- 116242- loc = env.RegexpSearch("main.go", "//Here") 116243- loc.Range.Start.Character -= 3 // Hello(_) //Here 116244- completions := env.Completion(loc) 116245- signatures := env.SignatureHelp(loc) 116246- 116247- if len(completions.Items) != 1 { 116248- t.Errorf("got %d completions, expected 1", len(completions.Items)) 116249- } 116250- if len(signatures.Signatures) != 1 { 116251- t.Errorf("got %d signatures, expected 1", len(signatures.Signatures)) 116252- } 116253- item := completions.Items[0].Documentation.Value 116254- var itemContent string 116255- if x, ok := item.(protocol.MarkupContent); !ok || x.Kind != protocol.Markdown { 116256- t.Fatalf("%#v is not markdown", item) 116257- } else { 116258- itemContent = strings.Trim(x.Value, "\n") 116259- } 116260- sig := signatures.Signatures[0].Documentation.Value 116261- var sigContent string 116262- if x, ok := sig.(protocol.MarkupContent); !ok || x.Kind != protocol.Markdown { 116263- t.Fatalf("%#v is not markdown", item) 116264- } else { 116265- sigContent = x.Value 116266- } 116267- if itemContent != sigContent { 116268- t.Errorf("item:%q not sig:%q", itemContent, sigContent) 116269- } 116270- if !strings.Contains(hoverContent, itemContent) { 116271- t.Errorf("hover:%q does not containt sig;%q", hoverContent, sigContent) 116272- } 116273- }) 116274-} 116275- 116276-// Test that the generated markdown contains links for Go references. 116277-// https://github.com/golang/go/issues/58352 116278-func TestHoverLinks(t *testing.T) { 116279- testenv.NeedsGo1Point(t, 19) 116280- const input = ` 116281--- go.mod -- 116282-go 1.19 116283-module mod.com 116284--- main.go -- 116285-package main 116286-// [fmt] 116287-var A int 116288-// [fmt.Println] 116289-var B int 116290-// [golang.org/x/tools/go/packages.Package.String] 116291-var C int 116292-` 116293- var tests = []struct { 116294- pat string 116295- ans string 116296- }{ 116297- {"A", "fmt"}, 116298- {"B", "fmt#Println"}, 116299- {"C", "golang.org/x/tools/go/packages#Package.String"}, 116300- } 116301- for _, test := range tests { 116302- Run(t, input, func(t *testing.T, env *Env) { 116303- env.OpenFile("main.go") 116304- loc := env.RegexpSearch("main.go", test.pat) 116305- hover, _ := env.Hover(loc) 116306- hoverContent := hover.Value 116307- want := fmt.Sprintf("%s/%s", "https://pkg.go.dev", test.ans) 116308- if !strings.Contains(hoverContent, want) { 116309- t.Errorf("hover:%q does not contain link %q", hoverContent, want) 116310- } 116311- }) 116312- } 116313-} 116314diff -urN a/gopls/internal/regtest/misc/imports_test.go b/gopls/internal/regtest/misc/imports_test.go 116315--- a/gopls/internal/regtest/misc/imports_test.go 2000-01-01 00:00:00.000000000 -0000 116316+++ b/gopls/internal/regtest/misc/imports_test.go 1970-01-01 00:00:00.000000000 +0000 116317@@ -1,258 +0,0 @@ 116318-// Copyright 2020 The Go Authors. All rights reserved. 116319-// Use of this source code is governed by a BSD-style 116320-// license that can be found in the LICENSE file. 116321- 116322-package misc 116323- 116324-import ( 116325- "io/ioutil" 116326- "os" 116327- "path/filepath" 116328- "strings" 116329- "testing" 116330- 116331- . "golang.org/x/tools/gopls/internal/lsp/regtest" 116332- 116333- "golang.org/x/tools/gopls/internal/lsp/protocol" 116334- "golang.org/x/tools/internal/testenv" 116335-) 116336- 116337-// Tests golang/go#38815. 116338-func TestIssue38815(t *testing.T) { 116339- const needs = ` 116340--- go.mod -- 116341-module foo 116342- 116343-go 1.12 116344--- a.go -- 116345-package main 116346-func f() {} 116347-` 116348- const ntest = `package main 116349-func TestZ(t *testing.T) { 116350- f() 116351-} 116352-` 116353- const want = `package main 116354- 116355-import "testing" 116356- 116357-func TestZ(t *testing.T) { 116358- f() 116359-} 116360-` 116361- 116362- // it was returning 116363- // "package main\nimport \"testing\"\npackage main..." 116364- Run(t, needs, func(t *testing.T, env *Env) { 116365- env.CreateBuffer("a_test.go", ntest) 116366- env.SaveBuffer("a_test.go") 116367- got := env.BufferText("a_test.go") 116368- if want != got { 116369- t.Errorf("got\n%q, wanted\n%q", got, want) 116370- } 116371- }) 116372-} 116373- 116374-func TestVim1(t *testing.T) { 116375- const vim1 = `package main 116376- 116377-import "fmt" 116378- 116379-var foo = 1 116380-var bar = 2 116381- 116382-func main() { 116383- fmt.Printf("This is a test %v\n", foo) 116384- fmt.Printf("This is another test %v\n", foo) 116385- fmt.Printf("This is also a test %v\n", foo) 116386-} 116387-` 116388- 116389- // The file remains unchanged, but if there are any CodeActions returned, they confuse vim. 116390- // Therefore check for no CodeActions 116391- Run(t, "", func(t *testing.T, env *Env) { 116392- env.CreateBuffer("main.go", vim1) 116393- env.OrganizeImports("main.go") 116394- actions := env.CodeAction("main.go", nil) 116395- if len(actions) > 0 { 116396- got := env.BufferText("main.go") 116397- t.Errorf("unexpected actions %#v", actions) 116398- if got == vim1 { 116399- t.Errorf("no changes") 116400- } else { 116401- t.Errorf("got\n%q", got) 116402- t.Errorf("was\n%q", vim1) 116403- } 116404- } 116405- }) 116406-} 116407- 116408-func TestVim2(t *testing.T) { 116409- const vim2 = `package main 116410- 116411-import ( 116412- "fmt" 116413- 116414- "example.com/blah" 116415- 116416- "rubbish.com/useless" 116417-) 116418- 116419-func main() { 116420- fmt.Println(blah.Name, useless.Name) 116421-} 116422-` 116423- 116424- Run(t, "", func(t *testing.T, env *Env) { 116425- env.CreateBuffer("main.go", vim2) 116426- env.OrganizeImports("main.go") 116427- actions := env.CodeAction("main.go", nil) 116428- if len(actions) > 0 { 116429- t.Errorf("unexpected actions %#v", actions) 116430- } 116431- }) 116432-} 116433- 116434-func TestGOMODCACHE(t *testing.T) { 116435- const proxy = ` 116436--- [email protected]/go.mod -- 116437-module example.com 116438- 116439-go 1.12 116440--- [email protected]/x/x.go -- 116441-package x 116442- 116443-const X = 1 116444--- [email protected]/y/y.go -- 116445-package y 116446- 116447-const Y = 2 116448-` 116449- const files = ` 116450--- go.mod -- 116451-module mod.com 116452- 116453-go 1.12 116454- 116455-require example.com v1.2.3 116456--- go.sum -- 116457-example.com v1.2.3 h1:6vTQqzX+pnwngZF1+5gcO3ZEWmix1jJ/h+pWS8wUxK0= 116458-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 116459--- main.go -- 116460-package main 116461- 116462-import "example.com/x" 116463- 116464-var _, _ = x.X, y.Y 116465-` 116466- modcache, err := ioutil.TempDir("", "TestGOMODCACHE-modcache") 116467- if err != nil { 116468- t.Fatal(err) 116469- } 116470- defer os.RemoveAll(modcache) 116471- WithOptions( 116472- EnvVars{"GOMODCACHE": modcache}, 116473- ProxyFiles(proxy), 116474- ).Run(t, files, func(t *testing.T, env *Env) { 116475- env.OpenFile("main.go") 116476- env.AfterChange(Diagnostics(env.AtRegexp("main.go", `y.Y`))) 116477- env.SaveBuffer("main.go") 116478- env.AfterChange(NoDiagnostics(ForFile("main.go"))) 116479- loc := env.GoToDefinition(env.RegexpSearch("main.go", `y.(Y)`)) 116480- path := env.Sandbox.Workdir.URIToPath(loc.URI) 116481- if !strings.HasPrefix(path, filepath.ToSlash(modcache)) { 116482- t.Errorf("found module dependency outside of GOMODCACHE: got %v, wanted subdir of %v", path, filepath.ToSlash(modcache)) 116483- } 116484- }) 116485-} 116486- 116487-// Tests golang/go#40685. 116488-func TestAcceptImportsQuickFixTestVariant(t *testing.T) { 116489- const pkg = ` 116490--- go.mod -- 116491-module mod.com 116492- 116493-go 1.12 116494--- a/a.go -- 116495-package a 116496- 116497-import ( 116498- "fmt" 116499-) 116500- 116501-func _() { 116502- fmt.Println("") 116503- os.Stat("") 116504-} 116505--- a/a_test.go -- 116506-package a 116507- 116508-import ( 116509- "os" 116510- "testing" 116511-) 116512- 116513-func TestA(t *testing.T) { 116514- os.Stat("") 116515-} 116516-` 116517- Run(t, pkg, func(t *testing.T, env *Env) { 116518- env.OpenFile("a/a.go") 116519- var d protocol.PublishDiagnosticsParams 116520- env.AfterChange( 116521- Diagnostics(env.AtRegexp("a/a.go", "os.Stat")), 116522- ReadDiagnostics("a/a.go", &d), 116523- ) 116524- env.ApplyQuickFixes("a/a.go", d.Diagnostics) 116525- env.AfterChange( 116526- NoDiagnostics(ForFile("a/a.go")), 116527- ) 116528- }) 116529-} 116530- 116531-// Test for golang/go#52784 116532-func TestGoWorkImports(t *testing.T) { 116533- testenv.NeedsGo1Point(t, 18) 116534- const pkg = ` 116535--- go.work -- 116536-go 1.19 116537- 116538-use ( 116539- ./caller 116540- ./mod 116541-) 116542--- caller/go.mod -- 116543-module caller.com 116544- 116545-go 1.18 116546- 116547-require mod.com v0.0.0 116548- 116549-replace mod.com => ../mod 116550--- caller/caller.go -- 116551-package main 116552- 116553-func main() { 116554- a.Test() 116555-} 116556--- mod/go.mod -- 116557-module mod.com 116558- 116559-go 1.18 116560--- mod/a/a.go -- 116561-package a 116562- 116563-func Test() { 116564-} 116565-` 116566- Run(t, pkg, func(t *testing.T, env *Env) { 116567- env.OpenFile("caller/caller.go") 116568- env.AfterChange(Diagnostics(env.AtRegexp("caller/caller.go", "a.Test"))) 116569- 116570- // Saving caller.go should trigger goimports, which should find a.Test in 116571- // the mod.com module, thanks to the go.work file. 116572- env.SaveBuffer("caller/caller.go") 116573- env.AfterChange(NoDiagnostics(ForFile("caller/caller.go"))) 116574- }) 116575-} 116576diff -urN a/gopls/internal/regtest/misc/import_test.go b/gopls/internal/regtest/misc/import_test.go 116577--- a/gopls/internal/regtest/misc/import_test.go 2000-01-01 00:00:00.000000000 -0000 116578+++ b/gopls/internal/regtest/misc/import_test.go 1970-01-01 00:00:00.000000000 +0000 116579@@ -1,133 +0,0 @@ 116580-// Copyright 2021 The Go Authors. All rights reserved. 116581-// Use of this source code is governed by a BSD-style 116582-// license that can be found in the LICENSE file. 116583- 116584-package misc 116585- 116586-import ( 116587- "testing" 116588- 116589- "github.com/google/go-cmp/cmp" 116590- "golang.org/x/tools/gopls/internal/lsp/command" 116591- "golang.org/x/tools/gopls/internal/lsp/protocol" 116592- . "golang.org/x/tools/gopls/internal/lsp/regtest" 116593- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 116594-) 116595- 116596-func TestAddImport(t *testing.T) { 116597- const before = `package main 116598- 116599-import "fmt" 116600- 116601-func main() { 116602- fmt.Println("hello world") 116603-} 116604-` 116605- 116606- const want = `package main 116607- 116608-import ( 116609- "bytes" 116610- "fmt" 116611-) 116612- 116613-func main() { 116614- fmt.Println("hello world") 116615-} 116616-` 116617- 116618- Run(t, "", func(t *testing.T, env *Env) { 116619- env.CreateBuffer("main.go", before) 116620- cmd, err := command.NewAddImportCommand("Add Import", command.AddImportArgs{ 116621- URI: env.Sandbox.Workdir.URI("main.go"), 116622- ImportPath: "bytes", 116623- }) 116624- if err != nil { 116625- t.Fatal(err) 116626- } 116627- env.ExecuteCommand(&protocol.ExecuteCommandParams{ 116628- Command: "gopls.add_import", 116629- Arguments: cmd.Arguments, 116630- }, nil) 116631- got := env.BufferText("main.go") 116632- if got != want { 116633- t.Fatalf("gopls.add_import failed\n%s", compare.Text(want, got)) 116634- } 116635- }) 116636-} 116637- 116638-func TestListImports(t *testing.T) { 116639- const files = ` 116640--- go.mod -- 116641-module mod.com 116642- 116643-go 1.12 116644--- foo.go -- 116645-package foo 116646-const C = 1 116647--- import_strings_test.go -- 116648-package foo 116649-import ( 116650- x "strings" 116651- "testing" 116652-) 116653- 116654-func TestFoo(t *testing.T) {} 116655--- import_testing_test.go -- 116656-package foo 116657- 116658-import "testing" 116659- 116660-func TestFoo2(t *testing.T) {} 116661-` 116662- tests := []struct { 116663- filename string 116664- want command.ListImportsResult 116665- }{ 116666- { 116667- filename: "import_strings_test.go", 116668- want: command.ListImportsResult{ 116669- Imports: []command.FileImport{ 116670- {Name: "x", Path: "strings"}, 116671- {Path: "testing"}, 116672- }, 116673- PackageImports: []command.PackageImport{ 116674- {Path: "strings"}, 116675- {Path: "testing"}, 116676- }, 116677- }, 116678- }, 116679- { 116680- filename: "import_testing_test.go", 116681- want: command.ListImportsResult{ 116682- Imports: []command.FileImport{ 116683- {Path: "testing"}, 116684- }, 116685- PackageImports: []command.PackageImport{ 116686- {Path: "strings"}, 116687- {Path: "testing"}, 116688- }, 116689- }, 116690- }, 116691- } 116692- 116693- Run(t, files, func(t *testing.T, env *Env) { 116694- for _, tt := range tests { 116695- cmd, err := command.NewListImportsCommand("List Imports", command.URIArg{ 116696- URI: env.Sandbox.Workdir.URI(tt.filename), 116697- }) 116698- if err != nil { 116699- t.Fatal(err) 116700- } 116701- var result command.ListImportsResult 116702- env.ExecuteCommand(&protocol.ExecuteCommandParams{ 116703- Command: command.ListImports.ID(), 116704- Arguments: cmd.Arguments, 116705- }, &result) 116706- if diff := cmp.Diff(tt.want, result); diff != "" { 116707- t.Errorf("unexpected list imports result for %q (-want +got):\n%s", tt.filename, diff) 116708- } 116709- } 116710- 116711- }) 116712-} 116713diff -urN a/gopls/internal/regtest/misc/leak_test.go b/gopls/internal/regtest/misc/leak_test.go 116714--- a/gopls/internal/regtest/misc/leak_test.go 2000-01-01 00:00:00.000000000 -0000 116715+++ b/gopls/internal/regtest/misc/leak_test.go 1970-01-01 00:00:00.000000000 +0000 116716@@ -1,89 +0,0 @@ 116717-// Copyright 2022 The Go Authors. All rights reserved. 116718-// Use of this source code is governed by a BSD-style 116719-// license that can be found in the LICENSE file. 116720- 116721-package misc 116722- 116723-import ( 116724- "context" 116725- "testing" 116726- 116727- "github.com/google/go-cmp/cmp" 116728- "golang.org/x/tools/gopls/internal/hooks" 116729- "golang.org/x/tools/gopls/internal/lsp/cache" 116730- "golang.org/x/tools/gopls/internal/lsp/debug" 116731- "golang.org/x/tools/gopls/internal/lsp/fake" 116732- "golang.org/x/tools/gopls/internal/lsp/lsprpc" 116733- . "golang.org/x/tools/gopls/internal/lsp/regtest" 116734- "golang.org/x/tools/internal/jsonrpc2" 116735- "golang.org/x/tools/internal/jsonrpc2/servertest" 116736-) 116737- 116738-// Test for golang/go#57222. 116739-func TestCacheLeak(t *testing.T) { 116740- // TODO(rfindley): either fix this test with additional instrumentation, or 116741- // delete it. 116742- t.Skip("This test races with cache eviction.") 116743- const files = `-- a.go -- 116744-package a 116745- 116746-func _() { 116747- println("1") 116748-} 116749-` 116750- c := cache.New(nil) 116751- env := setupEnv(t, files, c) 116752- env.Await(InitialWorkspaceLoad) 116753- env.OpenFile("a.go") 116754- 116755- // Make a couple edits to stabilize cache state. 116756- // 116757- // For some reason, after only one edit we're left with two parsed files 116758- // (perhaps because something had to ParseHeader). If this test proves flaky, 116759- // we'll need to investigate exactly what is causing various parse modes to 116760- // be present (or rewrite the test to be more tolerant, for example make ~100 116761- // modifications and assert that we're within a few of where we're started). 116762- env.RegexpReplace("a.go", "1", "2") 116763- env.RegexpReplace("a.go", "2", "3") 116764- env.AfterChange() 116765- 116766- // Capture cache state, make an arbitrary change, and wait for gopls to do 116767- // its work. Afterward, we should have the exact same number of parsed 116768- before := c.MemStats() 116769- env.RegexpReplace("a.go", "3", "4") 116770- env.AfterChange() 116771- after := c.MemStats() 116772- 116773- if diff := cmp.Diff(before, after); diff != "" { 116774- t.Errorf("store objects differ after change (-before +after)\n%s", diff) 116775- } 116776-} 116777- 116778-// setupEnv creates a new sandbox environment for editing the txtar encoded 116779-// content of files. It uses a new gopls instance backed by the Cache c. 116780-func setupEnv(t *testing.T, files string, c *cache.Cache) *Env { 116781- ctx := debug.WithInstance(context.Background(), "", "off") 116782- server := lsprpc.NewStreamServer(c, false, hooks.Options) 116783- ts := servertest.NewPipeServer(server, jsonrpc2.NewRawStream) 116784- s, err := fake.NewSandbox(&fake.SandboxConfig{ 116785- Files: fake.UnpackTxt(files), 116786- }) 116787- if err != nil { 116788- t.Fatal(err) 116789- } 116790- 116791- a := NewAwaiter(s.Workdir) 116792- const skipApplyEdits = false 116793- editor, err := fake.NewEditor(s, fake.EditorConfig{}).Connect(ctx, ts, a.Hooks(), skipApplyEdits) 116794- if err != nil { 116795- t.Fatal(err) 116796- } 116797- 116798- return &Env{ 116799- T: t, 116800- Ctx: ctx, 116801- Editor: editor, 116802- Sandbox: s, 116803- Awaiter: a, 116804- } 116805-} 116806diff -urN a/gopls/internal/regtest/misc/link_test.go b/gopls/internal/regtest/misc/link_test.go 116807--- a/gopls/internal/regtest/misc/link_test.go 2000-01-01 00:00:00.000000000 -0000 116808+++ b/gopls/internal/regtest/misc/link_test.go 1970-01-01 00:00:00.000000000 +0000 116809@@ -1,96 +0,0 @@ 116810-// Copyright 2020 The Go Authors. All rights reserved. 116811-// Use of this source code is governed by a BSD-style 116812-// license that can be found in the LICENSE file. 116813- 116814-package misc 116815- 116816-import ( 116817- "strings" 116818- "testing" 116819- 116820- . "golang.org/x/tools/gopls/internal/lsp/regtest" 116821-) 116822- 116823-func TestHoverAndDocumentLink(t *testing.T) { 116824- const program = ` 116825--- go.mod -- 116826-module mod.test 116827- 116828-go 1.12 116829- 116830-require import.test v1.2.3 116831--- go.sum -- 116832-import.test v1.2.3 h1:Mu4N9BICLJFxwwn8YNg6T3frkFWW1O7evXvo0HiRjBc= 116833-import.test v1.2.3/go.mod h1:KooCN1g237upRg7irU7F+3oADn5tVClU8YYW4I1xhMk= 116834--- main.go -- 116835-package main 116836- 116837-import "import.test/pkg" 116838- 116839-func main() { 116840- // Issue 43990: this is not a link that most users can open from an LSP 116841- // client: mongodb://not.a.link.com 116842- println(pkg.Hello) 116843-}` 116844- 116845- const proxy = ` 116846--- [email protected]/go.mod -- 116847-module import.test 116848- 116849-go 1.12 116850--- [email protected]/pkg/const.go -- 116851-package pkg 116852- 116853-const Hello = "Hello" 116854-` 116855- WithOptions( 116856- ProxyFiles(proxy), 116857- ).Run(t, program, func(t *testing.T, env *Env) { 116858- env.OpenFile("main.go") 116859- env.OpenFile("go.mod") 116860- 116861- modLink := "https://pkg.go.dev/mod/[email protected]" 116862- pkgLink := "https://pkg.go.dev/[email protected]/pkg" 116863- 116864- // First, check that we get the expected links via hover and documentLink. 116865- content, _ := env.Hover(env.RegexpSearch("main.go", "pkg.Hello")) 116866- if content == nil || !strings.Contains(content.Value, pkgLink) { 116867- t.Errorf("hover: got %v in main.go, want contains %q", content, pkgLink) 116868- } 116869- content, _ = env.Hover(env.RegexpSearch("go.mod", "import.test")) 116870- if content == nil || !strings.Contains(content.Value, pkgLink) { 116871- t.Errorf("hover: got %v in go.mod, want contains %q", content, pkgLink) 116872- } 116873- links := env.DocumentLink("main.go") 116874- if len(links) != 1 || links[0].Target != pkgLink { 116875- t.Errorf("documentLink: got links %+v for main.go, want one link with target %q", links, pkgLink) 116876- } 116877- links = env.DocumentLink("go.mod") 116878- if len(links) != 1 || links[0].Target != modLink { 116879- t.Errorf("documentLink: got links %+v for go.mod, want one link with target %q", links, modLink) 116880- } 116881- 116882- // Then change the environment to make these links private. 116883- cfg := env.Editor.Config() 116884- cfg.Env = map[string]string{"GOPRIVATE": "import.test"} 116885- env.ChangeConfiguration(cfg) 116886- 116887- // Finally, verify that the links are gone. 116888- content, _ = env.Hover(env.RegexpSearch("main.go", "pkg.Hello")) 116889- if content == nil || strings.Contains(content.Value, pkgLink) { 116890- t.Errorf("hover: got %v in main.go, want non-empty hover without %q", content, pkgLink) 116891- } 116892- content, _ = env.Hover(env.RegexpSearch("go.mod", "import.test")) 116893- if content == nil || strings.Contains(content.Value, modLink) { 116894- t.Errorf("hover: got %v in go.mod, want contains %q", content, modLink) 116895- } 116896- links = env.DocumentLink("main.go") 116897- if len(links) != 0 { 116898- t.Errorf("documentLink: got %d document links for main.go, want 0\nlinks: %v", len(links), links) 116899- } 116900- links = env.DocumentLink("go.mod") 116901- if len(links) != 0 { 116902- t.Errorf("documentLink: got %d document links for go.mod, want 0\nlinks: %v", len(links), links) 116903- } 116904- }) 116905-} 116906diff -urN a/gopls/internal/regtest/misc/misc_test.go b/gopls/internal/regtest/misc/misc_test.go 116907--- a/gopls/internal/regtest/misc/misc_test.go 2000-01-01 00:00:00.000000000 -0000 116908+++ b/gopls/internal/regtest/misc/misc_test.go 1970-01-01 00:00:00.000000000 +0000 116909@@ -1,18 +0,0 @@ 116910-// Copyright 2020 The Go Authors. All rights reserved. 116911-// Use of this source code is governed by a BSD-style 116912-// license that can be found in the LICENSE file. 116913- 116914-package misc 116915- 116916-import ( 116917- "testing" 116918- 116919- "golang.org/x/tools/gopls/internal/hooks" 116920- "golang.org/x/tools/gopls/internal/lsp/regtest" 116921- "golang.org/x/tools/internal/bug" 116922-) 116923- 116924-func TestMain(m *testing.M) { 116925- bug.PanicOnBugs = true 116926- regtest.Main(m, hooks.Options) 116927-} 116928diff -urN a/gopls/internal/regtest/misc/multiple_adhoc_test.go b/gopls/internal/regtest/misc/multiple_adhoc_test.go 116929--- a/gopls/internal/regtest/misc/multiple_adhoc_test.go 2000-01-01 00:00:00.000000000 -0000 116930+++ b/gopls/internal/regtest/misc/multiple_adhoc_test.go 1970-01-01 00:00:00.000000000 +0000 116931@@ -1,44 +0,0 @@ 116932-// Copyright 2021 The Go Authors. All rights reserved. 116933-// Use of this source code is governed by a BSD-style 116934-// license that can be found in the LICENSE file. 116935- 116936-package misc 116937- 116938-import ( 116939- "testing" 116940- 116941- . "golang.org/x/tools/gopls/internal/lsp/regtest" 116942-) 116943- 116944-func TestMultipleAdHocPackages(t *testing.T) { 116945- Run(t, ` 116946--- a/a.go -- 116947-package main 116948- 116949-import "fmt" 116950- 116951-func main() { 116952- fmt.Println("") 116953-} 116954--- a/b.go -- 116955-package main 116956- 116957-import "fmt" 116958- 116959-func main() () { 116960- fmt.Println("") 116961-} 116962-`, func(t *testing.T, env *Env) { 116963- env.OpenFile("a/a.go") 116964- if list := env.Completion(env.RegexpSearch("a/a.go", "Println")); list == nil || len(list.Items) == 0 { 116965- t.Fatal("expected completions, got none") 116966- } 116967- env.OpenFile("a/b.go") 116968- if list := env.Completion(env.RegexpSearch("a/b.go", "Println")); list == nil || len(list.Items) == 0 { 116969- t.Fatal("expected completions, got none") 116970- } 116971- if list := env.Completion(env.RegexpSearch("a/a.go", "Println")); list == nil || len(list.Items) == 0 { 116972- t.Fatal("expected completions, got none") 116973- } 116974- }) 116975-} 116976diff -urN a/gopls/internal/regtest/misc/references_test.go b/gopls/internal/regtest/misc/references_test.go 116977--- a/gopls/internal/regtest/misc/references_test.go 2000-01-01 00:00:00.000000000 -0000 116978+++ b/gopls/internal/regtest/misc/references_test.go 1970-01-01 00:00:00.000000000 +0000 116979@@ -1,399 +0,0 @@ 116980-// Copyright 2020 The Go Authors. All rights reserved. 116981-// Use of this source code is governed by a BSD-style 116982-// license that can be found in the LICENSE file. 116983- 116984-package misc 116985- 116986-import ( 116987- "fmt" 116988- "os" 116989- "sort" 116990- "strings" 116991- "testing" 116992- 116993- "github.com/google/go-cmp/cmp" 116994- "golang.org/x/tools/gopls/internal/lsp/protocol" 116995- . "golang.org/x/tools/gopls/internal/lsp/regtest" 116996-) 116997- 116998-func TestStdlibReferences(t *testing.T) { 116999- const files = ` 117000--- go.mod -- 117001-module mod.com 117002- 117003-go 1.12 117004--- main.go -- 117005-package main 117006- 117007-import "fmt" 117008- 117009-func main() { 117010- fmt.Print() 117011-} 117012-` 117013- 117014- Run(t, files, func(t *testing.T, env *Env) { 117015- env.OpenFile("main.go") 117016- loc := env.GoToDefinition(env.RegexpSearch("main.go", `fmt.(Print)`)) 117017- refs, err := env.Editor.References(env.Ctx, loc) 117018- if err != nil { 117019- t.Fatal(err) 117020- } 117021- if len(refs) != 2 { 117022- // TODO(adonovan): make this assertion less maintainer-hostile. 117023- t.Fatalf("got %v reference(s), want 2", len(refs)) 117024- } 117025- // The first reference is guaranteed to be the definition. 117026- if got, want := refs[1].URI, env.Sandbox.Workdir.URI("main.go"); got != want { 117027- t.Errorf("found reference in %v, wanted %v", got, want) 117028- } 117029- }) 117030-} 117031- 117032-// This is a regression test for golang/go#48400 (a panic). 117033-func TestReferencesOnErrorMethod(t *testing.T) { 117034- // Ideally this would actually return the correct answer, 117035- // instead of merely failing gracefully. 117036- const files = ` 117037--- go.mod -- 117038-module mod.com 117039- 117040-go 1.12 117041--- main.go -- 117042-package main 117043- 117044-type t interface { 117045- error 117046-} 117047- 117048-type s struct{} 117049- 117050-func (*s) Error() string { 117051- return "" 117052-} 117053- 117054-func _() { 117055- var s s 117056- _ = s.Error() 117057-} 117058-` 117059- Run(t, files, func(t *testing.T, env *Env) { 117060- env.OpenFile("main.go") 117061- loc := env.GoToDefinition(env.RegexpSearch("main.go", `Error`)) 117062- refs, err := env.Editor.References(env.Ctx, loc) 117063- if err != nil { 117064- t.Fatalf("references on (*s).Error failed: %v", err) 117065- } 117066- // TODO(adonovan): this test is crying out for marker support in regtests. 117067- var buf strings.Builder 117068- for _, ref := range refs { 117069- fmt.Fprintf(&buf, "%s %s\n", env.Sandbox.Workdir.URIToPath(ref.URI), ref.Range) 117070- } 117071- got := buf.String() 117072- want := "main.go 8:10-8:15\n" + // (*s).Error decl 117073- "main.go 14:7-14:12\n" // s.Error() call 117074- if diff := cmp.Diff(want, got); diff != "" { 117075- t.Errorf("unexpected references on (*s).Error (-want +got):\n%s", diff) 117076- } 117077- }) 117078-} 117079- 117080-func TestPackageReferences(t *testing.T) { 117081- tests := []struct { 117082- packageName string 117083- wantRefCount int 117084- wantFiles []string 117085- }{ 117086- { 117087- "lib1", 117088- 3, 117089- []string{ 117090- "main.go", 117091- "lib1/a.go", 117092- "lib1/b.go", 117093- }, 117094- }, 117095- { 117096- "lib2", 117097- 2, 117098- []string{ 117099- "main.go", 117100- "lib2/a.go", 117101- }, 117102- }, 117103- } 117104- 117105- const files = ` 117106--- go.mod -- 117107-module mod.com 117108- 117109-go 1.18 117110--- lib1/a.go -- 117111-package lib1 117112- 117113-const A = 1 117114- 117115--- lib1/b.go -- 117116-package lib1 117117- 117118-const B = 1 117119- 117120--- lib2/a.go -- 117121-package lib2 117122- 117123-const C = 1 117124- 117125--- main.go -- 117126-package main 117127- 117128-import ( 117129- "mod.com/lib1" 117130- "mod.com/lib2" 117131-) 117132- 117133-func main() { 117134- println("Hello") 117135-} 117136-` 117137- Run(t, files, func(t *testing.T, env *Env) { 117138- for _, test := range tests { 117139- file := fmt.Sprintf("%s/a.go", test.packageName) 117140- env.OpenFile(file) 117141- loc := env.RegexpSearch(file, test.packageName) 117142- refs := env.References(loc) 117143- if len(refs) != test.wantRefCount { 117144- // TODO(adonovan): make this assertion less maintainer-hostile. 117145- t.Fatalf("got %v reference(s), want %d", len(refs), test.wantRefCount) 117146- } 117147- var refURIs []string 117148- for _, ref := range refs { 117149- refURIs = append(refURIs, string(ref.URI)) 117150- } 117151- for _, base := range test.wantFiles { 117152- hasBase := false 117153- for _, ref := range refURIs { 117154- if strings.HasSuffix(ref, base) { 117155- hasBase = true 117156- break 117157- } 117158- } 117159- if !hasBase { 117160- t.Fatalf("got [%v], want reference ends with \"%v\"", strings.Join(refURIs, ","), base) 117161- } 117162- } 117163- } 117164- }) 117165-} 117166- 117167-// Test for golang/go#43144. 117168-// 117169-// Verify that we search for references and implementations in intermediate 117170-// test variants. 117171-func TestReferencesInTestVariants(t *testing.T) { 117172- const files = ` 117173--- go.mod -- 117174-module foo.mod 117175- 117176-go 1.12 117177--- foo/foo.go -- 117178-package foo 117179- 117180-import "foo.mod/bar" 117181- 117182-const Foo = 42 117183- 117184-type T int 117185-type InterfaceM interface{ M() } 117186-type InterfaceF interface{ F() } 117187- 117188-func _() { 117189- _ = bar.Blah 117190-} 117191- 117192--- foo/foo_test.go -- 117193-package foo 117194- 117195-type Fer struct{} 117196-func (Fer) F() {} 117197- 117198--- bar/bar.go -- 117199-package bar 117200- 117201-var Blah = 123 117202- 117203--- bar/bar_test.go -- 117204-package bar 117205- 117206-type Mer struct{} 117207-func (Mer) M() {} 117208- 117209-func TestBar() { 117210- _ = Blah 117211-} 117212--- bar/bar_x_test.go -- 117213-package bar_test 117214- 117215-import ( 117216- "foo.mod/bar" 117217- "foo.mod/foo" 117218-) 117219- 117220-type Mer struct{} 117221-func (Mer) M() {} 117222- 117223-func _() { 117224- _ = bar.Blah 117225- _ = foo.Foo 117226-} 117227-` 117228- 117229- Run(t, files, func(t *testing.T, env *Env) { 117230- env.OpenFile("foo/foo.go") 117231- 117232- // Helper to map locations relative file paths. 117233- fileLocations := func(locs []protocol.Location) []string { 117234- var got []string 117235- for _, loc := range locs { 117236- got = append(got, env.Sandbox.Workdir.URIToPath(loc.URI)) 117237- } 117238- sort.Strings(got) 117239- return got 117240- } 117241- 117242- refTests := []struct { 117243- re string 117244- wantRefs []string 117245- }{ 117246- // Blah is referenced: 117247- // - inside the foo.mod/bar (ordinary) package 117248- // - inside the foo.mod/bar [foo.mod/bar.test] test variant package 117249- // - from the foo.mod/bar_test [foo.mod/bar.test] x_test package 117250- // - from the foo.mod/foo package 117251- {"Blah", []string{"bar/bar.go", "bar/bar_test.go", "bar/bar_x_test.go", "foo/foo.go"}}, 117252- 117253- // Foo is referenced in bar_x_test.go via the intermediate test variant 117254- // foo.mod/foo [foo.mod/bar.test]. 117255- {"Foo", []string{"bar/bar_x_test.go", "foo/foo.go"}}, 117256- } 117257- 117258- for _, test := range refTests { 117259- loc := env.RegexpSearch("foo/foo.go", test.re) 117260- refs := env.References(loc) 117261- 117262- got := fileLocations(refs) 117263- if diff := cmp.Diff(test.wantRefs, got); diff != "" { 117264- t.Errorf("References(%q) returned unexpected diff (-want +got):\n%s", test.re, diff) 117265- } 117266- } 117267- 117268- implTests := []struct { 117269- re string 117270- wantImpls []string 117271- }{ 117272- // InterfaceM is implemented both in foo.mod/bar [foo.mod/bar.test] (which 117273- // doesn't import foo), and in foo.mod/bar_test [foo.mod/bar.test], which 117274- // imports the test variant of foo. 117275- {"InterfaceM", []string{"bar/bar_test.go", "bar/bar_x_test.go"}}, 117276- 117277- // A search within the ordinary package to should find implementations 117278- // (Fer) within the augmented test package. 117279- {"InterfaceF", []string{"foo/foo_test.go"}}, 117280- } 117281- 117282- for _, test := range implTests { 117283- loc := env.RegexpSearch("foo/foo.go", test.re) 117284- impls := env.Implementations(loc) 117285- 117286- got := fileLocations(impls) 117287- if diff := cmp.Diff(test.wantImpls, got); diff != "" { 117288- t.Errorf("Implementations(%q) returned unexpected diff (-want +got):\n%s", test.re, diff) 117289- } 117290- } 117291- }) 117292-} 117293- 117294-// This is a regression test for Issue #56169, in which interface 117295-// implementations in vendored modules were not found. The actual fix 117296-// was the same as for #55995; see TestVendoringInvalidatesMetadata. 117297-func TestImplementationsInVendor(t *testing.T) { 117298- t.Skip("golang/go#56169: file watching does not capture vendor dirs") 117299- 117300- const proxy = ` 117301--- other.com/[email protected]/go.mod -- 117302-module other.com/b 117303-go 1.14 117304- 117305--- other.com/[email protected]/b.go -- 117306-package b 117307-type B int 117308-func (B) F() {} 117309-` 117310- const src = ` 117311--- go.mod -- 117312-module example.com/a 117313-go 1.14 117314-require other.com/b v1.0.0 117315- 117316--- go.sum -- 117317-other.com/b v1.0.0 h1:9WyCKS+BLAMRQM0CegP6zqP2beP+ShTbPaARpNY31II= 117318-other.com/b v1.0.0/go.mod h1:TgHQFucl04oGT+vrUm/liAzukYHNxCwKNkQZEyn3m9g= 117319- 117320--- a.go -- 117321-package a 117322-import "other.com/b" 117323-type I interface { F() } 117324-var _ b.B 117325- 117326-` 117327- WithOptions( 117328- ProxyFiles(proxy), 117329- Modes(Default), // fails in 'experimental' mode 117330- ).Run(t, src, func(t *testing.T, env *Env) { 117331- // Enable to debug go.sum mismatch, which may appear as 117332- // "module lookup disabled by GOPROXY=off", confusingly. 117333- if false { 117334- env.DumpGoSum(".") 117335- } 117336- 117337- checkVendor := func(locs []protocol.Location, wantVendor bool) { 117338- if len(locs) != 1 { 117339- t.Errorf("got %d locations, want 1", len(locs)) 117340- } else if strings.Contains(string(locs[0].URI), "/vendor/") != wantVendor { 117341- t.Errorf("got location %s, wantVendor=%t", locs[0], wantVendor) 117342- } 117343- } 117344- 117345- env.OpenFile("a.go") 117346- refLoc := env.RegexpSearch("a.go", "I") // find "I" reference 117347- 117348- // Initially, a.I has one implementation b.B in 117349- // the module cache, not the vendor tree. 117350- checkVendor(env.Implementations(refLoc), false) 117351- 117352- // Run 'go mod vendor' outside the editor. 117353- if err := env.Sandbox.RunGoCommand(env.Ctx, ".", "mod", []string{"vendor"}, true); err != nil { 117354- t.Fatalf("go mod vendor: %v", err) 117355- } 117356- 117357- // Synchronize changes to watched files. 117358- env.Await(env.DoneWithChangeWatchedFiles()) 117359- 117360- // Now, b.B is found in the vendor tree. 117361- checkVendor(env.Implementations(refLoc), true) 117362- 117363- // Delete the vendor tree. 117364- if err := os.RemoveAll(env.Sandbox.Workdir.AbsPath("vendor")); err != nil { 117365- t.Fatal(err) 117366- } 117367- // Notify the server of the deletion. 117368- if err := env.Sandbox.Workdir.CheckForFileChanges(env.Ctx); err != nil { 117369- t.Fatal(err) 117370- } 117371- 117372- // Synchronize again. 117373- env.Await(env.DoneWithChangeWatchedFiles()) 117374- 117375- // b.B is once again defined in the module cache. 117376- checkVendor(env.Implementations(refLoc), false) 117377- }) 117378-} 117379diff -urN a/gopls/internal/regtest/misc/rename_test.go b/gopls/internal/regtest/misc/rename_test.go 117380--- a/gopls/internal/regtest/misc/rename_test.go 2000-01-01 00:00:00.000000000 -0000 117381+++ b/gopls/internal/regtest/misc/rename_test.go 1970-01-01 00:00:00.000000000 +0000 117382@@ -1,935 +0,0 @@ 117383-// Copyright 2021 The Go Authors. All rights reserved. 117384-// Use of this source code is governed by a BSD-style 117385-// license that can be found in the LICENSE file. 117386- 117387-package misc 117388- 117389-import ( 117390- "fmt" 117391- "strings" 117392- "testing" 117393- 117394- "golang.org/x/tools/gopls/internal/lsp/protocol" 117395- . "golang.org/x/tools/gopls/internal/lsp/regtest" 117396- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 117397- "golang.org/x/tools/internal/testenv" 117398-) 117399- 117400-func TestPrepareRenameMainPackage(t *testing.T) { 117401- const files = ` 117402--- go.mod -- 117403-module mod.com 117404- 117405-go 1.18 117406--- main.go -- 117407-package main 117408- 117409-import ( 117410- "fmt" 117411-) 117412- 117413-func main() { 117414- fmt.Println(1) 117415-} 117416-` 117417- const wantErr = "can't rename package \"main\"" 117418- Run(t, files, func(t *testing.T, env *Env) { 117419- env.OpenFile("main.go") 117420- loc := env.RegexpSearch("main.go", `main`) 117421- params := &protocol.PrepareRenameParams{ 117422- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 117423- } 117424- _, err := env.Editor.Server.PrepareRename(env.Ctx, params) 117425- if err == nil { 117426- t.Errorf("missing can't rename package main error from PrepareRename") 117427- } 117428- 117429- if err.Error() != wantErr { 117430- t.Errorf("got %v, want %v", err.Error(), wantErr) 117431- } 117432- }) 117433-} 117434- 117435-// Test case for golang/go#56227 117436-func TestRenameWithUnsafeSlice(t *testing.T) { 117437- testenv.NeedsGo1Point(t, 17) // unsafe.Slice was added in Go 1.17 117438- const files = ` 117439--- go.mod -- 117440-module mod.com 117441- 117442-go 1.18 117443--- p.go -- 117444-package p 117445- 117446-import "unsafe" 117447- 117448-type T struct{} 117449- 117450-func (T) M() {} 117451- 117452-func _() { 117453- x := [3]int{1, 2, 3} 117454- ptr := unsafe.Pointer(&x) 117455- _ = unsafe.Slice((*int)(ptr), 3) 117456-} 117457-` 117458- 117459- Run(t, files, func(t *testing.T, env *Env) { 117460- env.OpenFile("p.go") 117461- env.Rename(env.RegexpSearch("p.go", "M"), "N") // must not panic 117462- }) 117463-} 117464- 117465-func TestPrepareRenameWithNoPackageDeclaration(t *testing.T) { 117466- const files = ` 117467-go 1.14 117468--- lib/a.go -- 117469-import "fmt" 117470- 117471-const A = 1 117472- 117473-func bar() { 117474- fmt.Println("Bar") 117475-} 117476- 117477--- main.go -- 117478-package main 117479- 117480-import "fmt" 117481- 117482-func main() { 117483- fmt.Println("Hello") 117484-} 117485-` 117486- Run(t, files, func(t *testing.T, env *Env) { 117487- env.OpenFile("lib/a.go") 117488- err := env.Editor.Rename(env.Ctx, env.RegexpSearch("lib/a.go", "fmt"), "fmt1") 117489- if got, want := fmt.Sprint(err), "no identifier found"; got != want { 117490- t.Errorf("Rename: got error %v, want %v", got, want) 117491- } 117492- }) 117493-} 117494- 117495-func TestPrepareRenameFailWithUnknownModule(t *testing.T) { 117496- testenv.NeedsGo1Point(t, 17) 117497- const files = ` 117498-go 1.14 117499--- lib/a.go -- 117500-package lib 117501- 117502-const A = 1 117503- 117504--- main.go -- 117505-package main 117506- 117507-import ( 117508- "mod.com/lib" 117509-) 117510- 117511-func main() { 117512- println("Hello") 117513-} 117514-` 117515- const wantErr = "can't rename package: missing module information for package" 117516- Run(t, files, func(t *testing.T, env *Env) { 117517- loc := env.RegexpSearch("lib/a.go", "lib") 117518- params := &protocol.PrepareRenameParams{ 117519- TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc), 117520- } 117521- _, err := env.Editor.Server.PrepareRename(env.Ctx, params) 117522- if err == nil || !strings.Contains(err.Error(), wantErr) { 117523- t.Errorf("missing cannot rename packages with unknown module from PrepareRename") 117524- } 117525- }) 117526-} 117527- 117528-// This test ensures that each import of a renamed package 117529-// is also renamed if it would otherwise create a conflict. 117530-func TestRenamePackageWithConflicts(t *testing.T) { 117531- testenv.NeedsGo1Point(t, 17) 117532- const files = ` 117533--- go.mod -- 117534-module mod.com 117535- 117536-go 1.18 117537--- lib/a.go -- 117538-package lib 117539- 117540-const A = 1 117541- 117542--- lib/nested/a.go -- 117543-package nested 117544- 117545-const B = 1 117546- 117547--- lib/x/a.go -- 117548-package nested1 117549- 117550-const C = 1 117551- 117552--- main.go -- 117553-package main 117554- 117555-import ( 117556- "mod.com/lib" 117557- "mod.com/lib/nested" 117558- nested1 "mod.com/lib/x" 117559-) 117560- 117561-func main() { 117562- println("Hello") 117563-} 117564-` 117565- Run(t, files, func(t *testing.T, env *Env) { 117566- env.OpenFile("lib/a.go") 117567- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "nested") 117568- 117569- // Check if the new package name exists. 117570- env.RegexpSearch("nested/a.go", "package nested") 117571- env.RegexpSearch("main.go", `nested2 "mod.com/nested"`) 117572- env.RegexpSearch("main.go", "mod.com/nested/nested") 117573- env.RegexpSearch("main.go", `nested1 "mod.com/nested/x"`) 117574- }) 117575-} 117576- 117577-func TestRenamePackageWithAlias(t *testing.T) { 117578- testenv.NeedsGo1Point(t, 17) 117579- const files = ` 117580--- go.mod -- 117581-module mod.com 117582- 117583-go 1.18 117584--- lib/a.go -- 117585-package lib 117586- 117587-const A = 1 117588- 117589--- lib/nested/a.go -- 117590-package nested 117591- 117592-const B = 1 117593- 117594--- main.go -- 117595-package main 117596- 117597-import ( 117598- "mod.com/lib" 117599- lib1 "mod.com/lib/nested" 117600-) 117601- 117602-func main() { 117603- println("Hello") 117604-} 117605-` 117606- Run(t, files, func(t *testing.T, env *Env) { 117607- env.OpenFile("lib/a.go") 117608- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "nested") 117609- 117610- // Check if the new package name exists. 117611- env.RegexpSearch("nested/a.go", "package nested") 117612- env.RegexpSearch("main.go", "mod.com/nested") 117613- env.RegexpSearch("main.go", `lib1 "mod.com/nested/nested"`) 117614- }) 117615-} 117616- 117617-func TestRenamePackageWithDifferentDirectoryPath(t *testing.T) { 117618- testenv.NeedsGo1Point(t, 17) 117619- const files = ` 117620--- go.mod -- 117621-module mod.com 117622- 117623-go 1.18 117624--- lib/a.go -- 117625-package lib 117626- 117627-const A = 1 117628- 117629--- lib/nested/a.go -- 117630-package foo 117631- 117632-const B = 1 117633- 117634--- main.go -- 117635-package main 117636- 117637-import ( 117638- "mod.com/lib" 117639- foo "mod.com/lib/nested" 117640-) 117641- 117642-func main() { 117643- println("Hello") 117644-} 117645-` 117646- Run(t, files, func(t *testing.T, env *Env) { 117647- env.OpenFile("lib/a.go") 117648- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "nested") 117649- 117650- // Check if the new package name exists. 117651- env.RegexpSearch("nested/a.go", "package nested") 117652- env.RegexpSearch("main.go", "mod.com/nested") 117653- env.RegexpSearch("main.go", `foo "mod.com/nested/nested"`) 117654- }) 117655-} 117656- 117657-func TestRenamePackage(t *testing.T) { 117658- testenv.NeedsGo1Point(t, 17) 117659- const files = ` 117660--- go.mod -- 117661-module mod.com 117662- 117663-go 1.18 117664--- lib/a.go -- 117665-package lib 117666- 117667-const A = 1 117668- 117669--- lib/b.go -- 117670-package lib 117671- 117672-const B = 1 117673- 117674--- lib/nested/a.go -- 117675-package nested 117676- 117677-const C = 1 117678- 117679--- main.go -- 117680-package main 117681- 117682-import ( 117683- "mod.com/lib" 117684- "mod.com/lib/nested" 117685-) 117686- 117687-func main() { 117688- println("Hello") 117689-} 117690-` 117691- Run(t, files, func(t *testing.T, env *Env) { 117692- env.OpenFile("lib/a.go") 117693- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "lib1") 117694- 117695- // Check if the new package name exists. 117696- env.RegexpSearch("lib1/a.go", "package lib1") 117697- env.RegexpSearch("lib1/b.go", "package lib1") 117698- env.RegexpSearch("main.go", "mod.com/lib1") 117699- env.RegexpSearch("main.go", "mod.com/lib1/nested") 117700- }) 117701-} 117702- 117703-// Test for golang/go#47564. 117704-func TestRenameInTestVariant(t *testing.T) { 117705- const files = ` 117706--- go.mod -- 117707-module mod.com 117708- 117709-go 1.12 117710--- stringutil/stringutil.go -- 117711-package stringutil 117712- 117713-func Identity(s string) string { 117714- return s 117715-} 117716--- stringutil/stringutil_test.go -- 117717-package stringutil 117718- 117719-func TestIdentity(t *testing.T) { 117720- if got := Identity("foo"); got != "foo" { 117721- t.Errorf("bad") 117722- } 117723-} 117724--- main.go -- 117725-package main 117726- 117727-import ( 117728- "fmt" 117729- 117730- "mod.com/stringutil" 117731-) 117732- 117733-func main() { 117734- fmt.Println(stringutil.Identity("hello world")) 117735-} 117736-` 117737- 117738- Run(t, files, func(t *testing.T, env *Env) { 117739- env.OpenFile("main.go") 117740- env.Rename(env.RegexpSearch("main.go", `stringutil\.(Identity)`), "Identityx") 117741- env.OpenFile("stringutil/stringutil_test.go") 117742- text := env.BufferText("stringutil/stringutil_test.go") 117743- if !strings.Contains(text, "Identityx") { 117744- t.Errorf("stringutil/stringutil_test.go: missing expected token `Identityx` after rename:\n%s", text) 117745- } 117746- }) 117747-} 117748- 117749-// This is a test that rename operation initiated by the editor function as expected. 117750-func TestRenameFileFromEditor(t *testing.T) { 117751- const files = ` 117752--- go.mod -- 117753-module mod.com 117754- 117755-go 1.16 117756--- a/a.go -- 117757-package a 117758- 117759-const X = 1 117760--- a/x.go -- 117761-package a 117762- 117763-const X = 2 117764--- b/b.go -- 117765-package b 117766-` 117767- 117768- Run(t, files, func(t *testing.T, env *Env) { 117769- // Rename files and verify that diagnostics are affected accordingly. 117770- 117771- // Initially, we should have diagnostics on both X's, for their duplicate declaration. 117772- env.OnceMet( 117773- InitialWorkspaceLoad, 117774- Diagnostics(env.AtRegexp("a/a.go", "X")), 117775- Diagnostics(env.AtRegexp("a/x.go", "X")), 117776- ) 117777- 117778- // Moving x.go should make the diagnostic go away. 117779- env.RenameFile("a/x.go", "b/x.go") 117780- env.AfterChange( 117781- NoDiagnostics(ForFile("a/a.go")), // no more duplicate declarations 117782- Diagnostics(env.AtRegexp("b/b.go", "package")), // as package names mismatch 117783- ) 117784- 117785- // Renaming should also work on open buffers. 117786- env.OpenFile("b/x.go") 117787- 117788- // Moving x.go back to a/ should cause the diagnostics to reappear. 117789- env.RenameFile("b/x.go", "a/x.go") 117790- env.AfterChange( 117791- Diagnostics(env.AtRegexp("a/a.go", "X")), 117792- Diagnostics(env.AtRegexp("a/x.go", "X")), 117793- ) 117794- 117795- // Renaming the entire directory should move both the open and closed file. 117796- env.RenameFile("a", "x") 117797- env.AfterChange( 117798- Diagnostics(env.AtRegexp("x/a.go", "X")), 117799- Diagnostics(env.AtRegexp("x/x.go", "X")), 117800- ) 117801- 117802- // As a sanity check, verify that x/x.go is open. 117803- if text := env.BufferText("x/x.go"); text == "" { 117804- t.Fatal("got empty buffer for x/x.go") 117805- } 117806- }) 117807-} 117808- 117809-func TestRenamePackage_Tests(t *testing.T) { 117810- testenv.NeedsGo1Point(t, 17) 117811- const files = ` 117812--- go.mod -- 117813-module mod.com 117814- 117815-go 1.18 117816--- lib/a.go -- 117817-package lib 117818- 117819-const A = 1 117820- 117821--- lib/b.go -- 117822-package lib 117823- 117824-const B = 1 117825- 117826--- lib/a_test.go -- 117827-package lib_test 117828- 117829-import ( 117830- "mod.com/lib" 117831- "fmt 117832-) 117833- 117834-const C = 1 117835- 117836--- lib/b_test.go -- 117837-package lib 117838- 117839-import ( 117840- "fmt 117841-) 117842- 117843-const D = 1 117844- 117845--- lib/nested/a.go -- 117846-package nested 117847- 117848-const D = 1 117849- 117850--- main.go -- 117851-package main 117852- 117853-import ( 117854- "mod.com/lib" 117855- "mod.com/lib/nested" 117856-) 117857- 117858-func main() { 117859- println("Hello") 117860-} 117861-` 117862- Run(t, files, func(t *testing.T, env *Env) { 117863- env.OpenFile("lib/a.go") 117864- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "lib1") 117865- 117866- // Check if the new package name exists. 117867- env.RegexpSearch("lib1/a.go", "package lib1") 117868- env.RegexpSearch("lib1/b.go", "package lib1") 117869- env.RegexpSearch("main.go", "mod.com/lib1") 117870- env.RegexpSearch("main.go", "mod.com/lib1/nested") 117871- 117872- // Check if the test package is renamed 117873- env.RegexpSearch("lib1/a_test.go", "package lib1_test") 117874- env.RegexpSearch("lib1/b_test.go", "package lib1") 117875- }) 117876-} 117877- 117878-func TestRenamePackage_NestedModule(t *testing.T) { 117879- testenv.NeedsGo1Point(t, 18) 117880- const files = ` 117881--- go.work -- 117882-go 1.18 117883-use ( 117884- . 117885- ./foo/bar 117886- ./foo/baz 117887-) 117888- 117889--- go.mod -- 117890-module mod.com 117891- 117892-go 1.18 117893- 117894-require ( 117895- mod.com/foo/bar v0.0.0 117896-) 117897- 117898-replace ( 117899- mod.com/foo/bar => ./foo/bar 117900- mod.com/foo/baz => ./foo/baz 117901-) 117902--- foo/foo.go -- 117903-package foo 117904- 117905-import "fmt" 117906- 117907-func Bar() { 117908- fmt.Println("In foo before renamed to foox.") 117909-} 117910- 117911--- foo/bar/go.mod -- 117912-module mod.com/foo/bar 117913- 117914--- foo/bar/bar.go -- 117915-package bar 117916- 117917-const Msg = "Hi from package bar" 117918- 117919--- foo/baz/go.mod -- 117920-module mod.com/foo/baz 117921- 117922--- foo/baz/baz.go -- 117923-package baz 117924- 117925-const Msg = "Hi from package baz" 117926- 117927--- main.go -- 117928-package main 117929- 117930-import ( 117931- "fmt" 117932- "mod.com/foo/bar" 117933- "mod.com/foo/baz" 117934- "mod.com/foo" 117935-) 117936- 117937-func main() { 117938- foo.Bar() 117939- fmt.Println(bar.Msg) 117940- fmt.Println(baz.Msg) 117941-} 117942-` 117943- Run(t, files, func(t *testing.T, env *Env) { 117944- env.OpenFile("foo/foo.go") 117945- env.Rename(env.RegexpSearch("foo/foo.go", "foo"), "foox") 117946- 117947- env.RegexpSearch("foox/foo.go", "package foox") 117948- env.OpenFile("foox/bar/bar.go") 117949- env.OpenFile("foox/bar/go.mod") 117950- 117951- env.RegexpSearch("main.go", "mod.com/foo/bar") 117952- env.RegexpSearch("main.go", "mod.com/foox") 117953- env.RegexpSearch("main.go", "foox.Bar()") 117954- 117955- env.RegexpSearch("go.mod", "./foox/bar") 117956- env.RegexpSearch("go.mod", "./foox/baz") 117957- }) 117958-} 117959- 117960-func TestRenamePackage_DuplicateImport(t *testing.T) { 117961- testenv.NeedsGo1Point(t, 17) 117962- const files = ` 117963--- go.mod -- 117964-module mod.com 117965- 117966-go 1.18 117967--- lib/a.go -- 117968-package lib 117969- 117970-const A = 1 117971- 117972--- lib/nested/a.go -- 117973-package nested 117974- 117975-const B = 1 117976- 117977--- main.go -- 117978-package main 117979- 117980-import ( 117981- "mod.com/lib" 117982- lib1 "mod.com/lib" 117983- lib2 "mod.com/lib/nested" 117984-) 117985- 117986-func main() { 117987- println("Hello") 117988-} 117989-` 117990- Run(t, files, func(t *testing.T, env *Env) { 117991- env.OpenFile("lib/a.go") 117992- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "nested") 117993- 117994- // Check if the new package name exists. 117995- env.RegexpSearch("nested/a.go", "package nested") 117996- env.RegexpSearch("main.go", "mod.com/nested") 117997- env.RegexpSearch("main.go", `lib1 "mod.com/nested"`) 117998- env.RegexpSearch("main.go", `lib2 "mod.com/nested/nested"`) 117999- }) 118000-} 118001- 118002-func TestRenamePackage_DuplicateBlankImport(t *testing.T) { 118003- testenv.NeedsGo1Point(t, 17) 118004- const files = ` 118005--- go.mod -- 118006-module mod.com 118007- 118008-go 1.18 118009--- lib/a.go -- 118010-package lib 118011- 118012-const A = 1 118013- 118014--- lib/nested/a.go -- 118015-package nested 118016- 118017-const B = 1 118018- 118019--- main.go -- 118020-package main 118021- 118022-import ( 118023- "mod.com/lib" 118024- _ "mod.com/lib" 118025- lib1 "mod.com/lib/nested" 118026-) 118027- 118028-func main() { 118029- println("Hello") 118030-} 118031-` 118032- Run(t, files, func(t *testing.T, env *Env) { 118033- env.OpenFile("lib/a.go") 118034- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "nested") 118035- 118036- // Check if the new package name exists. 118037- env.RegexpSearch("nested/a.go", "package nested") 118038- env.RegexpSearch("main.go", "mod.com/nested") 118039- env.RegexpSearch("main.go", `_ "mod.com/nested"`) 118040- env.RegexpSearch("main.go", `lib1 "mod.com/nested/nested"`) 118041- }) 118042-} 118043- 118044-func TestRenamePackage_TestVariant(t *testing.T) { 118045- const files = ` 118046--- go.mod -- 118047-module mod.com 118048- 118049-go 1.12 118050--- foo/foo.go -- 118051-package foo 118052- 118053-const Foo = 42 118054--- bar/bar.go -- 118055-package bar 118056- 118057-import "mod.com/foo" 118058- 118059-const Bar = foo.Foo 118060--- bar/bar_test.go -- 118061-package bar 118062- 118063-import "mod.com/foo" 118064- 118065-const Baz = foo.Foo 118066--- testdata/bar/bar.go -- 118067-package bar 118068- 118069-import "mod.com/foox" 118070- 118071-const Bar = foox.Foo 118072--- testdata/bar/bar_test.go -- 118073-package bar 118074- 118075-import "mod.com/foox" 118076- 118077-const Baz = foox.Foo 118078-` 118079- Run(t, files, func(t *testing.T, env *Env) { 118080- env.OpenFile("foo/foo.go") 118081- env.Rename(env.RegexpSearch("foo/foo.go", "package (foo)"), "foox") 118082- 118083- checkTestdata(t, env) 118084- }) 118085-} 118086- 118087-func TestRenamePackage_IntermediateTestVariant(t *testing.T) { 118088- // In this test set up, we have the following import edges: 118089- // bar_test -> baz -> foo -> bar 118090- // bar_test -> foo -> bar 118091- // bar_test -> bar 118092- // 118093- // As a consequence, bar_x_test.go is in the reverse closure of both 118094- // `foo [bar.test]` and `baz [bar.test]`. This test confirms that we don't 118095- // produce duplicate edits in this case. 118096- const files = ` 118097--- go.mod -- 118098-module foo.mod 118099- 118100-go 1.12 118101--- foo/foo.go -- 118102-package foo 118103- 118104-import "foo.mod/bar" 118105- 118106-const Foo = 42 118107- 118108-const _ = bar.Bar 118109--- baz/baz.go -- 118110-package baz 118111- 118112-import "foo.mod/foo" 118113- 118114-const Baz = foo.Foo 118115--- bar/bar.go -- 118116-package bar 118117- 118118-var Bar = 123 118119--- bar/bar_test.go -- 118120-package bar 118121- 118122-const _ = Bar 118123--- bar/bar_x_test.go -- 118124-package bar_test 118125- 118126-import ( 118127- "foo.mod/bar" 118128- "foo.mod/baz" 118129- "foo.mod/foo" 118130-) 118131- 118132-const _ = bar.Bar + baz.Baz + foo.Foo 118133--- testdata/foox/foo.go -- 118134-package foox 118135- 118136-import "foo.mod/bar" 118137- 118138-const Foo = 42 118139- 118140-const _ = bar.Bar 118141--- testdata/baz/baz.go -- 118142-package baz 118143- 118144-import "foo.mod/foox" 118145- 118146-const Baz = foox.Foo 118147--- testdata/bar/bar_x_test.go -- 118148-package bar_test 118149- 118150-import ( 118151- "foo.mod/bar" 118152- "foo.mod/baz" 118153- "foo.mod/foox" 118154-) 118155- 118156-const _ = bar.Bar + baz.Baz + foox.Foo 118157-` 118158- 118159- Run(t, files, func(t *testing.T, env *Env) { 118160- env.OpenFile("foo/foo.go") 118161- env.Rename(env.RegexpSearch("foo/foo.go", "package (foo)"), "foox") 118162- 118163- checkTestdata(t, env) 118164- }) 118165-} 118166- 118167-func TestRenamePackage_Nesting(t *testing.T) { 118168- testenv.NeedsGo1Point(t, 17) 118169- const files = ` 118170--- go.mod -- 118171-module mod.com 118172- 118173-go 1.18 118174--- lib/a.go -- 118175-package lib 118176- 118177-import "mod.com/lib/nested" 118178- 118179-const A = 1 + nested.B 118180--- lib/nested/a.go -- 118181-package nested 118182- 118183-const B = 1 118184--- other/other.go -- 118185-package other 118186- 118187-import ( 118188- "mod.com/lib" 118189- "mod.com/lib/nested" 118190-) 118191- 118192-const C = lib.A + nested.B 118193--- testdata/libx/a.go -- 118194-package libx 118195- 118196-import "mod.com/libx/nested" 118197- 118198-const A = 1 + nested.B 118199--- testdata/other/other.go -- 118200-package other 118201- 118202-import ( 118203- "mod.com/libx" 118204- "mod.com/libx/nested" 118205-) 118206- 118207-const C = libx.A + nested.B 118208-` 118209- Run(t, files, func(t *testing.T, env *Env) { 118210- env.OpenFile("lib/a.go") 118211- env.Rename(env.RegexpSearch("lib/a.go", "package (lib)"), "libx") 118212- 118213- checkTestdata(t, env) 118214- }) 118215-} 118216- 118217-func TestRenamePackage_InvalidName(t *testing.T) { 118218- testenv.NeedsGo1Point(t, 17) 118219- const files = ` 118220--- go.mod -- 118221-module mod.com 118222- 118223-go 1.18 118224--- lib/a.go -- 118225-package lib 118226- 118227-import "mod.com/lib/nested" 118228- 118229-const A = 1 + nested.B 118230-` 118231- 118232- Run(t, files, func(t *testing.T, env *Env) { 118233- env.OpenFile("lib/a.go") 118234- loc := env.RegexpSearch("lib/a.go", "package (lib)") 118235- 118236- for _, badName := range []string{"$$$", "lib_test"} { 118237- if err := env.Editor.Rename(env.Ctx, loc, badName); err == nil { 118238- t.Errorf("Rename(lib, libx) succeeded, want non-nil error") 118239- } 118240- } 118241- }) 118242-} 118243- 118244-func TestRenamePackage_InternalPackage(t *testing.T) { 118245- testenv.NeedsGo1Point(t, 17) 118246- const files = ` 118247--- go.mod -- 118248-module mod.com 118249- 118250-go 1.18 118251--- lib/a.go -- 118252-package lib 118253- 118254-import ( 118255- "fmt" 118256- "mod.com/lib/internal/x" 118257-) 118258- 118259-const A = 1 118260- 118261-func print() { 118262- fmt.Println(x.B) 118263-} 118264- 118265--- lib/internal/x/a.go -- 118266-package x 118267- 118268-const B = 1 118269- 118270--- main.go -- 118271-package main 118272- 118273-import "mod.com/lib" 118274- 118275-func main() { 118276- lib.print() 118277-} 118278-` 118279- Run(t, files, func(t *testing.T, env *Env) { 118280- env.OpenFile("lib/internal/x/a.go") 118281- env.Rename(env.RegexpSearch("lib/internal/x/a.go", "x"), "utils") 118282- 118283- // Check if the new package name exists. 118284- env.RegexpSearch("lib/a.go", "mod.com/lib/internal/utils") 118285- env.RegexpSearch("lib/a.go", "utils.B") 118286- 118287- // Check if the test package is renamed 118288- env.RegexpSearch("lib/internal/utils/a.go", "package utils") 118289- 118290- env.OpenFile("lib/a.go") 118291- env.Rename(env.RegexpSearch("lib/a.go", "lib"), "lib1") 118292- 118293- // Check if the new package name exists. 118294- env.RegexpSearch("lib1/a.go", "package lib1") 118295- env.RegexpSearch("lib1/a.go", "mod.com/lib1/internal/utils") 118296- env.RegexpSearch("main.go", `import "mod.com/lib1"`) 118297- env.RegexpSearch("main.go", "lib1.print()") 118298- }) 118299-} 118300- 118301-// checkTestdata checks that current buffer contents match their corresponding 118302-// expected content in the testdata directory. 118303-func checkTestdata(t *testing.T, env *Env) { 118304- t.Helper() 118305- files := env.ListFiles("testdata") 118306- if len(files) == 0 { 118307- t.Fatal("no files in testdata directory") 118308- } 118309- for _, file := range files { 118310- suffix := strings.TrimPrefix(file, "testdata/") 118311- got := env.BufferText(suffix) 118312- want := env.ReadWorkspaceFile(file) 118313- if diff := compare.Text(want, got); diff != "" { 118314- t.Errorf("Rename: unexpected buffer content for %s (-want +got):\n%s", suffix, diff) 118315- } 118316- } 118317-} 118318diff -urN a/gopls/internal/regtest/misc/semantictokens_test.go b/gopls/internal/regtest/misc/semantictokens_test.go 118319--- a/gopls/internal/regtest/misc/semantictokens_test.go 2000-01-01 00:00:00.000000000 -0000 118320+++ b/gopls/internal/regtest/misc/semantictokens_test.go 1970-01-01 00:00:00.000000000 +0000 118321@@ -1,204 +0,0 @@ 118322-// Copyright 2021 The Go Authors. All rights reserved. 118323-// Use of this source code is governed by a BSD-style 118324-// license that can be found in the LICENSE file. 118325- 118326-package misc 118327- 118328-import ( 118329- "strings" 118330- "testing" 118331- 118332- "github.com/google/go-cmp/cmp" 118333- "golang.org/x/tools/gopls/internal/lsp" 118334- "golang.org/x/tools/gopls/internal/lsp/protocol" 118335- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118336- "golang.org/x/tools/internal/typeparams" 118337-) 118338- 118339-func TestBadURICrash_VSCodeIssue1498(t *testing.T) { 118340- const src = ` 118341--- go.mod -- 118342-module example.com 118343- 118344-go 1.12 118345- 118346--- main.go -- 118347-package main 118348- 118349-func main() {} 118350- 118351-` 118352- WithOptions( 118353- Modes(Default), 118354- Settings{"allExperiments": true}, 118355- ).Run(t, src, func(t *testing.T, env *Env) { 118356- params := &protocol.SemanticTokensParams{} 118357- const badURI = "http://foo" 118358- params.TextDocument.URI = badURI 118359- // This call panicked in the past: golang/vscode-go#1498. 118360- if _, err := env.Editor.Server.SemanticTokensFull(env.Ctx, params); err != nil { 118361- // Requests to an invalid URI scheme shouldn't result in an error, we 118362- // simply don't support this so return empty result. This could be 118363- // changed, but for now assert on the current behavior. 118364- t.Errorf("SemanticTokensFull(%q): %v", badURI, err) 118365- } 118366- }) 118367-} 118368- 118369-// fix bug involving type parameters and regular parameters 118370-// (golang/vscode-go#2527) 118371-func TestSemantic_2527(t *testing.T) { 118372- if !typeparams.Enabled { 118373- t.Skip("type parameters are needed for this test") 118374- } 118375- // these are the expected types of identifiers in text order 118376- want := []result{ 118377- {"package", "keyword", ""}, 118378- {"foo", "namespace", ""}, 118379- {"func", "keyword", ""}, 118380- {"Add", "function", "definition deprecated"}, 118381- {"T", "typeParameter", "definition"}, 118382- {"int", "type", "defaultLibrary"}, 118383- {"target", "parameter", "definition"}, 118384- {"T", "typeParameter", ""}, 118385- {"l", "parameter", "definition"}, 118386- {"T", "typeParameter", ""}, 118387- {"T", "typeParameter", ""}, 118388- {"return", "keyword", ""}, 118389- {"append", "function", "defaultLibrary"}, 118390- {"l", "parameter", ""}, 118391- {"target", "parameter", ""}, 118392- {"for", "keyword", ""}, 118393- {"range", "keyword", ""}, 118394- {"l", "parameter", ""}, 118395- {"return", "keyword", ""}, 118396- {"nil", "variable", "readonly defaultLibrary"}, 118397- } 118398- src := ` 118399--- go.mod -- 118400-module example.com 118401- 118402-go 1.19 118403--- main.go -- 118404-package foo 118405-// Deprecated (for testing) 118406-func Add[T int](target T, l []T) []T { 118407- return append(l, target) 118408- for range l {} // test coverage 118409- return nil 118410-} 118411-` 118412- WithOptions( 118413- Modes(Default), 118414- Settings{"semanticTokens": true}, 118415- ).Run(t, src, func(t *testing.T, env *Env) { 118416- env.OpenFile("main.go") 118417- env.AfterChange( 118418- Diagnostics(env.AtRegexp("main.go", "for range")), 118419- ) 118420- p := &protocol.SemanticTokensParams{ 118421- TextDocument: protocol.TextDocumentIdentifier{ 118422- URI: env.Sandbox.Workdir.URI("main.go"), 118423- }, 118424- } 118425- v, err := env.Editor.Server.SemanticTokensFull(env.Ctx, p) 118426- if err != nil { 118427- t.Fatal(err) 118428- } 118429- seen := interpret(v.Data, env.BufferText("main.go")) 118430- if x := cmp.Diff(want, seen); x != "" { 118431- t.Errorf("Semantic tokens do not match (-want +got):\n%s", x) 118432- } 118433- }) 118434- 118435-} 118436- 118437-// fix inconsistency in TypeParameters 118438-// https://github.com/golang/go/issues/57619 118439-func TestSemantic_57619(t *testing.T) { 118440- if !typeparams.Enabled { 118441- t.Skip("type parameters are needed for this test") 118442- } 118443- src := ` 118444--- go.mod -- 118445-module example.com 118446- 118447-go 1.19 118448--- main.go -- 118449-package foo 118450-type Smap[K int, V any] struct { 118451- Store map[K]V 118452-} 118453-func (s *Smap[K, V]) Get(k K) (V, bool) { 118454- v, ok := s.Store[k] 118455- return v, ok 118456-} 118457-func New[K int, V any]() Smap[K, V] { 118458- return Smap[K, V]{Store: make(map[K]V)} 118459-} 118460-` 118461- WithOptions( 118462- Modes(Default), 118463- Settings{"semanticTokens": true}, 118464- ).Run(t, src, func(t *testing.T, env *Env) { 118465- env.OpenFile("main.go") 118466- p := &protocol.SemanticTokensParams{ 118467- TextDocument: protocol.TextDocumentIdentifier{ 118468- URI: env.Sandbox.Workdir.URI("main.go"), 118469- }, 118470- } 118471- v, err := env.Editor.Server.SemanticTokensFull(env.Ctx, p) 118472- if err != nil { 118473- t.Fatal(err) 118474- } 118475- seen := interpret(v.Data, env.BufferText("main.go")) 118476- for i, s := range seen { 118477- if (s.Token == "K" || s.Token == "V") && s.TokenType != "typeParameter" { 118478- t.Errorf("%d: expected K and V to be type parameters, but got %v", i, s) 118479- } 118480- } 118481- }) 118482-} 118483- 118484-type result struct { 118485- Token string 118486- TokenType string 118487- Mod string 118488-} 118489- 118490-// human-readable version of the semantic tokens 118491-// comment, string, number are elided 118492-// (and in the future, maybe elide other things, like operators) 118493-func interpret(x []uint32, contents string) []result { 118494- lines := strings.Split(contents, "\n") 118495- ans := []result{} 118496- line, col := 1, 1 118497- for i := 0; i < len(x); i += 5 { 118498- line += int(x[i]) 118499- col += int(x[i+1]) 118500- if x[i] != 0 { // new line 118501- col = int(x[i+1]) + 1 // 1-based column numbers 118502- } 118503- sz := x[i+2] 118504- t := semanticTypes[x[i+3]] 118505- if t == "comment" || t == "string" || t == "number" { 118506- continue 118507- } 118508- l := x[i+4] 118509- var mods []string 118510- for i, mod := range semanticModifiers { 118511- if l&(1<<i) != 0 { 118512- mods = append(mods, mod) 118513- } 118514- } 118515- // col is a utf-8 offset 118516- tok := lines[line-1][col-1 : col-1+int(sz)] 118517- ans = append(ans, result{tok, t, strings.Join(mods, " ")}) 118518- } 118519- return ans 118520-} 118521- 118522-var ( 118523- semanticTypes = lsp.SemanticTypes() 118524- semanticModifiers = lsp.SemanticModifiers() 118525-) 118526diff -urN a/gopls/internal/regtest/misc/settings_test.go b/gopls/internal/regtest/misc/settings_test.go 118527--- a/gopls/internal/regtest/misc/settings_test.go 2000-01-01 00:00:00.000000000 -0000 118528+++ b/gopls/internal/regtest/misc/settings_test.go 1970-01-01 00:00:00.000000000 +0000 118529@@ -1,32 +0,0 @@ 118530-// Copyright 2022 The Go Authors. All rights reserved. 118531-// Use of this source code is governed by a BSD-style 118532-// license that can be found in the LICENSE file. 118533- 118534-package misc 118535- 118536-import ( 118537- "testing" 118538- 118539- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118540-) 118541- 118542-func TestEmptyDirectoryFilters_Issue51843(t *testing.T) { 118543- const src = ` 118544--- go.mod -- 118545-module mod.com 118546- 118547-go 1.12 118548--- main.go -- 118549-package main 118550- 118551-func main() { 118552-} 118553-` 118554- 118555- WithOptions( 118556- Settings{"directoryFilters": []string{""}}, 118557- ).Run(t, src, func(t *testing.T, env *Env) { 118558- // No need to do anything. Issue golang/go#51843 is triggered by the empty 118559- // directory filter above. 118560- }) 118561-} 118562diff -urN a/gopls/internal/regtest/misc/shared_test.go b/gopls/internal/regtest/misc/shared_test.go 118563--- a/gopls/internal/regtest/misc/shared_test.go 2000-01-01 00:00:00.000000000 -0000 118564+++ b/gopls/internal/regtest/misc/shared_test.go 1970-01-01 00:00:00.000000000 +0000 118565@@ -1,72 +0,0 @@ 118566-// Copyright 2020 The Go Authors. All rights reserved. 118567-// Use of this source code is governed by a BSD-style 118568-// license that can be found in the LICENSE file. 118569- 118570-package misc 118571- 118572-import ( 118573- "testing" 118574- 118575- "golang.org/x/tools/gopls/internal/lsp/fake" 118576- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118577-) 118578- 118579-// Smoke test that simultaneous editing sessions in the same workspace works. 118580-func TestSimultaneousEdits(t *testing.T) { 118581- const sharedProgram = ` 118582--- go.mod -- 118583-module mod 118584- 118585-go 1.12 118586--- main.go -- 118587-package main 118588- 118589-import "fmt" 118590- 118591-func main() { 118592- fmt.Println("Hello World.") 118593-}` 118594- 118595- WithOptions( 118596- Modes(DefaultModes()&(Forwarded|SeparateProcess)), 118597- ).Run(t, sharedProgram, func(t *testing.T, env1 *Env) { 118598- // Create a second test session connected to the same workspace and server 118599- // as the first. 118600- awaiter := NewAwaiter(env1.Sandbox.Workdir) 118601- const skipApplyEdits = false 118602- editor, err := fake.NewEditor(env1.Sandbox, env1.Editor.Config()).Connect(env1.Ctx, env1.Server, awaiter.Hooks(), skipApplyEdits) 118603- if err != nil { 118604- t.Fatal(err) 118605- } 118606- env2 := &Env{ 118607- T: t, 118608- Ctx: env1.Ctx, 118609- Sandbox: env1.Sandbox, 118610- Server: env1.Server, 118611- Editor: editor, 118612- Awaiter: awaiter, 118613- } 118614- env2.Await(InitialWorkspaceLoad) 118615- // In editor #1, break fmt.Println as before. 118616- env1.OpenFile("main.go") 118617- env1.RegexpReplace("main.go", "Printl(n)", "") 118618- // In editor #2 remove the closing brace. 118619- env2.OpenFile("main.go") 118620- env2.RegexpReplace("main.go", "\\)\n(})", "") 118621- 118622- // Now check that we got different diagnostics in each environment. 118623- env1.AfterChange(Diagnostics(env1.AtRegexp("main.go", "Printl"))) 118624- env2.AfterChange(Diagnostics(env2.AtRegexp("main.go", "$"))) 118625- 118626- // Now close editor #2, and verify that operation in editor #1 is 118627- // unaffected. 118628- if err := env2.Editor.Close(env2.Ctx); err != nil { 118629- t.Errorf("closing second editor: %v", err) 118630- } 118631- 118632- env1.RegexpReplace("main.go", "Printl", "Println") 118633- env1.AfterChange( 118634- NoDiagnostics(ForFile("main.go")), 118635- ) 118636- }) 118637-} 118638diff -urN a/gopls/internal/regtest/misc/signature_help_test.go b/gopls/internal/regtest/misc/signature_help_test.go 118639--- a/gopls/internal/regtest/misc/signature_help_test.go 2000-01-01 00:00:00.000000000 -0000 118640+++ b/gopls/internal/regtest/misc/signature_help_test.go 1970-01-01 00:00:00.000000000 +0000 118641@@ -1,69 +0,0 @@ 118642-// Copyright 2023 The Go Authors. All rights reserved. 118643-// Use of this source code is governed by a BSD-style 118644-// license that can be found in the LICENSE file. 118645- 118646-package misc 118647- 118648-import ( 118649- "testing" 118650- 118651- "github.com/google/go-cmp/cmp" 118652- "golang.org/x/tools/gopls/internal/lsp/protocol" 118653- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118654-) 118655- 118656-func TestSignatureHelpInNonWorkspacePackage(t *testing.T) { 118657- const files = ` 118658--- a/go.mod -- 118659-module a.com 118660- 118661-go 1.18 118662--- a/a/a.go -- 118663-package a 118664- 118665-func DoSomething(int) {} 118666- 118667-func _() { 118668- DoSomething() 118669-} 118670--- b/go.mod -- 118671-module b.com 118672-go 1.18 118673- 118674-require a.com v1.0.0 118675- 118676-replace a.com => ../a 118677--- b/b/b.go -- 118678-package b 118679- 118680-import "a.com/a" 118681- 118682-func _() { 118683- a.DoSomething() 118684-} 118685-` 118686- 118687- WithOptions( 118688- WorkspaceFolders("a"), 118689- ).Run(t, files, func(t *testing.T, env *Env) { 118690- env.OpenFile("a/a/a.go") 118691- env.OpenFile("b/b/b.go") 118692- signatureHelp := func(filename string) *protocol.SignatureHelp { 118693- loc := env.RegexpSearch(filename, `DoSomething\(()\)`) 118694- var params protocol.SignatureHelpParams 118695- params.TextDocument.URI = loc.URI 118696- params.Position = loc.Range.Start 118697- help, err := env.Editor.Server.SignatureHelp(env.Ctx, ¶ms) 118698- if err != nil { 118699- t.Fatal(err) 118700- } 118701- return help 118702- } 118703- ahelp := signatureHelp("a/a/a.go") 118704- bhelp := signatureHelp("b/b/b.go") 118705- 118706- if diff := cmp.Diff(ahelp, bhelp); diff != "" { 118707- t.Fatal(diff) 118708- } 118709- }) 118710-} 118711diff -urN a/gopls/internal/regtest/misc/staticcheck_test.go b/gopls/internal/regtest/misc/staticcheck_test.go 118712--- a/gopls/internal/regtest/misc/staticcheck_test.go 2000-01-01 00:00:00.000000000 -0000 118713+++ b/gopls/internal/regtest/misc/staticcheck_test.go 1970-01-01 00:00:00.000000000 +0000 118714@@ -1,110 +0,0 @@ 118715-// Copyright 2022 The Go Authors. All rights reserved. 118716-// Use of this source code is governed by a BSD-style 118717-// license that can be found in the LICENSE file. 118718- 118719-package misc 118720- 118721-import ( 118722- "testing" 118723- 118724- "golang.org/x/tools/internal/testenv" 118725- 118726- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118727-) 118728- 118729-func TestStaticcheckGenerics(t *testing.T) { 118730- testenv.NeedsGo1Point(t, 19) // generics were introduced in Go 1.18, staticcheck requires go1.19+ 118731- 118732- const files = ` 118733--- go.mod -- 118734-module mod.com 118735- 118736-go 1.18 118737--- a/a.go -- 118738-package a 118739- 118740-import ( 118741- "errors" 118742- "sort" 118743- "strings" 118744-) 118745- 118746-func Zero[P any]() P { 118747- var p P 118748- return p 118749-} 118750- 118751-type Inst[P any] struct { 118752- Field P 118753-} 118754- 118755-func testGenerics[P *T, T any](p P) { 118756- // Calls to instantiated functions should not break checks. 118757- slice := Zero[string]() 118758- sort.Slice(slice, func(i, j int) bool { 118759- return slice[i] < slice[j] 118760- }) 118761- 118762- // Usage of instantiated fields should not break checks. 118763- g := Inst[string]{"hello"} 118764- g.Field = strings.TrimLeft(g.Field, "12234") 118765- 118766- // Use of type parameters should not break checks. 118767- var q P 118768- p = q // SA4009: p is overwritten before its first use 118769- q = &*p // SA4001: &* will be simplified 118770-} 118771- 118772- 118773-// FooErr should be called ErrFoo (ST1012) 118774-var FooErr error = errors.New("foo") 118775-` 118776- 118777- WithOptions( 118778- Settings{"staticcheck": true}, 118779- ).Run(t, files, func(t *testing.T, env *Env) { 118780- env.OpenFile("a/a.go") 118781- env.AfterChange( 118782- Diagnostics(env.AtRegexp("a/a.go", "sort.Slice"), FromSource("sortslice")), 118783- Diagnostics(env.AtRegexp("a/a.go", "sort.Slice.(slice)"), FromSource("SA1028")), 118784- Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)"), FromSource("ST1012")), 118785- Diagnostics(env.AtRegexp("a/a.go", `"12234"`), FromSource("SA1024")), 118786- Diagnostics(env.AtRegexp("a/a.go", "testGenerics.*(p P)"), FromSource("SA4009")), 118787- Diagnostics(env.AtRegexp("a/a.go", "q = (&\\*p)"), FromSource("SA4001")), 118788- ) 118789- }) 118790-} 118791- 118792-// Test for golang/go#56270: an analysis with related info should not panic if 118793-// analysis.RelatedInformation.End is not set. 118794-func TestStaticcheckRelatedInfo(t *testing.T) { 118795- testenv.NeedsGo1Point(t, 19) // staticcheck is only supported at Go 1.19+ 118796- const files = ` 118797--- go.mod -- 118798-module mod.test 118799- 118800-go 1.18 118801--- p.go -- 118802-package p 118803- 118804-import ( 118805- "fmt" 118806-) 118807- 118808-func Foo(enabled interface{}) { 118809- if enabled, ok := enabled.(bool); ok { 118810- } else { 118811- _ = fmt.Sprintf("invalid type %T", enabled) // enabled is always bool here 118812- } 118813-} 118814-` 118815- 118816- WithOptions( 118817- Settings{"staticcheck": true}, 118818- ).Run(t, files, func(t *testing.T, env *Env) { 118819- env.OpenFile("p.go") 118820- env.AfterChange( 118821- Diagnostics(env.AtRegexp("p.go", ", (enabled)"), FromSource("SA9008")), 118822- ) 118823- }) 118824-} 118825diff -urN a/gopls/internal/regtest/misc/vendor_test.go b/gopls/internal/regtest/misc/vendor_test.go 118826--- a/gopls/internal/regtest/misc/vendor_test.go 2000-01-01 00:00:00.000000000 -0000 118827+++ b/gopls/internal/regtest/misc/vendor_test.go 1970-01-01 00:00:00.000000000 +0000 118828@@ -1,65 +0,0 @@ 118829-// Copyright 2020 The Go Authors. All rights reserved. 118830-// Use of this source code is governed by a BSD-style 118831-// license that can be found in the LICENSE file. 118832- 118833-package misc 118834- 118835-import ( 118836- "testing" 118837- 118838- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118839- 118840- "golang.org/x/tools/gopls/internal/lsp/protocol" 118841-) 118842- 118843-const basicProxy = ` 118844--- golang.org/x/hello@v1.2.3/go.mod -- 118845-module golang.org/x/hello 118846- 118847-go 1.14 118848--- golang.org/x/hello@v1.2.3/hi/hi.go -- 118849-package hi 118850- 118851-var Goodbye error 118852-` 118853- 118854-func TestInconsistentVendoring(t *testing.T) { 118855- const pkgThatUsesVendoring = ` 118856--- go.mod -- 118857-module mod.com 118858- 118859-go 1.14 118860- 118861-require golang.org/x/hello v1.2.3 118862--- go.sum -- 118863-golang.org/x/hello v1.2.3 h1:EcMp5gSkIhaTkPXp8/3+VH+IFqTpk3ZbpOhqk0Ncmho= 118864-golang.org/x/hello v1.2.3/go.mod h1:WW7ER2MRNXWA6c8/4bDIek4Hc/+DofTrMaQQitGXcco= 118865--- vendor/modules.txt -- 118866--- a/a1.go -- 118867-package a 118868- 118869-import "golang.org/x/hello/hi" 118870- 118871-func _() { 118872- _ = hi.Goodbye 118873- var q int // hardcode a diagnostic 118874-} 118875-` 118876- WithOptions( 118877- Modes(Default), 118878- ProxyFiles(basicProxy), 118879- ).Run(t, pkgThatUsesVendoring, func(t *testing.T, env *Env) { 118880- env.OpenFile("a/a1.go") 118881- d := &protocol.PublishDiagnosticsParams{} 118882- env.OnceMet( 118883- InitialWorkspaceLoad, 118884- Diagnostics(env.AtRegexp("go.mod", "module mod.com"), WithMessage("Inconsistent vendoring")), 118885- ReadDiagnostics("go.mod", d), 118886- ) 118887- env.ApplyQuickFixes("go.mod", d.Diagnostics) 118888- 118889- env.AfterChange( 118890- Diagnostics(env.AtRegexp("a/a1.go", `q int`), WithMessage("not used")), 118891- ) 118892- }) 118893-} 118894diff -urN a/gopls/internal/regtest/misc/vuln_test.go b/gopls/internal/regtest/misc/vuln_test.go 118895--- a/gopls/internal/regtest/misc/vuln_test.go 2000-01-01 00:00:00.000000000 -0000 118896+++ b/gopls/internal/regtest/misc/vuln_test.go 1970-01-01 00:00:00.000000000 +0000 118897@@ -1,977 +0,0 @@ 118898-// Copyright 2022 The Go Authors. All rights reserved. 118899-// Use of this source code is governed by a BSD-style 118900-// license that can be found in the LICENSE file. 118901- 118902-//go:build go1.18 118903-// +build go1.18 118904- 118905-package misc 118906- 118907-import ( 118908- "context" 118909- "encoding/json" 118910- "path/filepath" 118911- "sort" 118912- "strings" 118913- "testing" 118914- 118915- "github.com/google/go-cmp/cmp" 118916- "golang.org/x/tools/gopls/internal/govulncheck" 118917- "golang.org/x/tools/gopls/internal/lsp/command" 118918- "golang.org/x/tools/gopls/internal/lsp/protocol" 118919- . "golang.org/x/tools/gopls/internal/lsp/regtest" 118920- "golang.org/x/tools/gopls/internal/lsp/source" 118921- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 118922- "golang.org/x/tools/gopls/internal/vulncheck" 118923- "golang.org/x/tools/gopls/internal/vulncheck/vulntest" 118924- "golang.org/x/tools/internal/testenv" 118925-) 118926- 118927-func TestRunGovulncheckError(t *testing.T) { 118928- const files = ` 118929--- go.mod -- 118930-module mod.com 118931- 118932-go 1.12 118933--- foo.go -- 118934-package foo 118935-` 118936- Run(t, files, func(t *testing.T, env *Env) { 118937- cmd, err := command.NewRunGovulncheckCommand("Run Vulncheck Exp", command.VulncheckArgs{ 118938- URI: "/invalid/file/url", // invalid arg 118939- }) 118940- if err != nil { 118941- t.Fatal(err) 118942- } 118943- 118944- params := &protocol.ExecuteCommandParams{ 118945- Command: command.RunGovulncheck.ID(), 118946- Arguments: cmd.Arguments, 118947- } 118948- 118949- response, err := env.Editor.ExecuteCommand(env.Ctx, params) 118950- // We want an error! 118951- if err == nil { 118952- t.Errorf("got success, want invalid file URL error: %v", response) 118953- } 118954- }) 118955-} 118956- 118957-func TestRunGovulncheckError2(t *testing.T) { 118958- const files = ` 118959--- go.mod -- 118960-module mod.com 118961- 118962-go 1.12 118963--- foo.go -- 118964-package foo 118965- 118966-func F() { // build error incomplete 118967-` 118968- WithOptions( 118969- EnvVars{ 118970- "_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`. 118971- }, 118972- Settings{ 118973- "codelenses": map[string]bool{ 118974- "run_govulncheck": true, 118975- }, 118976- }, 118977- ).Run(t, files, func(t *testing.T, env *Env) { 118978- env.OpenFile("go.mod") 118979- var result command.RunVulncheckResult 118980- env.ExecuteCodeLensCommand("go.mod", command.RunGovulncheck, &result) 118981- var ws WorkStatus 118982- env.Await( 118983- CompletedProgress(result.Token, &ws), 118984- ) 118985- wantEndMsg, wantMsgPart := "failed", "failed to load packages due to errors" 118986- if ws.EndMsg != "failed" || !strings.Contains(ws.Msg, wantMsgPart) { 118987- t.Errorf("work status = %+v, want {EndMessage: %q, Message: %q}", ws, wantEndMsg, wantMsgPart) 118988- } 118989- }) 118990-} 118991- 118992-const vulnsData = ` 118993--- GO-2022-01.yaml -- 118994-modules: 118995- - module: golang.org/amod 118996- versions: 118997- - introduced: 1.0.0 118998- - fixed: 1.0.4 118999- - introduced: 1.1.2 119000- packages: 119001- - package: golang.org/amod/avuln 119002- symbols: 119003- - VulnData.Vuln1 119004- - VulnData.Vuln2 119005-description: > 119006- vuln in amod 119007-references: 119008- - href: pkg.go.dev/vuln/GO-2022-01 119009--- GO-2022-03.yaml -- 119010-modules: 119011- - module: golang.org/amod 119012- versions: 119013- - introduced: 1.0.0 119014- - fixed: 1.0.6 119015- packages: 119016- - package: golang.org/amod/avuln 119017- symbols: 119018- - nonExisting 119019-description: > 119020- unaffecting vulnerability 119021--- GO-2022-02.yaml -- 119022-modules: 119023- - module: golang.org/bmod 119024- packages: 119025- - package: golang.org/bmod/bvuln 119026- symbols: 119027- - Vuln 119028-description: | 119029- vuln in bmod 119030- 119031- This is a long description 119032- of this vulnerability. 119033-references: 119034- - href: pkg.go.dev/vuln/GO-2022-03 119035--- GO-2022-04.yaml -- 119036-modules: 119037- - module: golang.org/bmod 119038- packages: 119039- - package: golang.org/bmod/unused 119040- symbols: 119041- - Vuln 119042-description: | 119043- vuln in bmod/somtrhingelse 119044-references: 119045- - href: pkg.go.dev/vuln/GO-2022-04 119046--- GOSTDLIB.yaml -- 119047-modules: 119048- - module: stdlib 119049- versions: 119050- - introduced: 1.18.0 119051- packages: 119052- - package: archive/zip 119053- symbols: 119054- - OpenReader 119055-references: 119056- - href: pkg.go.dev/vuln/GOSTDLIB 119057-` 119058- 119059-func TestRunGovulncheckStd(t *testing.T) { 119060- testenv.NeedsGo1Point(t, 18) 119061- const files = ` 119062--- go.mod -- 119063-module mod.com 119064- 119065-go 1.18 119066--- main.go -- 119067-package main 119068- 119069-import ( 119070- "archive/zip" 119071- "fmt" 119072-) 119073- 119074-func main() { 119075- _, err := zip.OpenReader("file.zip") // vulnerability id: GOSTDLIB 119076- fmt.Println(err) 119077-} 119078-` 119079- 119080- db, err := vulntest.NewDatabase(context.Background(), []byte(vulnsData)) 119081- if err != nil { 119082- t.Fatal(err) 119083- } 119084- defer db.Clean() 119085- WithOptions( 119086- EnvVars{ 119087- // Let the analyzer read vulnerabilities data from the testdata/vulndb. 119088- "GOVULNDB": db.URI(), 119089- // When fetchinging stdlib package vulnerability info, 119090- // behave as if our go version is go1.18 for this testing. 119091- // The default behavior is to run `go env GOVERSION` (which isn't mutable env var). 119092- vulncheck.GoVersionForVulnTest: "go1.18", 119093- "_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`. 119094- }, 119095- Settings{ 119096- "codelenses": map[string]bool{ 119097- "run_govulncheck": true, 119098- }, 119099- }, 119100- ).Run(t, files, func(t *testing.T, env *Env) { 119101- env.OpenFile("go.mod") 119102- 119103- // Test CodeLens is present. 119104- lenses := env.CodeLens("go.mod") 119105- 119106- const wantCommand = "gopls." + string(command.RunGovulncheck) 119107- var gotCodelens = false 119108- var lens protocol.CodeLens 119109- for _, l := range lenses { 119110- if l.Command.Command == wantCommand { 119111- gotCodelens = true 119112- lens = l 119113- break 119114- } 119115- } 119116- if !gotCodelens { 119117- t.Fatal("got no vulncheck codelens") 119118- } 119119- // Run Command included in the codelens. 119120- var result command.RunVulncheckResult 119121- env.ExecuteCommand(&protocol.ExecuteCommandParams{ 119122- Command: lens.Command.Command, 119123- Arguments: lens.Command.Arguments, 119124- }, &result) 119125- 119126- env.OnceMet( 119127- CompletedProgress(result.Token, nil), 119128- ShownMessage("Found GOSTDLIB"), 119129- NoDiagnostics(ForFile("go.mod")), 119130- ) 119131- testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{ 119132- "go.mod": {IDs: []string{"GOSTDLIB"}, Mode: govulncheck.ModeGovulncheck}}) 119133- }) 119134-} 119135- 119136-func TestFetchVulncheckResultStd(t *testing.T) { 119137- testenv.NeedsGo1Point(t, 18) 119138- const files = ` 119139--- go.mod -- 119140-module mod.com 119141- 119142-go 1.18 119143--- main.go -- 119144-package main 119145- 119146-import ( 119147- "archive/zip" 119148- "fmt" 119149-) 119150- 119151-func main() { 119152- _, err := zip.OpenReader("file.zip") // vulnerability id: GOSTDLIB 119153- fmt.Println(err) 119154-} 119155-` 119156- 119157- db, err := vulntest.NewDatabase(context.Background(), []byte(vulnsData)) 119158- if err != nil { 119159- t.Fatal(err) 119160- } 119161- defer db.Clean() 119162- WithOptions( 119163- EnvVars{ 119164- // Let the analyzer read vulnerabilities data from the testdata/vulndb. 119165- "GOVULNDB": db.URI(), 119166- // When fetchinging stdlib package vulnerability info, 119167- // behave as if our go version is go1.18 for this testing. 119168- vulncheck.GoVersionForVulnTest: "go1.18", 119169- "_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`. 119170- }, 119171- Settings{"ui.diagnostic.vulncheck": "Imports"}, 119172- ).Run(t, files, func(t *testing.T, env *Env) { 119173- env.OpenFile("go.mod") 119174- env.AfterChange( 119175- NoDiagnostics(ForFile("go.mod")), 119176- // we don't publish diagnostics for standard library vulnerability yet. 119177- ) 119178- testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{ 119179- "go.mod": { 119180- IDs: []string{"GOSTDLIB"}, 119181- Mode: govulncheck.ModeImports, 119182- }, 119183- }) 119184- }) 119185-} 119186- 119187-type fetchVulncheckResult struct { 119188- IDs []string 119189- Mode govulncheck.AnalysisMode 119190-} 119191- 119192-func testFetchVulncheckResult(t *testing.T, env *Env, want map[string]fetchVulncheckResult) { 119193- t.Helper() 119194- 119195- var result map[protocol.DocumentURI]*govulncheck.Result 119196- fetchCmd, err := command.NewFetchVulncheckResultCommand("fetch", command.URIArg{ 119197- URI: env.Sandbox.Workdir.URI("go.mod"), 119198- }) 119199- if err != nil { 119200- t.Fatal(err) 119201- } 119202- env.ExecuteCommand(&protocol.ExecuteCommandParams{ 119203- Command: fetchCmd.Command, 119204- Arguments: fetchCmd.Arguments, 119205- }, &result) 119206- 119207- for _, v := range want { 119208- sort.Strings(v.IDs) 119209- } 119210- got := map[string]fetchVulncheckResult{} 119211- for k, r := range result { 119212- var osv []string 119213- for _, v := range r.Vulns { 119214- osv = append(osv, v.OSV.ID) 119215- } 119216- sort.Strings(osv) 119217- modfile := env.Sandbox.Workdir.RelPath(k.SpanURI().Filename()) 119218- got[modfile] = fetchVulncheckResult{ 119219- IDs: osv, 119220- Mode: r.Mode, 119221- } 119222- } 119223- if diff := cmp.Diff(want, got); diff != "" { 119224- t.Errorf("fetch vulnchheck result = got %v, want %v: diff %v", got, want, diff) 119225- } 119226-} 119227- 119228-const workspace1 = ` 119229--- go.mod -- 119230-module golang.org/entry 119231- 119232-go 1.18 119233- 119234-require golang.org/cmod v1.1.3 119235- 119236-require ( 119237- golang.org/amod v1.0.0 // indirect 119238- golang.org/bmod v0.5.0 // indirect 119239-) 119240--- go.sum -- 119241-golang.org/amod v1.0.0 h1:EUQOI2m5NhQZijXZf8WimSnnWubaFNrrKUH/PopTN8k= 119242-golang.org/amod v1.0.0/go.mod h1:yvny5/2OtYFomKt8ax+WJGvN6pfN1pqjGnn7DQLUi6E= 119243-golang.org/bmod v0.5.0 h1:KgvUulMyMiYRB7suKA0x+DfWRVdeyPgVJvcishTH+ng= 119244-golang.org/bmod v0.5.0/go.mod h1:f6o+OhF66nz/0BBc/sbCsshyPRKMSxZIlG50B/bsM4c= 119245-golang.org/cmod v1.1.3 h1:PJ7rZFTk7xGAunBRDa0wDe7rZjZ9R/vr1S2QkVVCngQ= 119246-golang.org/cmod v1.1.3/go.mod h1:eCR8dnmvLYQomdeAZRCPgS5JJihXtqOQrpEkNj5feQA= 119247--- x/x.go -- 119248-package x 119249- 119250-import ( 119251- "golang.org/cmod/c" 119252- "golang.org/entry/y" 119253-) 119254- 119255-func X() { 119256- c.C1().Vuln1() // vuln use: X -> Vuln1 119257-} 119258- 119259-func CallY() { 119260- y.Y() // vuln use: CallY -> y.Y -> bvuln.Vuln 119261-} 119262- 119263--- y/y.go -- 119264-package y 119265- 119266-import "golang.org/cmod/c" 119267- 119268-func Y() { 119269- c.C2()() // vuln use: Y -> bvuln.Vuln 119270-} 119271-` 119272- 119273-// cmod/c imports amod/avuln and bmod/bvuln. 119274-const proxy1 = ` 119275--- golang.org/cmod@v1.1.3/go.mod -- 119276-module golang.org/cmod 119277- 119278-go 1.12 119279--- golang.org/cmod@v1.1.3/c/c.go -- 119280-package c 119281- 119282-import ( 119283- "golang.org/amod/avuln" 119284- "golang.org/bmod/bvuln" 119285-) 119286- 119287-type I interface { 119288- Vuln1() 119289-} 119290- 119291-func C1() I { 119292- v := avuln.VulnData{} 119293- v.Vuln2() // vuln use 119294- return v 119295-} 119296- 119297-func C2() func() { 119298- return bvuln.Vuln 119299-} 119300--- golang.org/amod@v1.0.0/go.mod -- 119301-module golang.org/amod 119302- 119303-go 1.14 119304--- golang.org/amod@v1.0.0/avuln/avuln.go -- 119305-package avuln 119306- 119307-type VulnData struct {} 119308-func (v VulnData) Vuln1() {} 119309-func (v VulnData) Vuln2() {} 119310--- golang.org/amod@v1.0.4/go.mod -- 119311-module golang.org/amod 119312- 119313-go 1.14 119314--- golang.org/amod@v1.0.4/avuln/avuln.go -- 119315-package avuln 119316- 119317-type VulnData struct {} 119318-func (v VulnData) Vuln1() {} 119319-func (v VulnData) Vuln2() {} 119320- 119321--- golang.org/bmod@v0.5.0/go.mod -- 119322-module golang.org/bmod 119323- 119324-go 1.14 119325--- golang.org/bmod@v0.5.0/bvuln/bvuln.go -- 119326-package bvuln 119327- 119328-func Vuln() { 119329- // something evil 119330-} 119331--- golang.org/bmod@v0.5.0/unused/unused.go -- 119332-package unused 119333- 119334-func Vuln() { 119335- // something evil 119336-} 119337--- golang.org/amod@v1.0.6/go.mod -- 119338-module golang.org/amod 119339- 119340-go 1.14 119341--- golang.org/amod@v1.0.6/avuln/avuln.go -- 119342-package avuln 119343- 119344-type VulnData struct {} 119345-func (v VulnData) Vuln1() {} 119346-func (v VulnData) Vuln2() {} 119347-` 119348- 119349-func vulnTestEnv(vulnsDB, proxyData string) (*vulntest.DB, []RunOption, error) { 119350- db, err := vulntest.NewDatabase(context.Background(), []byte(vulnsData)) 119351- if err != nil { 119352- return nil, nil, nil 119353- } 119354- settings := Settings{ 119355- "codelenses": map[string]bool{ 119356- "run_govulncheck": true, 119357- }, 119358- } 119359- ev := EnvVars{ 119360- // Let the analyzer read vulnerabilities data from the testdata/vulndb. 119361- "GOVULNDB": db.URI(), 119362- // When fetching stdlib package vulnerability info, 119363- // behave as if our go version is go1.18 for this testing. 119364- // The default behavior is to run `go env GOVERSION` (which isn't mutable env var). 119365- vulncheck.GoVersionForVulnTest: "go1.18", 119366- "_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`. 119367- "GOSUMDB": "off", 119368- } 119369- return db, []RunOption{ProxyFiles(proxyData), ev, settings}, nil 119370-} 119371- 119372-func TestRunVulncheckPackageDiagnostics(t *testing.T) { 119373- testenv.NeedsGo1Point(t, 18) 119374- 119375- db, opts0, err := vulnTestEnv(vulnsData, proxy1) 119376- if err != nil { 119377- t.Fatal(err) 119378- } 119379- defer db.Clean() 119380- 119381- checkVulncheckDiagnostics := func(env *Env, t *testing.T) { 119382- env.OpenFile("go.mod") 119383- 119384- gotDiagnostics := &protocol.PublishDiagnosticsParams{} 119385- env.AfterChange( 119386- Diagnostics(env.AtRegexp("go.mod", `golang.org/amod`)), 119387- ReadDiagnostics("go.mod", gotDiagnostics), 119388- ) 119389- 119390- testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{ 119391- "go.mod": { 119392- IDs: []string{"GO-2022-01", "GO-2022-02", "GO-2022-03"}, 119393- Mode: govulncheck.ModeImports, 119394- }, 119395- }) 119396- 119397- wantVulncheckDiagnostics := map[string]vulnDiagExpectation{ 119398- "golang.org/amod": { 119399- diagnostics: []vulnDiag{ 119400- { 119401- msg: "golang.org/amod has known vulnerabilities GO-2022-01, GO-2022-03.", 119402- severity: protocol.SeverityInformation, 119403- source: string(source.Vulncheck), 119404- codeActions: []string{ 119405- "Run govulncheck to verify", 119406- "Upgrade to v1.0.6", 119407- "Upgrade to latest", 119408- }, 119409- }, 119410- }, 119411- codeActions: []string{ 119412- "Run govulncheck to verify", 119413- "Upgrade to v1.0.6", 119414- "Upgrade to latest", 119415- }, 119416- hover: []string{"GO-2022-01", "Fixed in v1.0.4.", "GO-2022-03"}, 119417- }, 119418- "golang.org/bmod": { 119419- diagnostics: []vulnDiag{ 119420- { 119421- msg: "golang.org/bmod has a vulnerability GO-2022-02.", 119422- severity: protocol.SeverityInformation, 119423- source: string(source.Vulncheck), 119424- codeActions: []string{ 119425- "Run govulncheck to verify", 119426- }, 119427- }, 119428- }, 119429- codeActions: []string{ 119430- "Run govulncheck to verify", 119431- }, 119432- hover: []string{"GO-2022-02", "This is a long description of this vulnerability.", "No fix is available."}, 119433- }, 119434- } 119435- 119436- for pattern, want := range wantVulncheckDiagnostics { 119437- modPathDiagnostics := testVulnDiagnostics(t, env, pattern, want, gotDiagnostics) 119438- 119439- gotActions := env.CodeAction("go.mod", modPathDiagnostics) 119440- if diff := diffCodeActions(gotActions, want.codeActions); diff != "" { 119441- t.Errorf("code actions for %q do not match, got %v, want %v\n%v\n", pattern, gotActions, want.codeActions, diff) 119442- continue 119443- } 119444- } 119445- } 119446- 119447- wantNoVulncheckDiagnostics := func(env *Env, t *testing.T) { 119448- env.OpenFile("go.mod") 119449- 119450- gotDiagnostics := &protocol.PublishDiagnosticsParams{} 119451- env.AfterChange( 119452- ReadDiagnostics("go.mod", gotDiagnostics), 119453- ) 119454- 119455- if len(gotDiagnostics.Diagnostics) > 0 { 119456- t.Errorf("Unexpected diagnostics: %v", stringify(gotDiagnostics)) 119457- } 119458- testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{}) 119459- } 119460- 119461- for _, tc := range []struct { 119462- name string 119463- setting Settings 119464- wantDiagnostics bool 119465- }{ 119466- {"imports", Settings{"ui.diagnostic.vulncheck": "Imports"}, true}, 119467- {"default", Settings{}, false}, 119468- {"invalid", Settings{"ui.diagnostic.vulncheck": "invalid"}, false}, 119469- } { 119470- t.Run(tc.name, func(t *testing.T) { 119471- // override the settings options to enable diagnostics 119472- opts := append(opts0, tc.setting) 119473- WithOptions(opts...).Run(t, workspace1, func(t *testing.T, env *Env) { 119474- // TODO(hyangah): implement it, so we see GO-2022-01, GO-2022-02, and GO-2022-03. 119475- // Check that the actions we get when including all diagnostics at a location return the same result 119476- if tc.wantDiagnostics { 119477- checkVulncheckDiagnostics(env, t) 119478- } else { 119479- wantNoVulncheckDiagnostics(env, t) 119480- } 119481- 119482- if tc.name == "imports" && tc.wantDiagnostics { 119483- // test we get only govulncheck-based diagnostics after "run govulncheck". 119484- var result command.RunVulncheckResult 119485- env.ExecuteCodeLensCommand("go.mod", command.RunGovulncheck, &result) 119486- gotDiagnostics := &protocol.PublishDiagnosticsParams{} 119487- env.OnceMet( 119488- CompletedProgress(result.Token, nil), 119489- ShownMessage("Found"), 119490- ) 119491- env.OnceMet( 119492- Diagnostics(env.AtRegexp("go.mod", "golang.org/bmod")), 119493- ReadDiagnostics("go.mod", gotDiagnostics), 119494- ) 119495- // We expect only one diagnostic for GO-2022-02. 119496- count := 0 119497- for _, diag := range gotDiagnostics.Diagnostics { 119498- if strings.Contains(diag.Message, "GO-2022-02") { 119499- count++ 119500- if got, want := diag.Severity, protocol.SeverityWarning; got != want { 119501- t.Errorf("Diagnostic for GO-2022-02 = %v, want %v", got, want) 119502- } 119503- } 119504- } 119505- if count != 1 { 119506- t.Errorf("Unexpected number of diagnostics about GO-2022-02 = %v, want 1:\n%+v", count, stringify(gotDiagnostics)) 119507- } 119508- } 119509- }) 119510- }) 119511- } 119512-} 119513- 119514-func stringify(a interface{}) string { 119515- data, _ := json.Marshal(a) 119516- return string(data) 119517-} 119518- 119519-func TestRunVulncheckWarning(t *testing.T) { 119520- testenv.NeedsGo1Point(t, 18) 119521- 119522- db, opts, err := vulnTestEnv(vulnsData, proxy1) 119523- if err != nil { 119524- t.Fatal(err) 119525- } 119526- defer db.Clean() 119527- WithOptions(opts...).Run(t, workspace1, func(t *testing.T, env *Env) { 119528- env.OpenFile("go.mod") 119529- 119530- var result command.RunVulncheckResult 119531- env.ExecuteCodeLensCommand("go.mod", command.RunGovulncheck, &result) 119532- gotDiagnostics := &protocol.PublishDiagnosticsParams{} 119533- env.OnceMet( 119534- CompletedProgress(result.Token, nil), 119535- ShownMessage("Found"), 119536- ) 119537- // Vulncheck diagnostics asynchronous to the vulncheck command. 119538- env.OnceMet( 119539- Diagnostics(env.AtRegexp("go.mod", `golang.org/amod`)), 119540- ReadDiagnostics("go.mod", gotDiagnostics), 119541- ) 119542- 119543- testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{ 119544- "go.mod": {IDs: []string{"GO-2022-01", "GO-2022-02", "GO-2022-03"}, Mode: govulncheck.ModeGovulncheck}, 119545- }) 119546- env.OpenFile("x/x.go") 119547- lineX := env.RegexpSearch("x/x.go", `c\.C1\(\)\.Vuln1\(\)`).Range.Start 119548- env.OpenFile("y/y.go") 119549- lineY := env.RegexpSearch("y/y.go", `c\.C2\(\)\(\)`).Range.Start 119550- wantDiagnostics := map[string]vulnDiagExpectation{ 119551- "golang.org/amod": { 119552- applyAction: "Upgrade to v1.0.6", 119553- diagnostics: []vulnDiag{ 119554- { 119555- msg: "golang.org/amod has a vulnerability used in the code: GO-2022-01.", 119556- severity: protocol.SeverityWarning, 119557- source: string(source.Govulncheck), 119558- codeActions: []string{ 119559- "Upgrade to v1.0.4", 119560- "Upgrade to latest", 119561- "Reset govulncheck result", 119562- }, 119563- relatedInfo: []vulnRelatedInfo{ 119564- {"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln1 119565- {"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln2 119566- }, 119567- }, 119568- { 119569- msg: "golang.org/amod has a vulnerability GO-2022-03 that is not used in the code.", 119570- severity: protocol.SeverityInformation, 119571- source: string(source.Govulncheck), 119572- codeActions: []string{ 119573- "Upgrade to v1.0.6", 119574- "Upgrade to latest", 119575- "Reset govulncheck result", 119576- }, 119577- relatedInfo: []vulnRelatedInfo{ 119578- {"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln1 119579- {"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln2 119580- }, 119581- }, 119582- }, 119583- codeActions: []string{ 119584- "Upgrade to v1.0.6", 119585- "Upgrade to latest", 119586- "Reset govulncheck result", 119587- }, 119588- hover: []string{"GO-2022-01", "Fixed in v1.0.4.", "GO-2022-03"}, 119589- }, 119590- "golang.org/bmod": { 119591- diagnostics: []vulnDiag{ 119592- { 119593- msg: "golang.org/bmod has a vulnerability used in the code: GO-2022-02.", 119594- severity: protocol.SeverityWarning, 119595- source: string(source.Govulncheck), 119596- codeActions: []string{ 119597- "Reset govulncheck result", // no fix, but we should give an option to reset. 119598- }, 119599- relatedInfo: []vulnRelatedInfo{ 119600- {"y.go", uint32(lineY.Line), "[GO-2022-02]"}, // bvuln.Vuln 119601- }, 119602- }, 119603- }, 119604- codeActions: []string{ 119605- "Reset govulncheck result", // no fix, but we should give an option to reset. 119606- }, 119607- hover: []string{"GO-2022-02", "This is a long description of this vulnerability.", "No fix is available."}, 119608- }, 119609- } 119610- 119611- for mod, want := range wantDiagnostics { 119612- modPathDiagnostics := testVulnDiagnostics(t, env, mod, want, gotDiagnostics) 119613- 119614- // Check that the actions we get when including all diagnostics at a location return the same result 119615- gotActions := env.CodeAction("go.mod", modPathDiagnostics) 119616- if diff := diffCodeActions(gotActions, want.codeActions); diff != "" { 119617- t.Errorf("code actions for %q do not match, expected %v, got %v\n%v\n", mod, want.codeActions, gotActions, diff) 119618- continue 119619- } 119620- 119621- // Apply the code action matching applyAction. 119622- if want.applyAction == "" { 119623- continue 119624- } 119625- for _, action := range gotActions { 119626- if action.Title == want.applyAction { 119627- env.ApplyCodeAction(action) 119628- break 119629- } 119630- } 119631- } 119632- 119633- env.Await(env.DoneWithChangeWatchedFiles()) 119634- wantGoMod := `module golang.org/entry 119635- 119636-go 1.18 119637- 119638-require golang.org/cmod v1.1.3 119639- 119640-require ( 119641- golang.org/amod v1.0.6 // indirect 119642- golang.org/bmod v0.5.0 // indirect 119643-) 119644-` 119645- if got := env.BufferText("go.mod"); got != wantGoMod { 119646- t.Fatalf("go.mod vulncheck fix failed:\n%s", compare.Text(wantGoMod, got)) 119647- } 119648- }) 119649-} 119650- 119651-func diffCodeActions(gotActions []protocol.CodeAction, want []string) string { 119652- var gotTitles []string 119653- for _, ca := range gotActions { 119654- gotTitles = append(gotTitles, ca.Title) 119655- } 119656- return cmp.Diff(want, gotTitles) 119657-} 119658- 119659-const workspace2 = ` 119660--- go.mod -- 119661-module golang.org/entry 119662- 119663-go 1.18 119664- 119665-require golang.org/bmod v0.5.0 119666- 119667--- go.sum -- 119668-golang.org/bmod v0.5.0 h1:MT/ysNRGbCiURc5qThRFWaZ5+rK3pQRPo9w7dYZfMDk= 119669-golang.org/bmod v0.5.0/go.mod h1:k+zl+Ucu4yLIjndMIuWzD/MnOHy06wqr3rD++y0abVs= 119670--- x/x.go -- 119671-package x 119672- 119673-import "golang.org/bmod/bvuln" 119674- 119675-func F() { 119676- // Calls a benign func in bvuln. 119677- bvuln.OK() 119678-} 119679-` 119680- 119681-const proxy2 = ` 119682--- golang.org/bmod@v0.5.0/bvuln/bvuln.go -- 119683-package bvuln 119684- 119685-func Vuln() {} // vulnerable. 119686-func OK() {} // ok. 119687-` 119688- 119689-func TestGovulncheckInfo(t *testing.T) { 119690- testenv.NeedsGo1Point(t, 18) 119691- 119692- db, opts, err := vulnTestEnv(vulnsData, proxy2) 119693- if err != nil { 119694- t.Fatal(err) 119695- } 119696- defer db.Clean() 119697- WithOptions(opts...).Run(t, workspace2, func(t *testing.T, env *Env) { 119698- env.OpenFile("go.mod") 119699- var result command.RunVulncheckResult 119700- env.ExecuteCodeLensCommand("go.mod", command.RunGovulncheck, &result) 119701- gotDiagnostics := &protocol.PublishDiagnosticsParams{} 119702- env.OnceMet( 119703- CompletedProgress(result.Token, nil), 119704- ShownMessage("No vulnerabilities found"), // only count affecting vulnerabilities. 119705- ) 119706- 119707- // Vulncheck diagnostics asynchronous to the vulncheck command. 119708- env.OnceMet( 119709- Diagnostics(env.AtRegexp("go.mod", "golang.org/bmod")), 119710- ReadDiagnostics("go.mod", gotDiagnostics), 119711- ) 119712- 119713- testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{"go.mod": {IDs: []string{"GO-2022-02"}, Mode: govulncheck.ModeGovulncheck}}) 119714- // wantDiagnostics maps a module path in the require 119715- // section of a go.mod to diagnostics that will be returned 119716- // when running vulncheck. 119717- wantDiagnostics := map[string]vulnDiagExpectation{ 119718- "golang.org/bmod": { 119719- diagnostics: []vulnDiag{ 119720- { 119721- msg: "golang.org/bmod has a vulnerability GO-2022-02 that is not used in the code.", 119722- severity: protocol.SeverityInformation, 119723- source: string(source.Govulncheck), 119724- codeActions: []string{ 119725- "Reset govulncheck result", 119726- }, 119727- }, 119728- }, 119729- codeActions: []string{ 119730- "Reset govulncheck result", 119731- }, 119732- hover: []string{"GO-2022-02", "This is a long description of this vulnerability.", "No fix is available."}, 119733- }, 119734- } 119735- 119736- var allActions []protocol.CodeAction 119737- for mod, want := range wantDiagnostics { 119738- modPathDiagnostics := testVulnDiagnostics(t, env, mod, want, gotDiagnostics) 119739- // Check that the actions we get when including all diagnostics at a location return the same result 119740- gotActions := env.CodeAction("go.mod", modPathDiagnostics) 119741- allActions = append(allActions, gotActions...) 119742- if diff := diffCodeActions(gotActions, want.codeActions); diff != "" { 119743- t.Errorf("code actions for %q do not match, expected %v, got %v\n%v\n", mod, want.codeActions, gotActions, diff) 119744- continue 119745- } 119746- } 119747- 119748- // Clear Diagnostics by using one of the reset code actions. 119749- var reset protocol.CodeAction 119750- for _, a := range allActions { 119751- if a.Title == "Reset govulncheck result" { 119752- reset = a 119753- break 119754- } 119755- } 119756- if reset.Title != "Reset govulncheck result" { 119757- t.Errorf("failed to find a 'Reset govulncheck result' code action, got %v", allActions) 119758- } 119759- env.ApplyCodeAction(reset) 119760- 119761- env.Await(NoDiagnostics(ForFile("go.mod"))) 119762- }) 119763-} 119764- 119765-// testVulnDiagnostics finds the require or module statement line for the requireMod in go.mod file 119766-// and runs checks if diagnostics and code actions associated with the line match expectation. 119767-func testVulnDiagnostics(t *testing.T, env *Env, pattern string, want vulnDiagExpectation, got *protocol.PublishDiagnosticsParams) []protocol.Diagnostic { 119768- t.Helper() 119769- loc := env.RegexpSearch("go.mod", pattern) 119770- var modPathDiagnostics []protocol.Diagnostic 119771- for _, w := range want.diagnostics { 119772- // Find the diagnostics at loc.start. 119773- var diag *protocol.Diagnostic 119774- for _, g := range got.Diagnostics { 119775- g := g 119776- if g.Range.Start == loc.Range.Start && w.msg == g.Message { 119777- modPathDiagnostics = append(modPathDiagnostics, g) 119778- diag = &g 119779- break 119780- } 119781- } 119782- if diag == nil { 119783- t.Errorf("no diagnostic at %q matching %q found\n", pattern, w.msg) 119784- continue 119785- } 119786- if diag.Severity != w.severity || diag.Source != w.source { 119787- t.Errorf("incorrect (severity, source) for %q, want (%s, %s) got (%s, %s)\n", w.msg, w.severity, w.source, diag.Severity, diag.Source) 119788- } 119789- sort.Slice(w.relatedInfo, func(i, j int) bool { return w.relatedInfo[i].less(w.relatedInfo[j]) }) 119790- if got, want := summarizeRelatedInfo(diag.RelatedInformation), w.relatedInfo; !cmp.Equal(got, want) { 119791- t.Errorf("related info for %q do not match, want %v, got %v\n", w.msg, want, got) 119792- } 119793- // Check expected code actions appear. 119794- gotActions := env.CodeAction("go.mod", []protocol.Diagnostic{*diag}) 119795- if diff := diffCodeActions(gotActions, w.codeActions); diff != "" { 119796- t.Errorf("code actions for %q do not match, want %v, got %v\n%v\n", w.msg, w.codeActions, gotActions, diff) 119797- continue 119798- } 119799- } 119800- // Check that useful info is supplemented as hover. 119801- if len(want.hover) > 0 { 119802- hover, _ := env.Hover(loc) 119803- for _, part := range want.hover { 119804- if !strings.Contains(hover.Value, part) { 119805- t.Errorf("hover contents for %q do not match, want %v, got %v\n", pattern, strings.Join(want.hover, ","), hover.Value) 119806- break 119807- } 119808- } 119809- } 119810- return modPathDiagnostics 119811-} 119812- 119813-// summarizeRelatedInfo converts protocol.DiagnosticRelatedInformation to vulnRelatedInfo 119814-// that captures only the part that we want to test. 119815-func summarizeRelatedInfo(rinfo []protocol.DiagnosticRelatedInformation) []vulnRelatedInfo { 119816- var res []vulnRelatedInfo 119817- for _, r := range rinfo { 119818- filename := filepath.Base(r.Location.URI.SpanURI().Filename()) 119819- message, _, _ := strings.Cut(r.Message, " ") 119820- line := r.Location.Range.Start.Line 119821- res = append(res, vulnRelatedInfo{filename, line, message}) 119822- } 119823- sort.Slice(res, func(i, j int) bool { 119824- return res[i].less(res[j]) 119825- }) 119826- return res 119827-} 119828- 119829-type vulnRelatedInfo struct { 119830- Filename string 119831- Line uint32 119832- Message string 119833-} 119834- 119835-type vulnDiag struct { 119836- msg string 119837- severity protocol.DiagnosticSeverity 119838- // codeActions is a list titles of code actions that we get with this 119839- // diagnostics as the context. 119840- codeActions []string 119841- // relatedInfo is related info message prefixed by the file base. 119842- // See summarizeRelatedInfo. 119843- relatedInfo []vulnRelatedInfo 119844- // diagnostic source. 119845- source string 119846-} 119847- 119848-func (i vulnRelatedInfo) less(j vulnRelatedInfo) bool { 119849- if i.Filename != j.Filename { 119850- return i.Filename < j.Filename 119851- } 119852- if i.Line != j.Line { 119853- return i.Line < j.Line 119854- } 119855- return i.Message < j.Message 119856-} 119857- 119858-// vulnDiagExpectation maps a module path in the require 119859-// section of a go.mod to diagnostics that will be returned 119860-// when running vulncheck. 119861-type vulnDiagExpectation struct { 119862- // applyAction is the title of the code action to run for this module. 119863- // If empty, no code actions will be executed. 119864- applyAction string 119865- // diagnostics is the list of diagnostics we expect at the require line for 119866- // the module path. 119867- diagnostics []vulnDiag 119868- // codeActions is a list titles of code actions that we get with context 119869- // diagnostics. 119870- codeActions []string 119871- // hover message is the list of expected hover message parts for this go.mod require line. 119872- // all parts must appear in the hover message. 119873- hover []string 119874-} 119875diff -urN a/gopls/internal/regtest/misc/workspace_symbol_test.go b/gopls/internal/regtest/misc/workspace_symbol_test.go 119876--- a/gopls/internal/regtest/misc/workspace_symbol_test.go 2000-01-01 00:00:00.000000000 -0000 119877+++ b/gopls/internal/regtest/misc/workspace_symbol_test.go 1970-01-01 00:00:00.000000000 +0000 119878@@ -1,124 +0,0 @@ 119879-// Copyright 2022 The Go Authors. All rights reserved. 119880-// Use of this source code is governed by a BSD-style 119881-// license that can be found in the LICENSE file. 119882- 119883-package misc 119884- 119885-import ( 119886- "testing" 119887- 119888- "golang.org/x/tools/gopls/internal/lsp/protocol" 119889- . "golang.org/x/tools/gopls/internal/lsp/regtest" 119890- "golang.org/x/tools/gopls/internal/lsp/source" 119891-) 119892- 119893-func TestWorkspaceSymbolMissingMetadata(t *testing.T) { 119894- const files = ` 119895--- go.mod -- 119896-module mod.com 119897- 119898-go 1.17 119899--- a.go -- 119900-package p 119901- 119902-const C1 = "a.go" 119903--- exclude.go -- 119904- 119905-//go:build exclude 119906-// +build exclude 119907- 119908-package exclude 119909- 119910-const C2 = "exclude.go" 119911-` 119912- 119913- Run(t, files, func(t *testing.T, env *Env) { 119914- env.OpenFile("a.go") 119915- syms := env.Symbol("C") 119916- if got, want := len(syms), 1; got != want { 119917- t.Errorf("got %d symbols, want %d", got, want) 119918- } 119919- 119920- // Opening up an ignored file will result in an overlay with missing 119921- // metadata, but this shouldn't break workspace symbols requests. 119922- env.OpenFile("exclude.go") 119923- syms = env.Symbol("C") 119924- if got, want := len(syms), 1; got != want { 119925- t.Errorf("got %d symbols, want %d", got, want) 119926- } 119927- }) 119928-} 119929- 119930-func TestWorkspaceSymbolSorting(t *testing.T) { 119931- const files = ` 119932--- go.mod -- 119933-module mod.com 119934- 119935-go 1.17 119936--- a/a.go -- 119937-package a 119938- 119939-const ( 119940- Foo = iota 119941- FooBar 119942- Fooey 119943- Fooex 119944- Fooest 119945-) 119946-` 119947- 119948- var symbolMatcher = string(source.SymbolFastFuzzy) 119949- WithOptions( 119950- Settings{"symbolMatcher": symbolMatcher}, 119951- ).Run(t, files, func(t *testing.T, env *Env) { 119952- want := []string{ 119953- "Foo", // prefer exact segment matches first 119954- "FooBar", // ...followed by exact word matches 119955- "Fooex", // shorter than Fooest, FooBar, lexically before Fooey 119956- "Fooey", // shorter than Fooest, Foobar 119957- "Fooest", 119958- } 119959- got := env.Symbol("Foo") 119960- compareSymbols(t, got, want...) 119961- }) 119962-} 119963- 119964-func TestWorkspaceSymbolSpecialPatterns(t *testing.T) { 119965- const files = ` 119966--- go.mod -- 119967-module mod.com 119968- 119969-go 1.17 119970--- a/a.go -- 119971-package a 119972- 119973-const ( 119974- AxxBxxCxx 119975- ABC 119976-) 119977-` 119978- 119979- var symbolMatcher = string(source.SymbolFastFuzzy) 119980- WithOptions( 119981- Settings{"symbolMatcher": symbolMatcher}, 119982- ).Run(t, files, func(t *testing.T, env *Env) { 119983- compareSymbols(t, env.Symbol("ABC"), "ABC", "AxxBxxCxx") 119984- compareSymbols(t, env.Symbol("'ABC"), "ABC") 119985- compareSymbols(t, env.Symbol("^mod.com"), "mod.com/a.ABC", "mod.com/a.AxxBxxCxx") 119986- compareSymbols(t, env.Symbol("^mod.com Axx"), "mod.com/a.AxxBxxCxx") 119987- compareSymbols(t, env.Symbol("C$"), "ABC") 119988- }) 119989-} 119990- 119991-func compareSymbols(t *testing.T, got []protocol.SymbolInformation, want ...string) { 119992- t.Helper() 119993- if len(got) != len(want) { 119994- t.Errorf("got %d symbols, want %d", len(got), len(want)) 119995- } 119996- 119997- for i := range got { 119998- if got[i].Name != want[i] { 119999- t.Errorf("got[%d] = %q, want %q", i, got[i].Name, want[i]) 120000- } 120001- } 120002-} 120003diff -urN a/gopls/internal/regtest/modfile/modfile_test.go b/gopls/internal/regtest/modfile/modfile_test.go 120004--- a/gopls/internal/regtest/modfile/modfile_test.go 2000-01-01 00:00:00.000000000 -0000 120005+++ b/gopls/internal/regtest/modfile/modfile_test.go 1970-01-01 00:00:00.000000000 +0000 120006@@ -1,1188 +0,0 @@ 120007-// Copyright 2020 The Go Authors. All rights reserved. 120008-// Use of this source code is governed by a BSD-style 120009-// license that can be found in the LICENSE file. 120010- 120011-package modfile 120012- 120013-import ( 120014- "path/filepath" 120015- "runtime" 120016- "strings" 120017- "testing" 120018- 120019- "golang.org/x/tools/gopls/internal/hooks" 120020- . "golang.org/x/tools/gopls/internal/lsp/regtest" 120021- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 120022- "golang.org/x/tools/internal/bug" 120023- 120024- "golang.org/x/tools/gopls/internal/lsp/protocol" 120025- "golang.org/x/tools/internal/testenv" 120026-) 120027- 120028-func TestMain(m *testing.M) { 120029- bug.PanicOnBugs = true 120030- Main(m, hooks.Options) 120031-} 120032- 120033-const workspaceProxy = ` 120034--- [email protected]/go.mod -- 120035-module example.com 120036- 120037-go 1.12 120038--- [email protected]/blah/blah.go -- 120039-package blah 120040- 120041-func SaySomething() { 120042- fmt.Println("something") 120043-} 120044--- [email protected]/go.mod -- 120045-module random.org 120046- 120047-go 1.12 120048--- [email protected]/bye/bye.go -- 120049-package bye 120050- 120051-func Goodbye() { 120052- println("Bye") 120053-} 120054-` 120055- 120056-const proxy = ` 120057--- [email protected]/go.mod -- 120058-module example.com 120059- 120060-go 1.12 120061--- [email protected]/blah/blah.go -- 120062-package blah 120063- 120064-const Name = "Blah" 120065--- [email protected]/go.mod -- 120066-module random.org 120067- 120068-go 1.12 120069--- [email protected]/blah/blah.go -- 120070-package hello 120071- 120072-const Name = "Hello" 120073-` 120074- 120075-func TestModFileModification(t *testing.T) { 120076- const untidyModule = ` 120077--- a/go.mod -- 120078-module mod.com 120079- 120080--- a/main.go -- 120081-package main 120082- 120083-import "example.com/blah" 120084- 120085-func main() { 120086- println(blah.Name) 120087-} 120088-` 120089- 120090- runner := RunMultiple{ 120091- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120092- {"nested", WithOptions(ProxyFiles(proxy))}, 120093- } 120094- 120095- t.Run("basic", func(t *testing.T) { 120096- runner.Run(t, untidyModule, func(t *testing.T, env *Env) { 120097- // Open the file and make sure that the initial workspace load does not 120098- // modify the go.mod file. 120099- goModContent := env.ReadWorkspaceFile("a/go.mod") 120100- env.OpenFile("a/main.go") 120101- env.AfterChange( 120102- Diagnostics(env.AtRegexp("a/main.go", "\"example.com/blah\"")), 120103- ) 120104- if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent { 120105- t.Fatalf("go.mod changed on disk:\n%s", compare.Text(goModContent, got)) 120106- } 120107- // Save the buffer, which will format and organize imports. 120108- // Confirm that the go.mod file still does not change. 120109- env.SaveBuffer("a/main.go") 120110- env.AfterChange( 120111- Diagnostics(env.AtRegexp("a/main.go", "\"example.com/blah\"")), 120112- ) 120113- if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent { 120114- t.Fatalf("go.mod changed on disk:\n%s", compare.Text(goModContent, got)) 120115- } 120116- }) 120117- }) 120118- 120119- // Reproduce golang/go#40269 by deleting and recreating main.go. 120120- t.Run("delete main.go", func(t *testing.T) { 120121- runner.Run(t, untidyModule, func(t *testing.T, env *Env) { 120122- goModContent := env.ReadWorkspaceFile("a/go.mod") 120123- mainContent := env.ReadWorkspaceFile("a/main.go") 120124- env.OpenFile("a/main.go") 120125- env.SaveBuffer("a/main.go") 120126- 120127- // Ensure that we're done processing all the changes caused by opening 120128- // and saving above. If not, we may run into a file locking issue on 120129- // windows. 120130- // 120131- // If this proves insufficient, env.RemoveWorkspaceFile can be updated to 120132- // retry file lock errors on windows. 120133- env.AfterChange() 120134- env.RemoveWorkspaceFile("a/main.go") 120135- 120136- // TODO(rfindley): awaiting here shouldn't really be necessary. We should 120137- // be consistent eventually. 120138- // 120139- // Probably this was meant to exercise a race with the change below. 120140- env.AfterChange() 120141- 120142- env.WriteWorkspaceFile("a/main.go", mainContent) 120143- env.AfterChange( 120144- Diagnostics(env.AtRegexp("a/main.go", "\"example.com/blah\"")), 120145- ) 120146- if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent { 120147- t.Fatalf("go.mod changed on disk:\n%s", compare.Text(goModContent, got)) 120148- } 120149- }) 120150- }) 120151-} 120152- 120153-func TestGoGetFix(t *testing.T) { 120154- const mod = ` 120155--- a/go.mod -- 120156-module mod.com 120157- 120158-go 1.12 120159- 120160--- a/main.go -- 120161-package main 120162- 120163-import "example.com/blah" 120164- 120165-var _ = blah.Name 120166-` 120167- 120168- const want = `module mod.com 120169- 120170-go 1.12 120171- 120172-require example.com v1.2.3 120173-` 120174- 120175- RunMultiple{ 120176- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120177- {"nested", WithOptions(ProxyFiles(proxy))}, 120178- }.Run(t, mod, func(t *testing.T, env *Env) { 120179- if strings.Contains(t.Name(), "workspace_module") { 120180- t.Skip("workspace module mode doesn't set -mod=readonly") 120181- } 120182- env.OpenFile("a/main.go") 120183- var d protocol.PublishDiagnosticsParams 120184- env.AfterChange( 120185- Diagnostics(env.AtRegexp("a/main.go", `"example.com/blah"`)), 120186- ReadDiagnostics("a/main.go", &d), 120187- ) 120188- var goGetDiag protocol.Diagnostic 120189- for _, diag := range d.Diagnostics { 120190- if strings.Contains(diag.Message, "could not import") { 120191- goGetDiag = diag 120192- } 120193- } 120194- env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{goGetDiag}) 120195- if got := env.ReadWorkspaceFile("a/go.mod"); got != want { 120196- t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) 120197- } 120198- }) 120199-} 120200- 120201-// Tests that multiple missing dependencies gives good single fixes. 120202-func TestMissingDependencyFixes(t *testing.T) { 120203- const mod = ` 120204--- a/go.mod -- 120205-module mod.com 120206- 120207-go 1.12 120208- 120209--- a/main.go -- 120210-package main 120211- 120212-import "example.com/blah" 120213-import "random.org/blah" 120214- 120215-var _, _ = blah.Name, hello.Name 120216-` 120217- 120218- const want = `module mod.com 120219- 120220-go 1.12 120221- 120222-require random.org v1.2.3 120223-` 120224- 120225- RunMultiple{ 120226- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120227- {"nested", WithOptions(ProxyFiles(proxy))}, 120228- }.Run(t, mod, func(t *testing.T, env *Env) { 120229- env.OpenFile("a/main.go") 120230- var d protocol.PublishDiagnosticsParams 120231- env.AfterChange( 120232- Diagnostics(env.AtRegexp("a/main.go", `"random.org/blah"`)), 120233- ReadDiagnostics("a/main.go", &d), 120234- ) 120235- var randomDiag protocol.Diagnostic 120236- for _, diag := range d.Diagnostics { 120237- if strings.Contains(diag.Message, "random.org") { 120238- randomDiag = diag 120239- } 120240- } 120241- env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{randomDiag}) 120242- if got := env.ReadWorkspaceFile("a/go.mod"); got != want { 120243- t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) 120244- } 120245- }) 120246-} 120247- 120248-// Tests that multiple missing dependencies gives good single fixes. 120249-func TestMissingDependencyFixesWithGoWork(t *testing.T) { 120250- testenv.NeedsGo1Point(t, 18) 120251- const mod = ` 120252--- go.work -- 120253-go 1.18 120254- 120255-use ( 120256- ./a 120257-) 120258--- a/go.mod -- 120259-module mod.com 120260- 120261-go 1.12 120262- 120263--- a/main.go -- 120264-package main 120265- 120266-import "example.com/blah" 120267-import "random.org/blah" 120268- 120269-var _, _ = blah.Name, hello.Name 120270-` 120271- 120272- const want = `module mod.com 120273- 120274-go 1.12 120275- 120276-require random.org v1.2.3 120277-` 120278- 120279- RunMultiple{ 120280- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120281- {"nested", WithOptions(ProxyFiles(proxy))}, 120282- }.Run(t, mod, func(t *testing.T, env *Env) { 120283- env.OpenFile("a/main.go") 120284- var d protocol.PublishDiagnosticsParams 120285- env.AfterChange( 120286- Diagnostics(env.AtRegexp("a/main.go", `"random.org/blah"`)), 120287- ReadDiagnostics("a/main.go", &d), 120288- ) 120289- var randomDiag protocol.Diagnostic 120290- for _, diag := range d.Diagnostics { 120291- if strings.Contains(diag.Message, "random.org") { 120292- randomDiag = diag 120293- } 120294- } 120295- env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{randomDiag}) 120296- if got := env.ReadWorkspaceFile("a/go.mod"); got != want { 120297- t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) 120298- } 120299- }) 120300-} 120301- 120302-func TestIndirectDependencyFix(t *testing.T) { 120303- const mod = ` 120304--- a/go.mod -- 120305-module mod.com 120306- 120307-go 1.12 120308- 120309-require example.com v1.2.3 // indirect 120310--- a/go.sum -- 120311-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 120312-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 120313--- a/main.go -- 120314-package main 120315- 120316-import "example.com/blah" 120317- 120318-func main() { 120319- fmt.Println(blah.Name) 120320-` 120321- const want = `module mod.com 120322- 120323-go 1.12 120324- 120325-require example.com v1.2.3 120326-` 120327- 120328- RunMultiple{ 120329- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120330- {"nested", WithOptions(ProxyFiles(proxy))}, 120331- }.Run(t, mod, func(t *testing.T, env *Env) { 120332- env.OpenFile("a/go.mod") 120333- var d protocol.PublishDiagnosticsParams 120334- env.AfterChange( 120335- Diagnostics(env.AtRegexp("a/go.mod", "// indirect")), 120336- ReadDiagnostics("a/go.mod", &d), 120337- ) 120338- env.ApplyQuickFixes("a/go.mod", d.Diagnostics) 120339- if got := env.BufferText("a/go.mod"); got != want { 120340- t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) 120341- } 120342- }) 120343-} 120344- 120345-func TestUnusedDiag(t *testing.T) { 120346- 120347- const proxy = ` 120348--- [email protected]/x.go -- 120349-package pkg 120350-const X = 1 120351-` 120352- const files = ` 120353--- a/go.mod -- 120354-module mod.com 120355-go 1.14 120356-require example.com v1.0.0 120357--- a/go.sum -- 120358-example.com v1.0.0 h1:38O7j5rEBajXk+Q5wzLbRN7KqMkSgEiN9NqcM1O2bBM= 120359-example.com v1.0.0/go.mod h1:vUsPMGpx9ZXXzECCOsOmYCW7npJTwuA16yl89n3Mgls= 120360--- a/main.go -- 120361-package main 120362-func main() {} 120363-` 120364- 120365- const want = `module mod.com 120366- 120367-go 1.14 120368-` 120369- 120370- RunMultiple{ 120371- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120372- {"nested", WithOptions(ProxyFiles(proxy))}, 120373- }.Run(t, files, func(t *testing.T, env *Env) { 120374- env.OpenFile("a/go.mod") 120375- var d protocol.PublishDiagnosticsParams 120376- env.AfterChange( 120377- Diagnostics(env.AtRegexp("a/go.mod", `require example.com`)), 120378- ReadDiagnostics("a/go.mod", &d), 120379- ) 120380- env.ApplyQuickFixes("a/go.mod", d.Diagnostics) 120381- if got := env.BufferText("a/go.mod"); got != want { 120382- t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) 120383- } 120384- }) 120385-} 120386- 120387-// Test to reproduce golang/go#39041. It adds a new require to a go.mod file 120388-// that already has an unused require. 120389-func TestNewDepWithUnusedDep(t *testing.T) { 120390- 120391- const proxy = ` 120392--- github.com/esimov/caire@v1.2.5/go.mod -- 120393-module github.com/esimov/caire 120394- 120395-go 1.12 120396--- github.com/esimov/caire@v1.2.5/caire.go -- 120397-package caire 120398- 120399-func RemoveTempImage() {} 120400--- google.golang.org/protobuf@v1.20.0/go.mod -- 120401-module google.golang.org/protobuf 120402- 120403-go 1.12 120404--- google.golang.org/protobuf@v1.20.0/hello/hello.go -- 120405-package hello 120406-` 120407- const repro = ` 120408--- a/go.mod -- 120409-module mod.com 120410- 120411-go 1.14 120412- 120413-require google.golang.org/protobuf v1.20.0 120414--- a/go.sum -- 120415-github.com/esimov/caire v1.2.5 h1:OcqDII/BYxcBYj3DuwDKjd+ANhRxRqLa2n69EGje7qw= 120416-github.com/esimov/caire v1.2.5/go.mod h1:mXnjRjg3+WUtuhfSC1rKRmdZU9vJZyS1ZWU0qSvJhK8= 120417-google.golang.org/protobuf v1.20.0 h1:y9T1vAtFKQg0faFNMOxJU7WuEqPWolVkjIkU6aI8qCY= 120418-google.golang.org/protobuf v1.20.0/go.mod h1:FcqsytGClbtLv1ot8NvsJHjBi0h22StKVP+K/j2liKA= 120419--- a/main.go -- 120420-package main 120421- 120422-import ( 120423- "github.com/esimov/caire" 120424-) 120425- 120426-func _() { 120427- caire.RemoveTempImage() 120428-}` 120429- 120430- RunMultiple{ 120431- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120432- {"nested", WithOptions(ProxyFiles(proxy))}, 120433- }.Run(t, repro, func(t *testing.T, env *Env) { 120434- env.OpenFile("a/main.go") 120435- var d protocol.PublishDiagnosticsParams 120436- env.AfterChange( 120437- Diagnostics(env.AtRegexp("a/main.go", `"github.com/esimov/caire"`)), 120438- ReadDiagnostics("a/main.go", &d), 120439- ) 120440- env.ApplyQuickFixes("a/main.go", d.Diagnostics) 120441- want := `module mod.com 120442- 120443-go 1.14 120444- 120445-require ( 120446- github.com/esimov/caire v1.2.5 120447- google.golang.org/protobuf v1.20.0 120448-) 120449-` 120450- if got := env.ReadWorkspaceFile("a/go.mod"); got != want { 120451- t.Fatalf("TestNewDepWithUnusedDep failed:\n%s", compare.Text(want, got)) 120452- } 120453- }) 120454-} 120455- 120456-// TODO: For this test to be effective, the sandbox's file watcher must respect 120457-// the file watching GlobPattern in the capability registration. See 120458-// golang/go#39384. 120459-func TestModuleChangesOnDisk(t *testing.T) { 120460- const mod = ` 120461--- a/go.mod -- 120462-module mod.com 120463- 120464-go 1.12 120465- 120466-require example.com v1.2.3 120467--- a/go.sum -- 120468-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 120469-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 120470--- a/main.go -- 120471-package main 120472- 120473-func main() { 120474- fmt.Println(blah.Name) 120475-` 120476- RunMultiple{ 120477- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120478- {"nested", WithOptions(ProxyFiles(proxy))}, 120479- }.Run(t, mod, func(t *testing.T, env *Env) { 120480- env.OnceMet( 120481- InitialWorkspaceLoad, 120482- Diagnostics(env.AtRegexp("a/go.mod", "require")), 120483- ) 120484- env.RunGoCommandInDir("a", "mod", "tidy") 120485- env.AfterChange( 120486- NoDiagnostics(ForFile("a/go.mod")), 120487- ) 120488- }) 120489-} 120490- 120491-// Tests golang/go#39784: a missing indirect dependency, necessary 120492-// due to [email protected]'s incomplete go.mod file. 120493-func TestBadlyVersionedModule(t *testing.T) { 120494- const proxy = ` 120495--- example.com/blah/@v/v1.0.0.mod -- 120496-module example.com 120497- 120498-go 1.12 120499--- example.com/blah@v1.0.0/blah.go -- 120500-package blah 120501- 120502-const Name = "Blah" 120503--- example.com/blah/v2/@v/v2.0.0.mod -- 120504-module example.com 120505- 120506-go 1.12 120507--- example.com/blah/v2@v2.0.0/blah.go -- 120508-package blah 120509- 120510-import "example.com/blah" 120511- 120512-var V1Name = blah.Name 120513-const Name = "Blah" 120514-` 120515- const files = ` 120516--- a/go.mod -- 120517-module mod.com 120518- 120519-go 1.12 120520- 120521-require example.com/blah/v2 v2.0.0 120522--- a/go.sum -- 120523-example.com/blah v1.0.0 h1:kGPlWJbMsn1P31H9xp/q2mYI32cxLnCvauHN0AVaHnc= 120524-example.com/blah v1.0.0/go.mod h1:PZUQaGFeVjyDmAE8ywmLbmDn3fj4Ws8epg4oLuDzW3M= 120525-example.com/blah/v2 v2.0.0 h1:DNPsFPkKtTdxclRheaMCiYAoYizp6PuBzO0OmLOO0pY= 120526-example.com/blah/v2 v2.0.0/go.mod h1:UZiKbTwobERo/hrqFLvIQlJwQZQGxWMVY4xere8mj7w= 120527--- a/main.go -- 120528-package main 120529- 120530-import "example.com/blah/v2" 120531- 120532-var _ = blah.Name 120533-` 120534- RunMultiple{ 120535- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120536- {"nested", WithOptions(ProxyFiles(proxy))}, 120537- }.Run(t, files, func(t *testing.T, env *Env) { 120538- env.OpenFile("a/main.go") 120539- env.OpenFile("a/go.mod") 120540- var modDiags protocol.PublishDiagnosticsParams 120541- env.AfterChange( 120542- // We would like for the error to appear in the v2 module, but 120543- // as of writing non-workspace packages are not diagnosed. 120544- Diagnostics(env.AtRegexp("a/main.go", `"example.com/blah/v2"`), WithMessage("cannot find module providing")), 120545- Diagnostics(env.AtRegexp("a/go.mod", `require example.com/blah/v2`), WithMessage("cannot find module providing")), 120546- ReadDiagnostics("a/go.mod", &modDiags), 120547- ) 120548- env.ApplyQuickFixes("a/go.mod", modDiags.Diagnostics) 120549- const want = `module mod.com 120550- 120551-go 1.12 120552- 120553-require ( 120554- example.com/blah v1.0.0 // indirect 120555- example.com/blah/v2 v2.0.0 120556-) 120557-` 120558- env.SaveBuffer("a/go.mod") 120559- env.AfterChange(NoDiagnostics(ForFile("a/main.go"))) 120560- if got := env.BufferText("a/go.mod"); got != want { 120561- t.Fatalf("suggested fixes failed:\n%s", compare.Text(want, got)) 120562- } 120563- }) 120564-} 120565- 120566-// Reproduces golang/go#38232. 120567-func TestUnknownRevision(t *testing.T) { 120568- if runtime.GOOS == "plan9" { 120569- t.Skipf("skipping test that fails for unknown reasons on plan9; see https://go.dev/issue/50477") 120570- } 120571- const unknown = ` 120572--- a/go.mod -- 120573-module mod.com 120574- 120575-require ( 120576- example.com v1.2.2 120577-) 120578--- a/main.go -- 120579-package main 120580- 120581-import "example.com/blah" 120582- 120583-func main() { 120584- var x = blah.Name 120585-} 120586-` 120587- 120588- runner := RunMultiple{ 120589- {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, 120590- {"nested", WithOptions(ProxyFiles(proxy))}, 120591- } 120592- // Start from a bad state/bad IWL, and confirm that we recover. 120593- t.Run("bad", func(t *testing.T) { 120594- runner.Run(t, unknown, func(t *testing.T, env *Env) { 120595- env.OpenFile("a/go.mod") 120596- env.AfterChange( 120597- Diagnostics(env.AtRegexp("a/go.mod", "example.com v1.2.2")), 120598- ) 120599- env.RegexpReplace("a/go.mod", "v1.2.2", "v1.2.3") 120600- env.SaveBuffer("a/go.mod") // Save to trigger diagnostics. 120601- 120602- d := protocol.PublishDiagnosticsParams{} 120603- env.AfterChange( 120604- // Make sure the diagnostic mentions the new version -- the old diagnostic is in the same place. 120605- Diagnostics(env.AtRegexp("a/go.mod", "example.com v1.2.3"), WithMessage("[email protected]")), 120606- ReadDiagnostics("a/go.mod", &d), 120607- ) 120608- qfs := env.GetQuickFixes("a/go.mod", d.Diagnostics) 120609- if len(qfs) == 0 { 120610- t.Fatalf("got 0 code actions to fix %v, wanted at least 1", d.Diagnostics) 120611- } 120612- env.ApplyCodeAction(qfs[0]) // Arbitrarily pick a single fix to apply. Applying all of them seems to cause trouble in this particular test. 120613- env.SaveBuffer("a/go.mod") // Save to trigger diagnostics. 120614- env.AfterChange( 120615- NoDiagnostics(ForFile("a/go.mod")), 120616- Diagnostics(env.AtRegexp("a/main.go", "x = ")), 120617- ) 120618- }) 120619- }) 120620- 120621- const known = ` 120622--- a/go.mod -- 120623-module mod.com 120624- 120625-require ( 120626- example.com v1.2.3 120627-) 120628--- a/go.sum -- 120629-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 120630-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 120631--- a/main.go -- 120632-package main 120633- 120634-import "example.com/blah" 120635- 120636-func main() { 120637- var x = blah.Name 120638-} 120639-` 120640- // Start from a good state, transform to a bad state, and confirm that we 120641- // still recover. 120642- t.Run("good", func(t *testing.T) { 120643- runner.Run(t, known, func(t *testing.T, env *Env) { 120644- env.OpenFile("a/go.mod") 120645- env.AfterChange( 120646- Diagnostics(env.AtRegexp("a/main.go", "x = ")), 120647- ) 120648- env.RegexpReplace("a/go.mod", "v1.2.3", "v1.2.2") 120649- env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk 120650- env.AfterChange( 120651- Diagnostics(env.AtRegexp("a/go.mod", "example.com v1.2.2")), 120652- ) 120653- env.RegexpReplace("a/go.mod", "v1.2.2", "v1.2.3") 120654- env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk 120655- env.AfterChange( 120656- Diagnostics(env.AtRegexp("a/main.go", "x = ")), 120657- ) 120658- }) 120659- }) 120660-} 120661- 120662-// Confirm that an error in an indirect dependency of a requirement is surfaced 120663-// as a diagnostic in the go.mod file. 120664-func TestErrorInIndirectDependency(t *testing.T) { 120665- const badProxy = ` 120666--- [email protected]/go.mod -- 120667-module example.com 120668- 120669-go 1.12 120670- 120671-require random.org v1.2.3 // indirect 120672--- [email protected]/blah/blah.go -- 120673-package blah 120674- 120675-const Name = "Blah" 120676--- [email protected]/go.mod -- 120677-module bob.org 120678- 120679-go 1.12 120680--- [email protected]/blah/blah.go -- 120681-package hello 120682- 120683-const Name = "Hello" 120684-` 120685- const module = ` 120686--- a/go.mod -- 120687-module mod.com 120688- 120689-go 1.14 120690- 120691-require example.com v1.2.3 120692--- a/main.go -- 120693-package main 120694- 120695-import "example.com/blah" 120696- 120697-func main() { 120698- println(blah.Name) 120699-} 120700-` 120701- RunMultiple{ 120702- {"default", WithOptions(ProxyFiles(badProxy), WorkspaceFolders("a"))}, 120703- {"nested", WithOptions(ProxyFiles(badProxy))}, 120704- }.Run(t, module, func(t *testing.T, env *Env) { 120705- env.OpenFile("a/go.mod") 120706- env.AfterChange( 120707- Diagnostics(env.AtRegexp("a/go.mod", "require example.com v1.2.3")), 120708- ) 120709- }) 120710-} 120711- 120712-// A copy of govim's config_set_env_goflags_mod_readonly test. 120713-func TestGovimModReadonly(t *testing.T) { 120714- const mod = ` 120715--- go.mod -- 120716-module mod.com 120717- 120718-go 1.13 120719--- main.go -- 120720-package main 120721- 120722-import "example.com/blah" 120723- 120724-func main() { 120725- println(blah.Name) 120726-} 120727-` 120728- WithOptions( 120729- EnvVars{"GOFLAGS": "-mod=readonly"}, 120730- ProxyFiles(proxy), 120731- Modes(Default), 120732- ).Run(t, mod, func(t *testing.T, env *Env) { 120733- env.OpenFile("main.go") 120734- original := env.ReadWorkspaceFile("go.mod") 120735- env.AfterChange( 120736- Diagnostics(env.AtRegexp("main.go", `"example.com/blah"`)), 120737- ) 120738- got := env.ReadWorkspaceFile("go.mod") 120739- if got != original { 120740- t.Fatalf("go.mod file modified:\n%s", compare.Text(original, got)) 120741- } 120742- env.RunGoCommand("get", "example.com/blah@v1.2.3") 120743- env.RunGoCommand("mod", "tidy") 120744- env.AfterChange( 120745- NoDiagnostics(ForFile("main.go")), 120746- ) 120747- }) 120748-} 120749- 120750-func TestMultiModuleModDiagnostics(t *testing.T) { 120751- testenv.NeedsGo1Point(t, 18) // uses go.work 120752- const mod = ` 120753--- go.work -- 120754-go 1.18 120755- 120756-use ( 120757- a 120758- b 120759-) 120760--- a/go.mod -- 120761-module moda.com 120762- 120763-go 1.14 120764- 120765-require ( 120766- example.com v1.2.3 120767-) 120768--- a/go.sum -- 120769-example.com v1.2.3 h1:Yryq11hF02fEf2JlOS2eph+ICE2/ceevGV3C9dl5V/c= 120770-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 120771--- a/main.go -- 120772-package main 120773- 120774-func main() {} 120775--- b/go.mod -- 120776-module modb.com 120777- 120778-require example.com v1.2.3 120779- 120780-go 1.14 120781--- b/main.go -- 120782-package main 120783- 120784-import "example.com/blah" 120785- 120786-func main() { 120787- blah.SaySomething() 120788-} 120789-` 120790- WithOptions( 120791- ProxyFiles(workspaceProxy), 120792- ).Run(t, mod, func(t *testing.T, env *Env) { 120793- env.AfterChange( 120794- Diagnostics( 120795- env.AtRegexp("a/go.mod", "example.com v1.2.3"), 120796- WithMessage("is not used"), 120797- ), 120798- ) 120799- }) 120800-} 120801- 120802-func TestModTidyWithBuildTags(t *testing.T) { 120803- const mod = ` 120804--- go.mod -- 120805-module mod.com 120806- 120807-go 1.14 120808--- main.go -- 120809-// +build bob 120810- 120811-package main 120812- 120813-import "example.com/blah" 120814- 120815-func main() { 120816- blah.SaySomething() 120817-} 120818-` 120819- WithOptions( 120820- ProxyFiles(workspaceProxy), 120821- Settings{"buildFlags": []string{"-tags", "bob"}}, 120822- ).Run(t, mod, func(t *testing.T, env *Env) { 120823- env.OnceMet( 120824- InitialWorkspaceLoad, 120825- Diagnostics(env.AtRegexp("main.go", `"example.com/blah"`)), 120826- ) 120827- }) 120828-} 120829- 120830-func TestModTypoDiagnostic(t *testing.T) { 120831- const mod = ` 120832--- go.mod -- 120833-module mod.com 120834- 120835-go 1.12 120836--- main.go -- 120837-package main 120838- 120839-func main() {} 120840-` 120841- Run(t, mod, func(t *testing.T, env *Env) { 120842- env.OpenFile("go.mod") 120843- env.RegexpReplace("go.mod", "module", "modul") 120844- env.AfterChange( 120845- Diagnostics(env.AtRegexp("go.mod", "modul")), 120846- ) 120847- }) 120848-} 120849- 120850-func TestSumUpdateFixesDiagnostics(t *testing.T) { 120851- const mod = ` 120852--- go.mod -- 120853-module mod.com 120854- 120855-go 1.12 120856- 120857-require ( 120858- example.com v1.2.3 120859-) 120860--- go.sum -- 120861--- main.go -- 120862-package main 120863- 120864-import ( 120865- "example.com/blah" 120866-) 120867- 120868-func main() { 120869- println(blah.Name) 120870-} 120871-` 120872- WithOptions( 120873- ProxyFiles(workspaceProxy), 120874- ).Run(t, mod, func(t *testing.T, env *Env) { 120875- d := &protocol.PublishDiagnosticsParams{} 120876- env.OpenFile("go.mod") 120877- env.AfterChange( 120878- Diagnostics( 120879- env.AtRegexp("go.mod", `example.com v1.2.3`), 120880- WithMessage("go.sum is out of sync"), 120881- ), 120882- ReadDiagnostics("go.mod", d), 120883- ) 120884- env.ApplyQuickFixes("go.mod", d.Diagnostics) 120885- env.SaveBuffer("go.mod") // Save to trigger diagnostics. 120886- env.AfterChange( 120887- NoDiagnostics(ForFile("go.mod")), 120888- ) 120889- }) 120890-} 120891- 120892-// This test confirms that editing a go.mod file only causes metadata 120893-// to be invalidated when it's saved. 120894-func TestGoModInvalidatesOnSave(t *testing.T) { 120895- const mod = ` 120896--- go.mod -- 120897-module mod.com 120898- 120899-go 1.12 120900--- main.go -- 120901-package main 120902- 120903-func main() { 120904- hello() 120905-} 120906--- hello.go -- 120907-package main 120908- 120909-func hello() {} 120910-` 120911- WithOptions( 120912- // TODO(rFindley) this doesn't work in multi-module workspace mode, because 120913- // it keeps around the last parsing modfile. Update this test to also 120914- // exercise the workspace module. 120915- Modes(Default), 120916- ).Run(t, mod, func(t *testing.T, env *Env) { 120917- env.OpenFile("go.mod") 120918- env.Await(env.DoneWithOpen()) 120919- env.RegexpReplace("go.mod", "module", "modul") 120920- // Confirm that we still have metadata with only on-disk edits. 120921- env.OpenFile("main.go") 120922- loc := env.GoToDefinition(env.RegexpSearch("main.go", "hello")) 120923- if filepath.Base(string(loc.URI)) != "hello.go" { 120924- t.Fatalf("expected definition in hello.go, got %s", loc.URI) 120925- } 120926- // Confirm that we no longer have metadata when the file is saved. 120927- env.SaveBufferWithoutActions("go.mod") 120928- _, err := env.Editor.GoToDefinition(env.Ctx, env.RegexpSearch("main.go", "hello")) 120929- if err == nil { 120930- t.Fatalf("expected error, got none") 120931- } 120932- }) 120933-} 120934- 120935-func TestRemoveUnusedDependency(t *testing.T) { 120936- const proxy = ` 120937--- [email protected]/go.mod -- 120938-module hasdep.com 120939- 120940-go 1.12 120941- 120942-require example.com v1.2.3 120943--- [email protected]/a/a.go -- 120944-package a 120945--- [email protected]/go.mod -- 120946-module example.com 120947- 120948-go 1.12 120949--- [email protected]/blah/blah.go -- 120950-package blah 120951- 120952-const Name = "Blah" 120953--- [email protected]/go.mod -- 120954-module random.com 120955- 120956-go 1.12 120957--- [email protected]/blah/blah.go -- 120958-package blah 120959- 120960-const Name = "Blah" 120961-` 120962- t.Run("almost tidied", func(t *testing.T) { 120963- const mod = ` 120964--- go.mod -- 120965-module mod.com 120966- 120967-go 1.12 120968- 120969-require hasdep.com v1.2.3 120970--- go.sum -- 120971-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 120972-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 120973-hasdep.com v1.2.3 h1:00y+N5oD+SpKoqV1zP2VOPawcW65Zb9NebANY3GSzGI= 120974-hasdep.com v1.2.3/go.mod h1:ePVZOlez+KZEOejfLPGL2n4i8qiAjrkhQZ4wcImqAes= 120975--- main.go -- 120976-package main 120977- 120978-func main() {} 120979-` 120980- WithOptions( 120981- ProxyFiles(proxy), 120982- ).Run(t, mod, func(t *testing.T, env *Env) { 120983- env.OpenFile("go.mod") 120984- d := &protocol.PublishDiagnosticsParams{} 120985- env.AfterChange( 120986- Diagnostics(env.AtRegexp("go.mod", "require hasdep.com v1.2.3")), 120987- ReadDiagnostics("go.mod", d), 120988- ) 120989- const want = `module mod.com 120990- 120991-go 1.12 120992-` 120993- env.ApplyQuickFixes("go.mod", d.Diagnostics) 120994- if got := env.BufferText("go.mod"); got != want { 120995- t.Fatalf("unexpected content in go.mod:\n%s", compare.Text(want, got)) 120996- } 120997- }) 120998- }) 120999- 121000- t.Run("not tidied", func(t *testing.T) { 121001- const mod = ` 121002--- go.mod -- 121003-module mod.com 121004- 121005-go 1.12 121006- 121007-require hasdep.com v1.2.3 121008-require random.com v1.2.3 121009--- go.sum -- 121010-example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY= 121011-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 121012-hasdep.com v1.2.3 h1:00y+N5oD+SpKoqV1zP2VOPawcW65Zb9NebANY3GSzGI= 121013-hasdep.com v1.2.3/go.mod h1:ePVZOlez+KZEOejfLPGL2n4i8qiAjrkhQZ4wcImqAes= 121014-random.com v1.2.3 h1:PzYTykzqqH6+qU0dIgh9iPFbfb4Mm8zNBjWWreRKtx0= 121015-random.com v1.2.3/go.mod h1:8EGj+8a4Hw1clAp8vbaeHAsKE4sbm536FP7nKyXO+qQ= 121016--- main.go -- 121017-package main 121018- 121019-func main() {} 121020-` 121021- WithOptions( 121022- ProxyFiles(proxy), 121023- ).Run(t, mod, func(t *testing.T, env *Env) { 121024- d := &protocol.PublishDiagnosticsParams{} 121025- env.OpenFile("go.mod") 121026- pos := env.RegexpSearch("go.mod", "require hasdep.com v1.2.3").Range.Start 121027- env.AfterChange( 121028- Diagnostics(AtPosition("go.mod", pos.Line, pos.Character)), 121029- ReadDiagnostics("go.mod", d), 121030- ) 121031- const want = `module mod.com 121032- 121033-go 1.12 121034- 121035-require random.com v1.2.3 121036-` 121037- var diagnostics []protocol.Diagnostic 121038- for _, d := range d.Diagnostics { 121039- if d.Range.Start.Line != uint32(pos.Line) { 121040- continue 121041- } 121042- diagnostics = append(diagnostics, d) 121043- } 121044- env.ApplyQuickFixes("go.mod", diagnostics) 121045- if got := env.BufferText("go.mod"); got != want { 121046- t.Fatalf("unexpected content in go.mod:\n%s", compare.Text(want, got)) 121047- } 121048- }) 121049- }) 121050-} 121051- 121052-func TestSumUpdateQuickFix(t *testing.T) { 121053- const mod = ` 121054--- go.mod -- 121055-module mod.com 121056- 121057-go 1.12 121058- 121059-require ( 121060- example.com v1.2.3 121061-) 121062--- go.sum -- 121063--- main.go -- 121064-package main 121065- 121066-import ( 121067- "example.com/blah" 121068-) 121069- 121070-func main() { 121071- blah.Hello() 121072-} 121073-` 121074- WithOptions( 121075- ProxyFiles(workspaceProxy), 121076- Modes(Default), 121077- ).Run(t, mod, func(t *testing.T, env *Env) { 121078- env.OpenFile("go.mod") 121079- params := &protocol.PublishDiagnosticsParams{} 121080- env.AfterChange( 121081- Diagnostics( 121082- env.AtRegexp("go.mod", `example.com`), 121083- WithMessage("go.sum is out of sync"), 121084- ), 121085- ReadDiagnostics("go.mod", params), 121086- ) 121087- env.ApplyQuickFixes("go.mod", params.Diagnostics) 121088- const want = `example.com v1.2.3 h1:Yryq11hF02fEf2JlOS2eph+ICE2/ceevGV3C9dl5V/c= 121089-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 121090-` 121091- if got := env.ReadWorkspaceFile("go.sum"); got != want { 121092- t.Fatalf("unexpected go.sum contents:\n%s", compare.Text(want, got)) 121093- } 121094- }) 121095-} 121096- 121097-func TestDownloadDeps(t *testing.T) { 121098- const proxy = ` 121099--- [email protected]/go.mod -- 121100-module example.com 121101- 121102-go 1.12 121103- 121104-require random.org v1.2.3 121105--- [email protected]/blah/blah.go -- 121106-package blah 121107- 121108-import "random.org/bye" 121109- 121110-func SaySomething() { 121111- bye.Goodbye() 121112-} 121113--- [email protected]/go.mod -- 121114-module random.org 121115- 121116-go 1.12 121117--- [email protected]/bye/bye.go -- 121118-package bye 121119- 121120-func Goodbye() { 121121- println("Bye") 121122-} 121123-` 121124- 121125- const mod = ` 121126--- go.mod -- 121127-module mod.com 121128- 121129-go 1.12 121130--- go.sum -- 121131--- main.go -- 121132-package main 121133- 121134-import ( 121135- "example.com/blah" 121136-) 121137- 121138-func main() { 121139- blah.SaySomething() 121140-} 121141-` 121142- WithOptions( 121143- ProxyFiles(proxy), 121144- Modes(Default), 121145- ).Run(t, mod, func(t *testing.T, env *Env) { 121146- env.OpenFile("main.go") 121147- d := &protocol.PublishDiagnosticsParams{} 121148- env.AfterChange( 121149- Diagnostics( 121150- env.AtRegexp("main.go", `"example.com/blah"`), 121151- WithMessage(`could not import example.com/blah (no required module provides package "example.com/blah")`), 121152- ), 121153- ReadDiagnostics("main.go", d), 121154- ) 121155- env.ApplyQuickFixes("main.go", d.Diagnostics) 121156- env.AfterChange( 121157- NoDiagnostics(ForFile("main.go")), 121158- NoDiagnostics(ForFile("go.mod")), 121159- ) 121160- }) 121161-} 121162- 121163-func TestInvalidGoVersion(t *testing.T) { 121164- const files = ` 121165--- go.mod -- 121166-module mod.com 121167- 121168-go foo 121169--- main.go -- 121170-package main 121171-` 121172- Run(t, files, func(t *testing.T, env *Env) { 121173- env.OnceMet( 121174- InitialWorkspaceLoad, 121175- Diagnostics(env.AtRegexp("go.mod", `go foo`), WithMessage("invalid go version")), 121176- ) 121177- env.WriteWorkspaceFile("go.mod", "module mod.com \n\ngo 1.12\n") 121178- env.AfterChange(NoDiagnostics(ForFile("go.mod"))) 121179- }) 121180-} 121181- 121182-// This is a regression test for a bug in the line-oriented implementation 121183-// of the "apply diffs" operation used by the fake editor. 121184-func TestIssue57627(t *testing.T) { 121185- const files = ` 121186--- go.work -- 121187-package main 121188-` 121189- Run(t, files, func(t *testing.T, env *Env) { 121190- env.OpenFile("go.work") 121191- env.SetBufferContent("go.work", "go 1.18\nuse moda/a") 121192- env.SaveBuffer("go.work") // doesn't fail 121193- }) 121194-} 121195diff -urN a/gopls/internal/regtest/template/template_test.go b/gopls/internal/regtest/template/template_test.go 121196--- a/gopls/internal/regtest/template/template_test.go 2000-01-01 00:00:00.000000000 -0000 121197+++ b/gopls/internal/regtest/template/template_test.go 1970-01-01 00:00:00.000000000 +0000 121198@@ -1,231 +0,0 @@ 121199-// Copyright 2022 The Go Authors. All rights reserved. 121200-// Use of this source code is governed by a BSD-style 121201-// license that can be found in the LICENSE file. 121202- 121203-package template 121204- 121205-import ( 121206- "strings" 121207- "testing" 121208- 121209- "golang.org/x/tools/gopls/internal/hooks" 121210- "golang.org/x/tools/gopls/internal/lsp/protocol" 121211- . "golang.org/x/tools/gopls/internal/lsp/regtest" 121212- "golang.org/x/tools/internal/bug" 121213-) 121214- 121215-func TestMain(m *testing.M) { 121216- bug.PanicOnBugs = true 121217- Main(m, hooks.Options) 121218-} 121219- 121220-func TestMultilineTokens(t *testing.T) { 121221- // 51731: panic: runtime error: slice bounds out of range [38:3] 121222- const files = ` 121223--- go.mod -- 121224-module mod.com 121225- 121226-go 1.17 121227--- hi.tmpl -- 121228-{{if (foÜx .X.Y)}}{{$A := 121229- "hi" 121230- }}{{.Z $A}}{{else}} 121231-{{$A.X 12}} 121232-{{foo (.X.Y) 23 ($A.Z)}} 121233-{{end}} 121234-` 121235- WithOptions( 121236- Settings{ 121237- "templateExtensions": []string{"tmpl"}, 121238- "semanticTokens": true, 121239- }, 121240- ).Run(t, files, func(t *testing.T, env *Env) { 121241- var p protocol.SemanticTokensParams 121242- p.TextDocument.URI = env.Sandbox.Workdir.URI("hi.tmpl") 121243- toks, err := env.Editor.Server.SemanticTokensFull(env.Ctx, &p) 121244- if err != nil { 121245- t.Errorf("semantic token failed: %v", err) 121246- } 121247- if toks == nil || len(toks.Data) == 0 { 121248- t.Errorf("got no semantic tokens") 121249- } 121250- }) 121251-} 121252- 121253-func TestTemplatesFromExtensions(t *testing.T) { 121254- const files = ` 121255--- go.mod -- 121256-module mod.com 121257- 121258-go 1.12 121259--- hello.tmpl -- 121260-{{range .Planets}} 121261-Hello {{}} <-- missing body 121262-{{end}} 121263-` 121264- WithOptions( 121265- Settings{ 121266- "templateExtensions": []string{"tmpl"}, 121267- "semanticTokens": true, 121268- }, 121269- ).Run(t, files, func(t *testing.T, env *Env) { 121270- // TODO: can we move this diagnostic onto {{}}? 121271- var diags protocol.PublishDiagnosticsParams 121272- env.OnceMet( 121273- InitialWorkspaceLoad, 121274- Diagnostics(env.AtRegexp("hello.tmpl", "()Hello {{}}")), 121275- ReadDiagnostics("hello.tmpl", &diags), 121276- ) 121277- d := diags.Diagnostics // issue 50786: check for Source 121278- if len(d) != 1 { 121279- t.Errorf("expected 1 diagnostic, got %d", len(d)) 121280- return 121281- } 121282- if d[0].Source != "template" { 121283- t.Errorf("expected Source 'template', got %q", d[0].Source) 121284- } 121285- // issue 50801 (even broken templates could return some semantic tokens) 121286- var p protocol.SemanticTokensParams 121287- p.TextDocument.URI = env.Sandbox.Workdir.URI("hello.tmpl") 121288- toks, err := env.Editor.Server.SemanticTokensFull(env.Ctx, &p) 121289- if err != nil { 121290- t.Errorf("semantic token failed: %v", err) 121291- } 121292- if toks == nil || len(toks.Data) == 0 { 121293- t.Errorf("got no semantic tokens") 121294- } 121295- 121296- env.WriteWorkspaceFile("hello.tmpl", "{{range .Planets}}\nHello {{.}}\n{{end}}") 121297- env.AfterChange(NoDiagnostics(ForFile("hello.tmpl"))) 121298- }) 121299-} 121300- 121301-func TestTemplatesObserveDirectoryFilters(t *testing.T) { 121302- const files = ` 121303--- go.mod -- 121304-module mod.com 121305- 121306-go 1.12 121307--- a/a.tmpl -- 121308-A {{}} <-- missing body 121309--- b/b.tmpl -- 121310-B {{}} <-- missing body 121311-` 121312- 121313- WithOptions( 121314- Settings{ 121315- "directoryFilters": []string{"-b"}, 121316- "templateExtensions": []string{"tmpl"}, 121317- }, 121318- ).Run(t, files, func(t *testing.T, env *Env) { 121319- env.OnceMet( 121320- InitialWorkspaceLoad, 121321- Diagnostics(env.AtRegexp("a/a.tmpl", "()A")), 121322- NoDiagnostics(ForFile("b/b.tmpl")), 121323- ) 121324- }) 121325-} 121326- 121327-func TestTemplatesFromLangID(t *testing.T) { 121328- const files = ` 121329--- go.mod -- 121330-module mod.com 121331- 121332-go 1.12 121333-` 121334- 121335- Run(t, files, func(t *testing.T, env *Env) { 121336- env.CreateBuffer("hello.tmpl", "") 121337- env.AfterChange( 121338- NoDiagnostics(ForFile("hello.tmpl")), // Don't get spurious errors for empty templates. 121339- ) 121340- env.SetBufferContent("hello.tmpl", "{{range .Planets}}\nHello {{}}\n{{end}}") 121341- env.Await(Diagnostics(env.AtRegexp("hello.tmpl", "()Hello {{}}"))) 121342- env.RegexpReplace("hello.tmpl", "{{}}", "{{.}}") 121343- env.Await(NoDiagnostics(ForFile("hello.tmpl"))) 121344- }) 121345-} 121346- 121347-func TestClosingTemplatesMakesDiagnosticsDisappear(t *testing.T) { 121348- const files = ` 121349--- go.mod -- 121350-module mod.com 121351- 121352-go 1.12 121353--- hello.tmpl -- 121354-{{range .Planets}} 121355-Hello {{}} <-- missing body 121356-{{end}} 121357-` 121358- 121359- Run(t, files, func(t *testing.T, env *Env) { 121360- env.OpenFile("hello.tmpl") 121361- env.AfterChange( 121362- Diagnostics(env.AtRegexp("hello.tmpl", "()Hello {{}}")), 121363- ) 121364- // Since we don't have templateExtensions configured, closing hello.tmpl 121365- // should make its diagnostics disappear. 121366- env.CloseBuffer("hello.tmpl") 121367- env.AfterChange( 121368- NoDiagnostics(ForFile("hello.tmpl")), 121369- ) 121370- }) 121371-} 121372- 121373-func TestMultipleSuffixes(t *testing.T) { 121374- const files = ` 121375--- go.mod -- 121376-module mod.com 121377- 121378-go 1.12 121379--- b.gotmpl -- 121380-{{define "A"}}goo{{end}} 121381--- a.tmpl -- 121382-{{template "A"}} 121383-` 121384- 121385- WithOptions( 121386- Settings{ 121387- "templateExtensions": []string{"tmpl", "gotmpl"}, 121388- }, 121389- ).Run(t, files, func(t *testing.T, env *Env) { 121390- env.OpenFile("a.tmpl") 121391- x := env.RegexpSearch("a.tmpl", `A`) 121392- loc := env.GoToDefinition(x) 121393- refs := env.References(loc) 121394- if len(refs) != 2 { 121395- t.Fatalf("got %v reference(s), want 2", len(refs)) 121396- } 121397- // make sure we got one from b.gotmpl 121398- want := env.Sandbox.Workdir.URI("b.gotmpl") 121399- if refs[0].URI != want && refs[1].URI != want { 121400- t.Errorf("failed to find reference to %s", shorten(want)) 121401- for i, r := range refs { 121402- t.Logf("%d: URI:%s %v", i, shorten(r.URI), r.Range) 121403- } 121404- } 121405- 121406- content, nloc := env.Hover(loc) 121407- if loc != nloc { 121408- t.Errorf("loc? got %v, wanted %v", nloc, loc) 121409- } 121410- if content.Value != "template A defined" { 121411- t.Errorf("got %s, wanted 'template A defined", content.Value) 121412- } 121413- }) 121414-} 121415- 121416-// shorten long URIs 121417-func shorten(fn protocol.DocumentURI) string { 121418- if len(fn) <= 20 { 121419- return string(fn) 121420- } 121421- pieces := strings.Split(string(fn), "/") 121422- if len(pieces) < 2 { 121423- return string(fn) 121424- } 121425- j := len(pieces) 121426- return pieces[j-2] + "/" + pieces[j-1] 121427-} 121428- 121429-// Hover needs tests 121430diff -urN a/gopls/internal/regtest/watch/watch_test.go b/gopls/internal/regtest/watch/watch_test.go 121431--- a/gopls/internal/regtest/watch/watch_test.go 2000-01-01 00:00:00.000000000 -0000 121432+++ b/gopls/internal/regtest/watch/watch_test.go 1970-01-01 00:00:00.000000000 +0000 121433@@ -1,702 +0,0 @@ 121434-// Copyright 2020 The Go Authors. All rights reserved. 121435-// Use of this source code is governed by a BSD-style 121436-// license that can be found in the LICENSE file. 121437- 121438-package regtest 121439- 121440-import ( 121441- "testing" 121442- 121443- "golang.org/x/tools/gopls/internal/hooks" 121444- . "golang.org/x/tools/gopls/internal/lsp/regtest" 121445- "golang.org/x/tools/internal/bug" 121446- 121447- "golang.org/x/tools/gopls/internal/lsp/fake" 121448- "golang.org/x/tools/gopls/internal/lsp/protocol" 121449-) 121450- 121451-func TestMain(m *testing.M) { 121452- bug.PanicOnBugs = true 121453- Main(m, hooks.Options) 121454-} 121455- 121456-func TestEditFile(t *testing.T) { 121457- const pkg = ` 121458--- go.mod -- 121459-module mod.com 121460- 121461-go 1.14 121462--- a/a.go -- 121463-package a 121464- 121465-func _() { 121466- var x int 121467-} 121468-` 121469- // Edit the file when it's *not open* in the workspace, and check that 121470- // diagnostics are updated. 121471- t.Run("unopened", func(t *testing.T) { 121472- Run(t, pkg, func(t *testing.T, env *Env) { 121473- env.OnceMet( 121474- InitialWorkspaceLoad, 121475- Diagnostics(env.AtRegexp("a/a.go", "x")), 121476- ) 121477- env.WriteWorkspaceFile("a/a.go", `package a; func _() {};`) 121478- env.AfterChange( 121479- NoDiagnostics(ForFile("a/a.go")), 121480- ) 121481- }) 121482- }) 121483- 121484- // Edit the file when it *is open* in the workspace, and check that 121485- // diagnostics are *not* updated. 121486- t.Run("opened", func(t *testing.T) { 121487- Run(t, pkg, func(t *testing.T, env *Env) { 121488- env.OpenFile("a/a.go") 121489- // Insert a trivial edit so that we don't automatically update the buffer 121490- // (see CL 267577). 121491- env.EditBuffer("a/a.go", fake.NewEdit(0, 0, 0, 0, " ")) 121492- env.AfterChange() 121493- env.WriteWorkspaceFile("a/a.go", `package a; func _() {};`) 121494- env.AfterChange( 121495- Diagnostics(env.AtRegexp("a/a.go", "x")), 121496- ) 121497- }) 121498- }) 121499-} 121500- 121501-// Edit a dependency on disk and expect a new diagnostic. 121502-func TestEditDependency(t *testing.T) { 121503- const pkg = ` 121504--- go.mod -- 121505-module mod.com 121506- 121507-go 1.14 121508--- b/b.go -- 121509-package b 121510- 121511-func B() int { return 0 } 121512--- a/a.go -- 121513-package a 121514- 121515-import ( 121516- "mod.com/b" 121517-) 121518- 121519-func _() { 121520- _ = b.B() 121521-} 121522-` 121523- Run(t, pkg, func(t *testing.T, env *Env) { 121524- env.OpenFile("a/a.go") 121525- env.AfterChange() 121526- env.WriteWorkspaceFile("b/b.go", `package b; func B() {};`) 121527- env.AfterChange( 121528- Diagnostics(env.AtRegexp("a/a.go", "b.B")), 121529- ) 121530- }) 121531-} 121532- 121533-// Edit both the current file and one of its dependencies on disk and 121534-// expect diagnostic changes. 121535-func TestEditFileAndDependency(t *testing.T) { 121536- const pkg = ` 121537--- go.mod -- 121538-module mod.com 121539- 121540-go 1.14 121541--- b/b.go -- 121542-package b 121543- 121544-func B() int { return 0 } 121545--- a/a.go -- 121546-package a 121547- 121548-import ( 121549- "mod.com/b" 121550-) 121551- 121552-func _() { 121553- var x int 121554- _ = b.B() 121555-} 121556-` 121557- Run(t, pkg, func(t *testing.T, env *Env) { 121558- env.OnceMet( 121559- InitialWorkspaceLoad, 121560- Diagnostics(env.AtRegexp("a/a.go", "x")), 121561- ) 121562- env.WriteWorkspaceFiles(map[string]string{ 121563- "b/b.go": `package b; func B() {};`, 121564- "a/a.go": `package a 121565- 121566-import "mod.com/b" 121567- 121568-func _() { 121569- b.B() 121570-}`, 121571- }) 121572- env.AfterChange( 121573- NoDiagnostics(ForFile("a/a.go")), 121574- NoDiagnostics(ForFile("b/b.go")), 121575- ) 121576- }) 121577-} 121578- 121579-// Delete a dependency and expect a new diagnostic. 121580-func TestDeleteDependency(t *testing.T) { 121581- const pkg = ` 121582--- go.mod -- 121583-module mod.com 121584- 121585-go 1.14 121586--- b/b.go -- 121587-package b 121588- 121589-func B() int { return 0 } 121590--- a/a.go -- 121591-package a 121592- 121593-import ( 121594- "mod.com/b" 121595-) 121596- 121597-func _() { 121598- _ = b.B() 121599-} 121600-` 121601- Run(t, pkg, func(t *testing.T, env *Env) { 121602- env.OpenFile("a/a.go") 121603- env.AfterChange() 121604- env.RemoveWorkspaceFile("b/b.go") 121605- env.AfterChange( 121606- Diagnostics(env.AtRegexp("a/a.go", "\"mod.com/b\"")), 121607- ) 121608- }) 121609-} 121610- 121611-// Create a dependency on disk and expect the diagnostic to go away. 121612-func TestCreateDependency(t *testing.T) { 121613- const missing = ` 121614--- go.mod -- 121615-module mod.com 121616- 121617-go 1.14 121618--- b/b.go -- 121619-package b 121620- 121621-func B() int { return 0 } 121622--- a/a.go -- 121623-package a 121624- 121625-import ( 121626- "mod.com/c" 121627-) 121628- 121629-func _() { 121630- c.C() 121631-} 121632-` 121633- Run(t, missing, func(t *testing.T, env *Env) { 121634- env.OnceMet( 121635- InitialWorkspaceLoad, 121636- Diagnostics(env.AtRegexp("a/a.go", "\"mod.com/c\"")), 121637- ) 121638- env.WriteWorkspaceFile("c/c.go", `package c; func C() {};`) 121639- env.AfterChange( 121640- NoDiagnostics(ForFile("a/a.go")), 121641- ) 121642- }) 121643-} 121644- 121645-// Create a new dependency and add it to the file on disk. 121646-// This is similar to what might happen if you switch branches. 121647-func TestCreateAndAddDependency(t *testing.T) { 121648- const original = ` 121649--- go.mod -- 121650-module mod.com 121651- 121652-go 1.14 121653--- a/a.go -- 121654-package a 121655- 121656-func _() {} 121657-` 121658- Run(t, original, func(t *testing.T, env *Env) { 121659- env.WriteWorkspaceFile("c/c.go", `package c; func C() {};`) 121660- env.WriteWorkspaceFile("a/a.go", `package a; import "mod.com/c"; func _() { c.C() }`) 121661- env.AfterChange( 121662- NoDiagnostics(ForFile("a/a.go")), 121663- ) 121664- }) 121665-} 121666- 121667-// Create a new file that defines a new symbol, in the same package. 121668-func TestCreateFile(t *testing.T) { 121669- const pkg = ` 121670--- go.mod -- 121671-module mod.com 121672- 121673-go 1.14 121674--- a/a.go -- 121675-package a 121676- 121677-func _() { 121678- hello() 121679-} 121680-` 121681- Run(t, pkg, func(t *testing.T, env *Env) { 121682- env.OnceMet( 121683- InitialWorkspaceLoad, 121684- Diagnostics(env.AtRegexp("a/a.go", "hello")), 121685- ) 121686- env.WriteWorkspaceFile("a/a2.go", `package a; func hello() {};`) 121687- env.AfterChange( 121688- NoDiagnostics(ForFile("a/a.go")), 121689- ) 121690- }) 121691-} 121692- 121693-// Add a new method to an interface and implement it. 121694-// Inspired by the structure of internal/lsp/source and internal/lsp/cache. 121695-func TestCreateImplementation(t *testing.T) { 121696- const pkg = ` 121697--- go.mod -- 121698-module mod.com 121699- 121700-go 1.14 121701--- b/b.go -- 121702-package b 121703- 121704-type B interface{ 121705- Hello() string 121706-} 121707- 121708-func SayHello(bee B) { 121709- println(bee.Hello()) 121710-} 121711--- a/a.go -- 121712-package a 121713- 121714-import "mod.com/b" 121715- 121716-type X struct {} 121717- 121718-func (_ X) Hello() string { 121719- return "" 121720-} 121721- 121722-func _() { 121723- x := X{} 121724- b.SayHello(x) 121725-} 121726-` 121727- const newMethod = `package b 121728-type B interface{ 121729- Hello() string 121730- Bye() string 121731-} 121732- 121733-func SayHello(bee B) { 121734- println(bee.Hello()) 121735-}` 121736- const implementation = `package a 121737- 121738-import "mod.com/b" 121739- 121740-type X struct {} 121741- 121742-func (_ X) Hello() string { 121743- return "" 121744-} 121745- 121746-func (_ X) Bye() string { 121747- return "" 121748-} 121749- 121750-func _() { 121751- x := X{} 121752- b.SayHello(x) 121753-}` 121754- 121755- // Add the new method before the implementation. Expect diagnostics. 121756- t.Run("method before implementation", func(t *testing.T) { 121757- Run(t, pkg, func(t *testing.T, env *Env) { 121758- env.WriteWorkspaceFile("b/b.go", newMethod) 121759- env.AfterChange( 121760- Diagnostics(AtPosition("a/a.go", 12, 12)), 121761- ) 121762- env.WriteWorkspaceFile("a/a.go", implementation) 121763- env.AfterChange( 121764- NoDiagnostics(ForFile("a/a.go")), 121765- ) 121766- }) 121767- }) 121768- // Add the new implementation before the new method. Expect no diagnostics. 121769- t.Run("implementation before method", func(t *testing.T) { 121770- Run(t, pkg, func(t *testing.T, env *Env) { 121771- env.WriteWorkspaceFile("a/a.go", implementation) 121772- env.AfterChange( 121773- NoDiagnostics(ForFile("a/a.go")), 121774- ) 121775- env.WriteWorkspaceFile("b/b.go", newMethod) 121776- env.AfterChange( 121777- NoDiagnostics(ForFile("a/a.go")), 121778- ) 121779- }) 121780- }) 121781- // Add both simultaneously. Expect no diagnostics. 121782- t.Run("implementation and method simultaneously", func(t *testing.T) { 121783- Run(t, pkg, func(t *testing.T, env *Env) { 121784- env.WriteWorkspaceFiles(map[string]string{ 121785- "a/a.go": implementation, 121786- "b/b.go": newMethod, 121787- }) 121788- env.AfterChange( 121789- NoDiagnostics(ForFile("a/a.go")), 121790- NoDiagnostics(ForFile("b/b.go")), 121791- ) 121792- }) 121793- }) 121794-} 121795- 121796-// Tests golang/go#38498. Delete a file and then force a reload. 121797-// Assert that we no longer try to load the file. 121798-func TestDeleteFiles(t *testing.T) { 121799- const pkg = ` 121800--- go.mod -- 121801-module mod.com 121802- 121803-go 1.14 121804--- a/a.go -- 121805-package a 121806- 121807-func _() { 121808- var _ int 121809-} 121810--- a/a_unneeded.go -- 121811-package a 121812-` 121813- t.Run("close then delete", func(t *testing.T) { 121814- WithOptions( 121815- Settings{"verboseOutput": true}, 121816- ).Run(t, pkg, func(t *testing.T, env *Env) { 121817- env.OpenFile("a/a.go") 121818- env.OpenFile("a/a_unneeded.go") 121819- env.AfterChange( 121820- LogMatching(protocol.Info, "a_unneeded.go", 1, false), 121821- ) 121822- 121823- // Close and delete the open file, mimicking what an editor would do. 121824- env.CloseBuffer("a/a_unneeded.go") 121825- env.RemoveWorkspaceFile("a/a_unneeded.go") 121826- env.RegexpReplace("a/a.go", "var _ int", "fmt.Println(\"\")") 121827- env.AfterChange( 121828- Diagnostics(env.AtRegexp("a/a.go", "fmt")), 121829- ) 121830- env.SaveBuffer("a/a.go") 121831- env.AfterChange( 121832- // There should only be one log message containing 121833- // a_unneeded.go, from the initial workspace load, which we 121834- // check for earlier. If there are more, there's a bug. 121835- LogMatching(protocol.Info, "a_unneeded.go", 1, false), 121836- NoDiagnostics(ForFile("a/a.go")), 121837- ) 121838- }) 121839- }) 121840- 121841- t.Run("delete then close", func(t *testing.T) { 121842- WithOptions( 121843- Settings{"verboseOutput": true}, 121844- ).Run(t, pkg, func(t *testing.T, env *Env) { 121845- env.OpenFile("a/a.go") 121846- env.OpenFile("a/a_unneeded.go") 121847- env.AfterChange( 121848- LogMatching(protocol.Info, "a_unneeded.go", 1, false), 121849- ) 121850- 121851- // Delete and then close the file. 121852- env.RemoveWorkspaceFile("a/a_unneeded.go") 121853- env.CloseBuffer("a/a_unneeded.go") 121854- env.RegexpReplace("a/a.go", "var _ int", "fmt.Println(\"\")") 121855- env.AfterChange( 121856- Diagnostics(env.AtRegexp("a/a.go", "fmt")), 121857- ) 121858- env.SaveBuffer("a/a.go") 121859- env.AfterChange( 121860- // There should only be one log message containing 121861- // a_unneeded.go, from the initial workspace load, which we 121862- // check for earlier. If there are more, there's a bug. 121863- LogMatching(protocol.Info, "a_unneeded.go", 1, false), 121864- NoDiagnostics(ForFile("a/a.go")), 121865- ) 121866- }) 121867- }) 121868-} 121869- 121870-// This change reproduces the behavior of switching branches, with multiple 121871-// files being created and deleted. The key change here is the movement of a 121872-// symbol from one file to another in a given package through a deletion and 121873-// creation. To reproduce an issue with metadata invalidation in batched 121874-// changes, the last change in the batch is an on-disk file change that doesn't 121875-// require metadata invalidation. 121876-func TestMoveSymbol(t *testing.T) { 121877- const pkg = ` 121878--- go.mod -- 121879-module mod.com 121880- 121881-go 1.14 121882--- main.go -- 121883-package main 121884- 121885-import "mod.com/a" 121886- 121887-func main() { 121888- var x int 121889- x = a.Hello 121890- println(x) 121891-} 121892--- a/a1.go -- 121893-package a 121894- 121895-var Hello int 121896--- a/a2.go -- 121897-package a 121898- 121899-func _() {} 121900-` 121901- Run(t, pkg, func(t *testing.T, env *Env) { 121902- env.WriteWorkspaceFile("a/a3.go", "package a\n\nvar Hello int\n") 121903- env.RemoveWorkspaceFile("a/a1.go") 121904- env.WriteWorkspaceFile("a/a2.go", "package a; func _() {};") 121905- env.AfterChange( 121906- NoDiagnostics(ForFile("main.go")), 121907- ) 121908- }) 121909-} 121910- 121911-// Reproduce golang/go#40456. 121912-func TestChangeVersion(t *testing.T) { 121913- const proxy = ` 121914--- [email protected]/go.mod -- 121915-module example.com 121916- 121917-go 1.12 121918--- [email protected]/blah/blah.go -- 121919-package blah 121920- 121921-const Name = "Blah" 121922- 121923-func X(x int) {} 121924--- [email protected]/go.mod -- 121925-module example.com 121926- 121927-go 1.12 121928--- [email protected]/blah/blah.go -- 121929-package blah 121930- 121931-const Name = "Blah" 121932- 121933-func X() {} 121934--- [email protected]/go.mod -- 121935-module random.org 121936- 121937-go 1.12 121938--- [email protected]/blah/blah.go -- 121939-package hello 121940- 121941-const Name = "Hello" 121942-` 121943- const mod = ` 121944--- go.mod -- 121945-module mod.com 121946- 121947-go 1.12 121948- 121949-require example.com v1.2.2 121950--- go.sum -- 121951-example.com v1.2.3 h1:OnPPkx+rW63kj9pgILsu12MORKhSlnFa3DVRJq1HZ7g= 121952-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 121953--- main.go -- 121954-package main 121955- 121956-import "example.com/blah" 121957- 121958-func main() { 121959- blah.X() 121960-} 121961-` 121962- WithOptions(ProxyFiles(proxy)).Run(t, mod, func(t *testing.T, env *Env) { 121963- env.WriteWorkspaceFiles(map[string]string{ 121964- "go.mod": `module mod.com 121965- 121966-go 1.12 121967- 121968-require example.com v1.2.3 121969-`, 121970- "main.go": `package main 121971- 121972-import ( 121973- "example.com/blah" 121974-) 121975- 121976-func main() { 121977- blah.X(1) 121978-} 121979-`, 121980- }) 121981- env.AfterChange( 121982- env.DoneWithChangeWatchedFiles(), 121983- NoDiagnostics(ForFile("main.go")), 121984- ) 121985- }) 121986-} 121987- 121988-// Reproduces golang/go#40340. 121989-func TestSwitchFromGOPATHToModuleMode(t *testing.T) { 121990- const files = ` 121991--- foo/blah/blah.go -- 121992-package blah 121993- 121994-const Name = "" 121995--- main.go -- 121996-package main 121997- 121998-import "foo/blah" 121999- 122000-func main() { 122001- _ = blah.Name 122002-} 122003-` 122004- WithOptions( 122005- InGOPATH(), 122006- Modes(Default), // golang/go#57521: this test is temporarily failing in 'experimental' mode 122007- EnvVars{"GO111MODULE": "auto"}, 122008- ).Run(t, files, func(t *testing.T, env *Env) { 122009- env.OpenFile("main.go") 122010- env.AfterChange( 122011- NoDiagnostics(ForFile("main.go")), 122012- ) 122013- if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}, true); err != nil { 122014- t.Fatal(err) 122015- } 122016- 122017- // TODO(golang/go#57558, golang/go#57512): file watching is asynchronous, 122018- // and we must wait for the view to be reconstructed before touching 122019- // main.go, so that the new view "knows" about main.go. This is a bug, but 122020- // awaiting the change here avoids it. 122021- env.AfterChange() 122022- 122023- env.RegexpReplace("main.go", `"foo/blah"`, `"mod.com/foo/blah"`) 122024- env.AfterChange( 122025- NoDiagnostics(ForFile("main.go")), 122026- ) 122027- }) 122028-} 122029- 122030-// Reproduces golang/go#40487. 122031-func TestSwitchFromModulesToGOPATH(t *testing.T) { 122032- const files = ` 122033--- foo/go.mod -- 122034-module mod.com 122035- 122036-go 1.14 122037--- foo/blah/blah.go -- 122038-package blah 122039- 122040-const Name = "" 122041--- foo/main.go -- 122042-package main 122043- 122044-import "mod.com/blah" 122045- 122046-func main() { 122047- _ = blah.Name 122048-} 122049-` 122050- WithOptions( 122051- InGOPATH(), 122052- EnvVars{"GO111MODULE": "auto"}, 122053- ).Run(t, files, func(t *testing.T, env *Env) { 122054- env.OpenFile("foo/main.go") 122055- env.RemoveWorkspaceFile("foo/go.mod") 122056- env.AfterChange( 122057- Diagnostics(env.AtRegexp("foo/main.go", `"mod.com/blah"`)), 122058- ) 122059- env.RegexpReplace("foo/main.go", `"mod.com/blah"`, `"foo/blah"`) 122060- env.AfterChange( 122061- NoDiagnostics(ForFile("foo/main.go")), 122062- ) 122063- }) 122064-} 122065- 122066-func TestNewSymbolInTestVariant(t *testing.T) { 122067- const files = ` 122068--- go.mod -- 122069-module mod.com 122070- 122071-go 1.12 122072--- a/a.go -- 122073-package a 122074- 122075-func bob() {} 122076--- a/a_test.go -- 122077-package a 122078- 122079-import "testing" 122080- 122081-func TestBob(t *testing.T) { 122082- bob() 122083-} 122084-` 122085- Run(t, files, func(t *testing.T, env *Env) { 122086- // Add a new symbol to the package under test and use it in the test 122087- // variant. Expect no diagnostics. 122088- env.WriteWorkspaceFiles(map[string]string{ 122089- "a/a.go": `package a 122090- 122091-func bob() {} 122092-func george() {} 122093-`, 122094- "a/a_test.go": `package a 122095- 122096-import "testing" 122097- 122098-func TestAll(t *testing.T) { 122099- bob() 122100- george() 122101-} 122102-`, 122103- }) 122104- env.AfterChange( 122105- NoDiagnostics(ForFile("a/a.go")), 122106- NoDiagnostics(ForFile("a/a_test.go")), 122107- ) 122108- // Now, add a new file to the test variant and use its symbol in the 122109- // original test file. Expect no diagnostics. 122110- env.WriteWorkspaceFiles(map[string]string{ 122111- "a/a_test.go": `package a 122112- 122113-import "testing" 122114- 122115-func TestAll(t *testing.T) { 122116- bob() 122117- george() 122118- hi() 122119-} 122120-`, 122121- "a/a2_test.go": `package a 122122- 122123-import "testing" 122124- 122125-func hi() {} 122126- 122127-func TestSomething(t *testing.T) {} 122128-`, 122129- }) 122130- env.AfterChange( 122131- NoDiagnostics(ForFile("a/a_test.go")), 122132- NoDiagnostics(ForFile("a/a2_test.go")), 122133- ) 122134- }) 122135-} 122136diff -urN a/gopls/internal/regtest/workspace/broken_test.go b/gopls/internal/regtest/workspace/broken_test.go 122137--- a/gopls/internal/regtest/workspace/broken_test.go 2000-01-01 00:00:00.000000000 -0000 122138+++ b/gopls/internal/regtest/workspace/broken_test.go 1970-01-01 00:00:00.000000000 +0000 122139@@ -1,264 +0,0 @@ 122140-// Copyright 2022 The Go Authors. All rights reserved. 122141-// Use of this source code is governed by a BSD-style 122142-// license that can be found in the LICENSE file. 122143- 122144-package workspace 122145- 122146-import ( 122147- "strings" 122148- "testing" 122149- 122150- "golang.org/x/tools/gopls/internal/lsp" 122151- . "golang.org/x/tools/gopls/internal/lsp/regtest" 122152- "golang.org/x/tools/internal/testenv" 122153-) 122154- 122155-// This file holds various tests for UX with respect to broken workspaces. 122156-// 122157-// TODO: consolidate other tests here. 122158-// 122159-// TODO: write more tests: 122160-// - an explicit GOWORK value that doesn't exist 122161-// - using modules and/or GOWORK inside of GOPATH? 122162- 122163-// Test for golang/go#53933 122164-func TestBrokenWorkspace_DuplicateModules(t *testing.T) { 122165- testenv.NeedsGo1Point(t, 18) 122166- 122167- // TODO(golang/go#57650): fix this feature. 122168- t.Skip("we no longer detect duplicate modules") 122169- 122170- // This proxy module content is replaced by the workspace, but is still 122171- // required for module resolution to function in the Go command. 122172- const proxy = ` 122173--- example.com/foo@v0.0.1/go.mod -- 122174-module example.com/foo 122175- 122176-go 1.12 122177-` 122178- 122179- const src = ` 122180--- go.work -- 122181-go 1.18 122182- 122183-use ( 122184- ./package1 122185- ./package1/vendor/example.com/foo 122186- ./package2 122187- ./package2/vendor/example.com/foo 122188-) 122189- 122190--- package1/go.mod -- 122191-module mod.test 122192- 122193-go 1.18 122194- 122195-require example.com/foo v0.0.1 122196--- package1/main.go -- 122197-package main 122198- 122199-import "example.com/foo" 122200- 122201-func main() { 122202- _ = foo.CompleteMe 122203-} 122204--- package1/vendor/example.com/foo/go.mod -- 122205-module example.com/foo 122206- 122207-go 1.18 122208--- package1/vendor/example.com/foo/foo.go -- 122209-package foo 122210- 122211-const CompleteMe = 111 122212--- package2/go.mod -- 122213-module mod2.test 122214- 122215-go 1.18 122216- 122217-require example.com/foo v0.0.1 122218--- package2/main.go -- 122219-package main 122220- 122221-import "example.com/foo" 122222- 122223-func main() { 122224- _ = foo.CompleteMe 122225-} 122226--- package2/vendor/example.com/foo/go.mod -- 122227-module example.com/foo 122228- 122229-go 1.18 122230--- package2/vendor/example.com/foo/foo.go -- 122231-package foo 122232- 122233-const CompleteMe = 222 122234-` 122235- 122236- WithOptions( 122237- ProxyFiles(proxy), 122238- ).Run(t, src, func(t *testing.T, env *Env) { 122239- env.OpenFile("package1/main.go") 122240- env.Await( 122241- OutstandingWork(lsp.WorkspaceLoadFailure, `found module "example.com/foo" multiple times in the workspace`), 122242- ) 122243- 122244- // Remove the redundant vendored copy of example.com. 122245- env.WriteWorkspaceFile("go.work", `go 1.18 122246- use ( 122247- ./package1 122248- ./package2 122249- ./package2/vendor/example.com/foo 122250- ) 122251- `) 122252- env.Await(NoOutstandingWork()) 122253- 122254- // Check that definitions in package1 go to the copy vendored in package2. 122255- location := env.GoToDefinition(env.RegexpSearch("package1/main.go", "CompleteMe")).URI.SpanURI().Filename() 122256- const wantLocation = "package2/vendor/example.com/foo/foo.go" 122257- if !strings.HasSuffix(location, wantLocation) { 122258- t.Errorf("got definition of CompleteMe at %q, want %q", location, wantLocation) 122259- } 122260- }) 122261-} 122262- 122263-// Test for golang/go#43186: correcting the module path should fix errors 122264-// without restarting gopls. 122265-func TestBrokenWorkspace_WrongModulePath(t *testing.T) { 122266- const files = ` 122267--- go.mod -- 122268-module mod.testx 122269- 122270-go 1.18 122271--- p/internal/foo/foo.go -- 122272-package foo 122273- 122274-const C = 1 122275--- p/internal/bar/bar.go -- 122276-package bar 122277- 122278-import "mod.test/p/internal/foo" 122279- 122280-const D = foo.C + 1 122281--- p/internal/bar/bar_test.go -- 122282-package bar_test 122283- 122284-import ( 122285- "mod.test/p/internal/foo" 122286- . "mod.test/p/internal/bar" 122287-) 122288- 122289-const E = D + foo.C 122290--- p/internal/baz/baz_test.go -- 122291-package baz_test 122292- 122293-import ( 122294- named "mod.test/p/internal/bar" 122295-) 122296- 122297-const F = named.D - 3 122298-` 122299- 122300- Run(t, files, func(t *testing.T, env *Env) { 122301- env.OpenFile("p/internal/bar/bar.go") 122302- env.AfterChange( 122303- Diagnostics(env.AtRegexp("p/internal/bar/bar.go", "\"mod.test/p/internal/foo\"")), 122304- ) 122305- env.OpenFile("go.mod") 122306- env.RegexpReplace("go.mod", "mod.testx", "mod.test") 122307- env.SaveBuffer("go.mod") // saving triggers a reload 122308- env.AfterChange(NoDiagnostics()) 122309- }) 122310-} 122311- 122312-func TestMultipleModules_Warning(t *testing.T) { 122313- msgForVersion := func(ver int) string { 122314- if ver >= 18 { 122315- return `gopls was not able to find modules in your workspace.` 122316- } else { 122317- return `gopls requires a module at the root of your workspace.` 122318- } 122319- } 122320- 122321- const modules = ` 122322--- a/go.mod -- 122323-module a.com 122324- 122325-go 1.12 122326--- a/a.go -- 122327-package a 122328--- a/empty.go -- 122329-// an empty file 122330--- b/go.mod -- 122331-module b.com 122332- 122333-go 1.12 122334--- b/b.go -- 122335-package b 122336-` 122337- for _, go111module := range []string{"on", "auto"} { 122338- t.Run("GO111MODULE="+go111module, func(t *testing.T) { 122339- WithOptions( 122340- Modes(Default), 122341- EnvVars{"GO111MODULE": go111module}, 122342- ).Run(t, modules, func(t *testing.T, env *Env) { 122343- ver := env.GoVersion() 122344- msg := msgForVersion(ver) 122345- env.OpenFile("a/a.go") 122346- env.OpenFile("a/empty.go") 122347- env.OpenFile("b/go.mod") 122348- env.AfterChange( 122349- Diagnostics(env.AtRegexp("a/a.go", "package a")), 122350- Diagnostics(env.AtRegexp("b/go.mod", "module b.com")), 122351- OutstandingWork(lsp.WorkspaceLoadFailure, msg), 122352- ) 122353- 122354- // Changing the workspace folders to the valid modules should resolve 122355- // the workspace errors and diagnostics. 122356- // 122357- // TODO(rfindley): verbose work tracking doesn't follow changing the 122358- // workspace folder, therefore we can't invoke AfterChange here. 122359- env.ChangeWorkspaceFolders("a", "b") 122360- env.Await( 122361- NoDiagnostics(ForFile("a/a.go")), 122362- NoDiagnostics(ForFile("b/go.mod")), 122363- NoOutstandingWork(), 122364- ) 122365- 122366- env.ChangeWorkspaceFolders(".") 122367- 122368- // TODO(rfindley): when GO111MODULE=auto, we need to open or change a 122369- // file here in order to detect a critical error. This is because gopls 122370- // has forgotten about a/a.go, and therefore doesn't hit the heuristic 122371- // "all packages are command-line-arguments". 122372- // 122373- // This is broken, and could be fixed by adjusting the heuristic to 122374- // account for the scenario where there are *no* workspace packages, or 122375- // (better) trying to get workspace packages for each open file. See 122376- // also golang/go#54261. 122377- env.OpenFile("b/b.go") 122378- env.AfterChange( 122379- // TODO(rfindley): fix these missing diagnostics. 122380- // Diagnostics(env.AtRegexp("a/a.go", "package a")), 122381- // Diagnostics(env.AtRegexp("b/go.mod", "module b.com")), 122382- Diagnostics(env.AtRegexp("b/b.go", "package b")), 122383- OutstandingWork(lsp.WorkspaceLoadFailure, msg), 122384- ) 122385- }) 122386- }) 122387- } 122388- 122389- // Expect no warning if GO111MODULE=auto in a directory in GOPATH. 122390- t.Run("GOPATH_GO111MODULE_auto", func(t *testing.T) { 122391- WithOptions( 122392- Modes(Default), 122393- EnvVars{"GO111MODULE": "auto"}, 122394- InGOPATH(), 122395- ).Run(t, modules, func(t *testing.T, env *Env) { 122396- env.OpenFile("a/a.go") 122397- env.AfterChange( 122398- NoDiagnostics(ForFile("a/a.go")), 122399- NoOutstandingWork(), 122400- ) 122401- }) 122402- }) 122403-} 122404diff -urN a/gopls/internal/regtest/workspace/directoryfilters_test.go b/gopls/internal/regtest/workspace/directoryfilters_test.go 122405--- a/gopls/internal/regtest/workspace/directoryfilters_test.go 2000-01-01 00:00:00.000000000 -0000 122406+++ b/gopls/internal/regtest/workspace/directoryfilters_test.go 1970-01-01 00:00:00.000000000 +0000 122407@@ -1,259 +0,0 @@ 122408-// Copyright 2022 The Go Authors. All rights reserved. 122409-// Use of this source code is governed by a BSD-style 122410-// license that can be found in the LICENSE file. 122411- 122412-package workspace 122413- 122414-import ( 122415- "sort" 122416- "strings" 122417- "testing" 122418- 122419- . "golang.org/x/tools/gopls/internal/lsp/regtest" 122420- "golang.org/x/tools/internal/testenv" 122421-) 122422- 122423-// This file contains regression tests for the directoryFilters setting. 122424-// 122425-// TODO: 122426-// - consolidate some of these tests into a single test 122427-// - add more tests for changing directory filters 122428- 122429-func TestDirectoryFilters(t *testing.T) { 122430- WithOptions( 122431- ProxyFiles(workspaceProxy), 122432- WorkspaceFolders("pkg"), 122433- Settings{ 122434- "directoryFilters": []string{"-inner"}, 122435- }, 122436- ).Run(t, workspaceModule, func(t *testing.T, env *Env) { 122437- syms := env.Symbol("Hi") 122438- sort.Slice(syms, func(i, j int) bool { return syms[i].ContainerName < syms[j].ContainerName }) 122439- for _, s := range syms { 122440- if strings.Contains(s.ContainerName, "inner") { 122441- t.Errorf("WorkspaceSymbol: found symbol %q with container %q, want \"inner\" excluded", s.Name, s.ContainerName) 122442- } 122443- } 122444- }) 122445-} 122446- 122447-func TestDirectoryFiltersLoads(t *testing.T) { 122448- // exclude, and its error, should be excluded from the workspace. 122449- const files = ` 122450--- go.mod -- 122451-module example.com 122452- 122453-go 1.12 122454--- exclude/exclude.go -- 122455-package exclude 122456- 122457-const _ = Nonexistant 122458-` 122459- 122460- WithOptions( 122461- Settings{"directoryFilters": []string{"-exclude"}}, 122462- ).Run(t, files, func(t *testing.T, env *Env) { 122463- env.OnceMet( 122464- InitialWorkspaceLoad, 122465- NoDiagnostics(ForFile("exclude/x.go")), 122466- ) 122467- }) 122468-} 122469- 122470-func TestDirectoryFiltersTransitiveDep(t *testing.T) { 122471- // Even though exclude is excluded from the workspace, it should 122472- // still be importable as a non-workspace package. 122473- const files = ` 122474--- go.mod -- 122475-module example.com 122476- 122477-go 1.12 122478--- include/include.go -- 122479-package include 122480-import "example.com/exclude" 122481- 122482-const _ = exclude.X 122483--- exclude/exclude.go -- 122484-package exclude 122485- 122486-const _ = Nonexistant // should be ignored, since this is a non-workspace package 122487-const X = 1 122488-` 122489- 122490- WithOptions( 122491- Settings{"directoryFilters": []string{"-exclude"}}, 122492- ).Run(t, files, func(t *testing.T, env *Env) { 122493- env.OnceMet( 122494- InitialWorkspaceLoad, 122495- NoDiagnostics(ForFile("exclude/exclude.go")), // filtered out 122496- NoDiagnostics(ForFile("include/include.go")), // successfully builds 122497- ) 122498- }) 122499-} 122500- 122501-func TestDirectoryFiltersWorkspaceModules(t *testing.T) { 122502- // Define a module include.com which should be in the workspace, plus a 122503- // module exclude.com which should be excluded and therefore come from 122504- // the proxy. 122505- const files = ` 122506--- include/go.mod -- 122507-module include.com 122508- 122509-go 1.12 122510- 122511-require exclude.com v1.0.0 122512- 122513--- include/go.sum -- 122514-exclude.com v1.0.0 h1:Q5QSfDXY5qyNCBeUiWovUGqcLCRZKoTs9XdBeVz+w1I= 122515-exclude.com v1.0.0/go.mod h1:hFox2uDlNB2s2Jfd9tHlQVfgqUiLVTmh6ZKat4cvnj4= 122516- 122517--- include/include.go -- 122518-package include 122519- 122520-import "exclude.com" 122521- 122522-var _ = exclude.X // satisfied only by the workspace version 122523--- exclude/go.mod -- 122524-module exclude.com 122525- 122526-go 1.12 122527--- exclude/exclude.go -- 122528-package exclude 122529- 122530-const X = 1 122531-` 122532- const proxy = ` 122533--- [email protected]/go.mod -- 122534-module exclude.com 122535- 122536-go 1.12 122537--- [email protected]/exclude.go -- 122538-package exclude 122539-` 122540- WithOptions( 122541- Modes(Experimental), 122542- ProxyFiles(proxy), 122543- Settings{"directoryFilters": []string{"-exclude"}}, 122544- ).Run(t, files, func(t *testing.T, env *Env) { 122545- env.Await(Diagnostics(env.AtRegexp("include/include.go", `exclude.(X)`))) 122546- }) 122547-} 122548- 122549-// Test for golang/go#46438: support for '**' in directory filters. 122550-func TestDirectoryFilters_Wildcard(t *testing.T) { 122551- filters := []string{"-**/bye"} 122552- WithOptions( 122553- ProxyFiles(workspaceProxy), 122554- WorkspaceFolders("pkg"), 122555- Settings{ 122556- "directoryFilters": filters, 122557- }, 122558- ).Run(t, workspaceModule, func(t *testing.T, env *Env) { 122559- syms := env.Symbol("Bye") 122560- sort.Slice(syms, func(i, j int) bool { return syms[i].ContainerName < syms[j].ContainerName }) 122561- for _, s := range syms { 122562- if strings.Contains(s.ContainerName, "bye") { 122563- t.Errorf("WorkspaceSymbol: found symbol %q with container %q with filters %v", s.Name, s.ContainerName, filters) 122564- } 122565- } 122566- }) 122567-} 122568- 122569-// Test for golang/go#52993: wildcard directoryFilters should apply to 122570-// goimports scanning as well. 122571-func TestDirectoryFilters_ImportScanning(t *testing.T) { 122572- const files = ` 122573--- go.mod -- 122574-module mod.test 122575- 122576-go 1.12 122577--- main.go -- 122578-package main 122579- 122580-func main() { 122581- bye.Goodbye() 122582-} 122583--- p/bye/bye.go -- 122584-package bye 122585- 122586-func Goodbye() {} 122587-` 122588- 122589- WithOptions( 122590- Settings{ 122591- "directoryFilters": []string{"-**/bye"}, 122592- }, 122593- // This test breaks in 'Experimental' mode, because with 122594- // experimentalWorkspaceModule set we the goimports scan behaves 122595- // differently. 122596- // 122597- // Since this feature is going away (golang/go#52897), don't investigate. 122598- Modes(Default), 122599- ).Run(t, files, func(t *testing.T, env *Env) { 122600- env.OpenFile("main.go") 122601- beforeSave := env.BufferText("main.go") 122602- env.OrganizeImports("main.go") 122603- got := env.BufferText("main.go") 122604- if got != beforeSave { 122605- t.Errorf("after organizeImports code action, got modified buffer:\n%s", got) 122606- } 122607- }) 122608-} 122609- 122610-// Test for golang/go#52993: non-wildcard directoryFilters should still be 122611-// applied relative to the workspace folder, not the module root. 122612-func TestDirectoryFilters_MultiRootImportScanning(t *testing.T) { 122613- testenv.NeedsGo1Point(t, 18) // uses go.work 122614- 122615- const files = ` 122616--- go.work -- 122617-go 1.18 122618- 122619-use ( 122620- a 122621- b 122622-) 122623--- a/go.mod -- 122624-module mod1.test 122625- 122626-go 1.18 122627--- a/main.go -- 122628-package main 122629- 122630-func main() { 122631- hi.Hi() 122632-} 122633--- a/hi/hi.go -- 122634-package hi 122635- 122636-func Hi() {} 122637--- b/go.mod -- 122638-module mod2.test 122639- 122640-go 1.18 122641--- b/main.go -- 122642-package main 122643- 122644-func main() { 122645- hi.Hi() 122646-} 122647--- b/hi/hi.go -- 122648-package hi 122649- 122650-func Hi() {} 122651-` 122652- 122653- WithOptions( 122654- Settings{ 122655- "directoryFilters": []string{"-hi"}, // this test fails with -**/hi 122656- }, 122657- ).Run(t, files, func(t *testing.T, env *Env) { 122658- env.OpenFile("a/main.go") 122659- beforeSave := env.BufferText("a/main.go") 122660- env.OrganizeImports("a/main.go") 122661- got := env.BufferText("a/main.go") 122662- if got == beforeSave { 122663- t.Errorf("after organizeImports code action, got identical buffer:\n%s", got) 122664- } 122665- }) 122666-} 122667diff -urN a/gopls/internal/regtest/workspace/fromenv_test.go b/gopls/internal/regtest/workspace/fromenv_test.go 122668--- a/gopls/internal/regtest/workspace/fromenv_test.go 2000-01-01 00:00:00.000000000 -0000 122669+++ b/gopls/internal/regtest/workspace/fromenv_test.go 1970-01-01 00:00:00.000000000 +0000 122670@@ -1,68 +0,0 @@ 122671-// Copyright 2022 The Go Authors. All rights reserved. 122672-// Use of this source code is governed by a BSD-style 122673-// license that can be found in the LICENSE file. 122674- 122675-package workspace 122676- 122677-import ( 122678- "testing" 122679- 122680- . "golang.org/x/tools/gopls/internal/lsp/regtest" 122681- "golang.org/x/tools/internal/testenv" 122682-) 122683- 122684-// Test that setting go.work via environment variables or settings works. 122685-func TestUseGoWorkOutsideTheWorkspace(t *testing.T) { 122686- testenv.NeedsGo1Point(t, 18) 122687- const files = ` 122688--- work/a/go.mod -- 122689-module a.com 122690- 122691-go 1.12 122692--- work/a/a.go -- 122693-package a 122694--- work/b/go.mod -- 122695-module b.com 122696- 122697-go 1.12 122698--- work/b/b.go -- 122699-package b 122700- 122701-func _() { 122702- x := 1 // unused 122703-} 122704--- other/c/go.mod -- 122705-module c.com 122706- 122707-go 1.18 122708--- other/c/c.go -- 122709-package c 122710--- config/go.work -- 122711-go 1.18 122712- 122713-use ( 122714- $SANDBOX_WORKDIR/work/a 122715- $SANDBOX_WORKDIR/work/b 122716- $SANDBOX_WORKDIR/other/c 122717-) 122718-` 122719- 122720- WithOptions( 122721- WorkspaceFolders("work"), // use a nested workspace dir, so that GOWORK is outside the workspace 122722- EnvVars{"GOWORK": "$SANDBOX_WORKDIR/config/go.work"}, 122723- ).Run(t, files, func(t *testing.T, env *Env) { 122724- // When we have an explicit GOWORK set, we should get a file watch request. 122725- env.OnceMet( 122726- InitialWorkspaceLoad, 122727- FileWatchMatching(`other`), 122728- FileWatchMatching(`config.go\.work`), 122729- ) 122730- env.Await(FileWatchMatching(`config.go\.work`)) 122731- // Even though work/b is not open, we should get its diagnostics as it is 122732- // included in the workspace. 122733- env.OpenFile("work/a/a.go") 122734- env.AfterChange( 122735- Diagnostics(env.AtRegexp("work/b/b.go", "x := 1"), WithMessage("not used")), 122736- ) 122737- }) 122738-} 122739diff -urN a/gopls/internal/regtest/workspace/metadata_test.go b/gopls/internal/regtest/workspace/metadata_test.go 122740--- a/gopls/internal/regtest/workspace/metadata_test.go 2000-01-01 00:00:00.000000000 -0000 122741+++ b/gopls/internal/regtest/workspace/metadata_test.go 1970-01-01 00:00:00.000000000 +0000 122742@@ -1,181 +0,0 @@ 122743-// Copyright 2022 The Go Authors. All rights reserved. 122744-// Use of this source code is governed by a BSD-style 122745-// license that can be found in the LICENSE file. 122746- 122747-package workspace 122748- 122749-import ( 122750- "strings" 122751- "testing" 122752- 122753- . "golang.org/x/tools/gopls/internal/lsp/regtest" 122754- "golang.org/x/tools/internal/testenv" 122755-) 122756- 122757-// TODO(rfindley): move workspace tests related to metadata bugs into this 122758-// file. 122759- 122760-func TestFixImportDecl(t *testing.T) { 122761- const src = ` 122762--- go.mod -- 122763-module mod.test 122764- 122765-go 1.12 122766--- p.go -- 122767-package p 122768- 122769-import ( 122770- _ "fmt" 122771- 122772-const C = 42 122773-` 122774- 122775- Run(t, src, func(t *testing.T, env *Env) { 122776- env.OpenFile("p.go") 122777- env.RegexpReplace("p.go", "\"fmt\"", "\"fmt\"\n)") 122778- env.AfterChange( 122779- NoDiagnostics(ForFile("p.go")), 122780- ) 122781- }) 122782-} 122783- 122784-// Test that moving ignoring a file via build constraints causes diagnostics to 122785-// be resolved. 122786-func TestIgnoreFile(t *testing.T) { 122787- testenv.NeedsGo1Point(t, 17) // needs native overlays and support for go:build directives 122788- 122789- const src = ` 122790--- go.mod -- 122791-module mod.test 122792- 122793-go 1.12 122794--- foo.go -- 122795-package main 122796- 122797-func main() {} 122798--- bar.go -- 122799-package main 122800- 122801-func main() {} 122802- ` 122803- 122804- WithOptions( 122805- // TODO(golang/go#54180): we don't run in 'experimental' mode here, because 122806- // with "experimentalUseInvalidMetadata", this test fails because the 122807- // orphaned bar.go is diagnosed using stale metadata, and then not 122808- // re-diagnosed when new metadata arrives. 122809- // 122810- // We could fix this by re-running diagnostics after a load, but should 122811- // consider whether that is worthwhile. 122812- Modes(Default), 122813- ).Run(t, src, func(t *testing.T, env *Env) { 122814- env.OpenFile("foo.go") 122815- env.OpenFile("bar.go") 122816- env.OnceMet( 122817- env.DoneWithOpen(), 122818- Diagnostics(env.AtRegexp("foo.go", "func (main)")), 122819- Diagnostics(env.AtRegexp("bar.go", "func (main)")), 122820- ) 122821- 122822- // Ignore bar.go. This should resolve diagnostics. 122823- env.RegexpReplace("bar.go", "package main", "//go:build ignore\n\npackage main") 122824- 122825- // To make this test pass with experimentalUseInvalidMetadata, we could make 122826- // an arbitrary edit that invalidates the snapshot, at which point the 122827- // orphaned diagnostics will be invalidated. 122828- // 122829- // But of course, this should not be necessary: we should invalidate stale 122830- // information when fresh metadata arrives. 122831- // env.RegexpReplace("foo.go", "package main", "package main // test") 122832- env.AfterChange( 122833- NoDiagnostics(ForFile("foo.go")), 122834- NoDiagnostics(ForFile("bar.go")), 122835- ) 122836- 122837- // If instead of 'ignore' (which gopls treats as a standalone package) we 122838- // used a different build tag, we should get a warning about having no 122839- // packages for bar.go 122840- env.RegexpReplace("bar.go", "ignore", "excluded") 122841- env.AfterChange( 122842- Diagnostics(env.AtRegexp("bar.go", "package (main)"), WithMessage("No packages")), 122843- ) 122844- }) 122845-} 122846- 122847-func TestReinitializeRepeatedly(t *testing.T) { 122848- testenv.NeedsGo1Point(t, 18) // uses go.work 122849- 122850- const multiModule = ` 122851--- go.work -- 122852-go 1.18 122853- 122854-use ( 122855- moda/a 122856- modb 122857-) 122858--- moda/a/go.mod -- 122859-module a.com 122860- 122861-require b.com v1.2.3 122862--- moda/a/go.sum -- 122863-b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI= 122864-b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8= 122865--- moda/a/a.go -- 122866-package a 122867- 122868-import ( 122869- "b.com/b" 122870-) 122871- 122872-func main() { 122873- var x int 122874- _ = b.Hello() 122875- // AAA 122876-} 122877--- modb/go.mod -- 122878-module b.com 122879- 122880--- modb/b/b.go -- 122881-package b 122882- 122883-func Hello() int { 122884- var x int 122885-} 122886-` 122887- WithOptions( 122888- ProxyFiles(workspaceModuleProxy), 122889- Settings{ 122890- // For this test, we want workspace diagnostics to start immediately 122891- // during change processing. 122892- "diagnosticsDelay": "0", 122893- }, 122894- ).Run(t, multiModule, func(t *testing.T, env *Env) { 122895- env.OpenFile("moda/a/a.go") 122896- env.AfterChange() 122897- 122898- // This test verifies that we fully process workspace reinitialization 122899- // (which allows GOPROXY), even when the reinitialized snapshot is 122900- // invalidated by subsequent changes. 122901- // 122902- // First, update go.work to remove modb. This will cause reinitialization 122903- // to fetch b.com from the proxy. 122904- env.WriteWorkspaceFile("go.work", "go 1.18\nuse moda/a") 122905- // Next, wait for gopls to start processing the change. Because we've set 122906- // diagnosticsDelay to zero, this will start diagnosing the workspace (and 122907- // try to reinitialize on the snapshot context). 122908- env.Await(env.StartedChangeWatchedFiles()) 122909- // Finally, immediately make a file change to cancel the previous 122910- // operation. This is racy, but will usually cause initialization to be 122911- // canceled. 122912- env.RegexpReplace("moda/a/a.go", "AAA", "BBB") 122913- env.AfterChange() 122914- // Now, to satisfy a definition request, gopls will try to reload moda. But 122915- // without access to the proxy (because this is no longer a 122916- // reinitialization), this loading will fail. 122917- loc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 122918- got := env.Sandbox.Workdir.URIToPath(loc.URI) 122919- if want := "[email protected]/b/b.go"; !strings.HasSuffix(got, want) { 122920- t.Errorf("expected %s, got %v", want, got) 122921- } 122922- }) 122923-} 122924diff -urN a/gopls/internal/regtest/workspace/misspelling_test.go b/gopls/internal/regtest/workspace/misspelling_test.go 122925--- a/gopls/internal/regtest/workspace/misspelling_test.go 2000-01-01 00:00:00.000000000 -0000 122926+++ b/gopls/internal/regtest/workspace/misspelling_test.go 1970-01-01 00:00:00.000000000 +0000 122927@@ -1,80 +0,0 @@ 122928-// Copyright 2023 The Go Authors. All rights reserved. 122929-// Use of this source code is governed by a BSD-style 122930-// license that can be found in the LICENSE file. 122931- 122932-package workspace 122933- 122934-import ( 122935- "runtime" 122936- "testing" 122937- 122938- . "golang.org/x/tools/gopls/internal/lsp/regtest" 122939- "golang.org/x/tools/gopls/internal/lsp/tests/compare" 122940-) 122941- 122942-// Test for golang/go#57081. 122943-func TestFormattingMisspelledURI(t *testing.T) { 122944- if runtime.GOOS != "windows" && runtime.GOOS != "darwin" { 122945- t.Skip("golang/go#57081 only reproduces on case-insensitive filesystems.") 122946- } 122947- const files = ` 122948--- go.mod -- 122949-module mod.test 122950- 122951-go 1.19 122952--- foo.go -- 122953-package foo 122954- 122955-const C = 2 // extra space is intentional 122956-` 122957- 122958- Run(t, files, func(t *testing.T, env *Env) { 122959- env.OpenFile("Foo.go") 122960- env.FormatBuffer("Foo.go") 122961- want := env.BufferText("Foo.go") 122962- 122963- if want == "" { 122964- t.Fatalf("Foo.go is empty") 122965- } 122966- 122967- // In golang/go#57081, we observed that if overlay cases don't match, gopls 122968- // will find (and format) the on-disk contents rather than the overlay, 122969- // resulting in invalid edits. 122970- // 122971- // Verify that this doesn't happen, by confirming that formatting is 122972- // idempotent. 122973- env.FormatBuffer("Foo.go") 122974- got := env.BufferText("Foo.go") 122975- if diff := compare.Text(want, got); diff != "" { 122976- t.Errorf("invalid content after second formatting:\n%s", diff) 122977- } 122978- }) 122979-} 122980- 122981-// Test that we can find packages for open files with different spelling on 122982-// case-insensitive file systems. 122983-func TestPackageForMisspelledURI(t *testing.T) { 122984- t.Skip("golang/go#57081: this test fails because the Go command does not load Foo.go correctly") 122985- if runtime.GOOS != "windows" && runtime.GOOS != "darwin" { 122986- t.Skip("golang/go#57081 only reproduces on case-insensitive filesystems.") 122987- } 122988- const files = ` 122989--- go.mod -- 122990-module mod.test 122991- 122992-go 1.19 122993--- foo.go -- 122994-package foo 122995- 122996-const C = D 122997--- bar.go -- 122998-package foo 122999- 123000-const D = 2 123001-` 123002- 123003- Run(t, files, func(t *testing.T, env *Env) { 123004- env.OpenFile("Foo.go") 123005- env.AfterChange(NoDiagnostics()) 123006- }) 123007-} 123008diff -urN a/gopls/internal/regtest/workspace/standalone_test.go b/gopls/internal/regtest/workspace/standalone_test.go 123009--- a/gopls/internal/regtest/workspace/standalone_test.go 2000-01-01 00:00:00.000000000 -0000 123010+++ b/gopls/internal/regtest/workspace/standalone_test.go 1970-01-01 00:00:00.000000000 +0000 123011@@ -1,206 +0,0 @@ 123012-// Copyright 2022 The Go Authors. All rights reserved. 123013-// Use of this source code is governed by a BSD-style 123014-// license that can be found in the LICENSE file. 123015- 123016-package workspace 123017- 123018-import ( 123019- "sort" 123020- "testing" 123021- 123022- "github.com/google/go-cmp/cmp" 123023- "golang.org/x/tools/gopls/internal/lsp/protocol" 123024- . "golang.org/x/tools/gopls/internal/lsp/regtest" 123025-) 123026- 123027-func TestStandaloneFiles(t *testing.T) { 123028- const files = ` 123029--- go.mod -- 123030-module mod.test 123031- 123032-go 1.16 123033--- lib/lib.go -- 123034-package lib 123035- 123036-const C = 0 123037- 123038-type I interface { 123039- M() 123040-} 123041--- lib/ignore.go -- 123042-//go:build ignore 123043-// +build ignore 123044- 123045-package main 123046- 123047-import ( 123048- "mod.test/lib" 123049-) 123050- 123051-const C = 1 123052- 123053-type Mer struct{} 123054-func (Mer) M() 123055- 123056-func main() { 123057- println(lib.C + C) 123058-} 123059-` 123060- WithOptions( 123061- // On Go 1.17 and earlier, this test fails with 123062- // experimentalWorkspaceModule. Not investigated, as 123063- // experimentalWorkspaceModule will be removed. 123064- Modes(Default), 123065- ).Run(t, files, func(t *testing.T, env *Env) { 123066- // Initially, gopls should not know about the standalone file as it hasn't 123067- // been opened. Therefore, we should only find one symbol 'C'. 123068- syms := env.Symbol("C") 123069- if got, want := len(syms), 1; got != want { 123070- t.Errorf("got %d symbols, want %d", got, want) 123071- } 123072- 123073- // Similarly, we should only find one reference to "C", and no 123074- // implementations of I. 123075- checkLocations := func(method string, gotLocations []protocol.Location, wantFiles ...string) { 123076- var gotFiles []string 123077- for _, l := range gotLocations { 123078- gotFiles = append(gotFiles, env.Sandbox.Workdir.URIToPath(l.URI)) 123079- } 123080- sort.Strings(gotFiles) 123081- sort.Strings(wantFiles) 123082- if diff := cmp.Diff(wantFiles, gotFiles); diff != "" { 123083- t.Errorf("%s(...): unexpected locations (-want +got):\n%s", method, diff) 123084- } 123085- } 123086- 123087- env.OpenFile("lib/lib.go") 123088- env.AfterChange(NoDiagnostics()) 123089- 123090- // Replacing C with D should not cause any workspace diagnostics, since we 123091- // haven't yet opened the standalone file. 123092- env.RegexpReplace("lib/lib.go", "C", "D") 123093- env.AfterChange(NoDiagnostics()) 123094- env.RegexpReplace("lib/lib.go", "D", "C") 123095- env.AfterChange(NoDiagnostics()) 123096- 123097- refs := env.References(env.RegexpSearch("lib/lib.go", "C")) 123098- checkLocations("References", refs, "lib/lib.go") 123099- 123100- impls := env.Implementations(env.RegexpSearch("lib/lib.go", "I")) 123101- checkLocations("Implementations", impls) // no implementations 123102- 123103- // Opening the standalone file should not result in any diagnostics. 123104- env.OpenFile("lib/ignore.go") 123105- env.AfterChange(NoDiagnostics()) 123106- 123107- // Having opened the standalone file, we should find its symbols in the 123108- // workspace. 123109- syms = env.Symbol("C") 123110- if got, want := len(syms), 2; got != want { 123111- t.Fatalf("got %d symbols, want %d", got, want) 123112- } 123113- 123114- foundMainC := false 123115- var symNames []string 123116- for _, sym := range syms { 123117- symNames = append(symNames, sym.Name) 123118- if sym.Name == "main.C" { 123119- foundMainC = true 123120- } 123121- } 123122- if !foundMainC { 123123- t.Errorf("WorkspaceSymbol(\"C\") = %v, want containing main.C", symNames) 123124- } 123125- 123126- // We should resolve workspace definitions in the standalone file. 123127- fileLoc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "lib.(C)")) 123128- file := env.Sandbox.Workdir.URIToPath(fileLoc.URI) 123129- if got, want := file, "lib/lib.go"; got != want { 123130- t.Errorf("GoToDefinition(lib.C) = %v, want %v", got, want) 123131- } 123132- 123133- // ...as well as intra-file definitions 123134- loc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "\\+ (C)")) 123135- wantLoc := env.RegexpSearch("lib/ignore.go", "const (C)") 123136- if loc != wantLoc { 123137- t.Errorf("GoToDefinition(C) = %v, want %v", loc, wantLoc) 123138- } 123139- 123140- // Renaming "lib.C" to "lib.D" should cause a diagnostic in the standalone 123141- // file. 123142- env.RegexpReplace("lib/lib.go", "C", "D") 123143- env.AfterChange(Diagnostics(env.AtRegexp("lib/ignore.go", "lib.(C)"))) 123144- 123145- // Undoing the replacement should fix diagnostics 123146- env.RegexpReplace("lib/lib.go", "D", "C") 123147- env.AfterChange(NoDiagnostics()) 123148- 123149- // Now that our workspace has no errors, we should be able to find 123150- // references and rename. 123151- refs = env.References(env.RegexpSearch("lib/lib.go", "C")) 123152- checkLocations("References", refs, "lib/lib.go", "lib/ignore.go") 123153- 123154- impls = env.Implementations(env.RegexpSearch("lib/lib.go", "I")) 123155- checkLocations("Implementations", impls, "lib/ignore.go") 123156- 123157- // Renaming should rename in the standalone package. 123158- env.Rename(env.RegexpSearch("lib/lib.go", "C"), "D") 123159- env.RegexpSearch("lib/ignore.go", "lib.D") 123160- }) 123161-} 123162- 123163-func TestStandaloneFiles_Configuration(t *testing.T) { 123164- const files = ` 123165--- go.mod -- 123166-module mod.test 123167- 123168-go 1.18 123169--- lib.go -- 123170-package lib // without this package, files are loaded as command-line-arguments 123171--- ignore.go -- 123172-//go:build ignore 123173-// +build ignore 123174- 123175-package main 123176- 123177-// An arbitrary comment. 123178- 123179-func main() {} 123180--- standalone.go -- 123181-//go:build standalone 123182-// +build standalone 123183- 123184-package main 123185- 123186-func main() {} 123187-` 123188- 123189- WithOptions( 123190- Settings{ 123191- "standaloneTags": []string{"standalone", "script"}, 123192- }, 123193- ).Run(t, files, func(t *testing.T, env *Env) { 123194- env.OpenFile("ignore.go") 123195- env.OpenFile("standalone.go") 123196- 123197- env.AfterChange( 123198- Diagnostics(env.AtRegexp("ignore.go", "package (main)")), 123199- NoDiagnostics(ForFile("standalone.go")), 123200- ) 123201- 123202- cfg := env.Editor.Config() 123203- cfg.Settings = map[string]interface{}{ 123204- "standaloneTags": []string{"ignore"}, 123205- } 123206- env.ChangeConfiguration(cfg) 123207- 123208- // TODO(golang/go#56158): gopls does not purge previously published 123209- // diagnostice when configuration changes. 123210- env.RegexpReplace("ignore.go", "arbitrary", "meaningless") 123211- 123212- env.AfterChange( 123213- NoDiagnostics(ForFile("ignore.go")), 123214- Diagnostics(env.AtRegexp("standalone.go", "package (main)")), 123215- ) 123216- }) 123217-} 123218diff -urN a/gopls/internal/regtest/workspace/workspace_test.go b/gopls/internal/regtest/workspace/workspace_test.go 123219--- a/gopls/internal/regtest/workspace/workspace_test.go 2000-01-01 00:00:00.000000000 -0000 123220+++ b/gopls/internal/regtest/workspace/workspace_test.go 1970-01-01 00:00:00.000000000 +0000 123221@@ -1,1263 +0,0 @@ 123222-// Copyright 2020 The Go Authors. All rights reserved. 123223-// Use of this source code is governed by a BSD-style 123224-// license that can be found in the LICENSE file. 123225- 123226-package workspace 123227- 123228-import ( 123229- "context" 123230- "fmt" 123231- "path/filepath" 123232- "strings" 123233- "testing" 123234- 123235- "golang.org/x/tools/gopls/internal/hooks" 123236- "golang.org/x/tools/gopls/internal/lsp" 123237- "golang.org/x/tools/gopls/internal/lsp/fake" 123238- "golang.org/x/tools/gopls/internal/lsp/protocol" 123239- "golang.org/x/tools/internal/bug" 123240- "golang.org/x/tools/internal/gocommand" 123241- "golang.org/x/tools/internal/testenv" 123242- 123243- . "golang.org/x/tools/gopls/internal/lsp/regtest" 123244-) 123245- 123246-func TestMain(m *testing.M) { 123247- bug.PanicOnBugs = true 123248- Main(m, hooks.Options) 123249-} 123250- 123251-const workspaceProxy = ` 123252--- [email protected]/go.mod -- 123253-module example.com 123254- 123255-go 1.12 123256--- [email protected]/blah/blah.go -- 123257-package blah 123258- 123259-import "fmt" 123260- 123261-func SaySomething() { 123262- fmt.Println("something") 123263-} 123264--- [email protected]/go.mod -- 123265-module random.org 123266- 123267-go 1.12 123268--- [email protected]/bye/bye.go -- 123269-package bye 123270- 123271-func Goodbye() { 123272- println("Bye") 123273-} 123274-` 123275- 123276-// TODO: Add a replace directive. 123277-const workspaceModule = ` 123278--- pkg/go.mod -- 123279-module mod.com 123280- 123281-go 1.14 123282- 123283-require ( 123284- example.com v1.2.3 123285- random.org v1.2.3 123286-) 123287--- pkg/go.sum -- 123288-example.com v1.2.3 h1:veRD4tUnatQRgsULqULZPjeoBGFr2qBhevSCZllD2Ds= 123289-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 123290-random.org v1.2.3 h1:+JE2Fkp7gS0zsHXGEQJ7hraom3pNTlkxC4b2qPfA+/Q= 123291-random.org v1.2.3/go.mod h1:E9KM6+bBX2g5ykHZ9H27w16sWo3QwgonyjM44Dnej3I= 123292--- pkg/main.go -- 123293-package main 123294- 123295-import ( 123296- "example.com/blah" 123297- "mod.com/inner" 123298- "random.org/bye" 123299-) 123300- 123301-func main() { 123302- blah.SaySomething() 123303- inner.Hi() 123304- bye.Goodbye() 123305-} 123306--- pkg/main2.go -- 123307-package main 123308- 123309-import "fmt" 123310- 123311-func _() { 123312- fmt.Print("%s") 123313-} 123314--- pkg/inner/inner.go -- 123315-package inner 123316- 123317-import "example.com/blah" 123318- 123319-func Hi() { 123320- blah.SaySomething() 123321-} 123322--- goodbye/bye/bye.go -- 123323-package bye 123324- 123325-func Bye() {} 123326--- goodbye/go.mod -- 123327-module random.org 123328- 123329-go 1.12 123330-` 123331- 123332-// Confirm that find references returns all of the references in the module, 123333-// regardless of what the workspace root is. 123334-func TestReferences(t *testing.T) { 123335- for _, tt := range []struct { 123336- name, rootPath string 123337- }{ 123338- { 123339- name: "module root", 123340- rootPath: "pkg", 123341- }, 123342- { 123343- name: "subdirectory", 123344- rootPath: "pkg/inner", 123345- }, 123346- } { 123347- t.Run(tt.name, func(t *testing.T) { 123348- opts := []RunOption{ProxyFiles(workspaceProxy)} 123349- if tt.rootPath != "" { 123350- opts = append(opts, WorkspaceFolders(tt.rootPath)) 123351- } 123352- WithOptions(opts...).Run(t, workspaceModule, func(t *testing.T, env *Env) { 123353- f := "pkg/inner/inner.go" 123354- env.OpenFile(f) 123355- locations := env.References(env.RegexpSearch(f, `SaySomething`)) 123356- want := 3 123357- if got := len(locations); got != want { 123358- t.Fatalf("expected %v locations, got %v", want, got) 123359- } 123360- }) 123361- }) 123362- } 123363-} 123364- 123365-// Make sure that analysis diagnostics are cleared for the whole package when 123366-// the only opened file is closed. This test was inspired by the experience in 123367-// VS Code, where clicking on a reference result triggers a 123368-// textDocument/didOpen without a corresponding textDocument/didClose. 123369-func TestClearAnalysisDiagnostics(t *testing.T) { 123370- WithOptions( 123371- ProxyFiles(workspaceProxy), 123372- WorkspaceFolders("pkg/inner"), 123373- ).Run(t, workspaceModule, func(t *testing.T, env *Env) { 123374- env.OpenFile("pkg/main.go") 123375- env.AfterChange( 123376- Diagnostics(env.AtRegexp("pkg/main2.go", "fmt.Print")), 123377- ) 123378- env.CloseBuffer("pkg/main.go") 123379- env.AfterChange( 123380- NoDiagnostics(ForFile("pkg/main2.go")), 123381- ) 123382- }) 123383-} 123384- 123385-// TestReloadOnlyOnce checks that changes to the go.mod file do not result in 123386-// redundant package loads (golang/go#54473). 123387-// 123388-// Note that this test may be fragile, as it depends on specific structure to 123389-// log messages around reinitialization. Nevertheless, it is important for 123390-// guarding against accidentally duplicate reloading. 123391-func TestReloadOnlyOnce(t *testing.T) { 123392- WithOptions( 123393- ProxyFiles(workspaceProxy), 123394- WorkspaceFolders("pkg"), 123395- ).Run(t, workspaceModule, func(t *testing.T, env *Env) { 123396- dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename() 123397- goModWithReplace := fmt.Sprintf(`%s 123398-replace random.org => %s 123399-`, env.ReadWorkspaceFile("pkg/go.mod"), dir) 123400- env.WriteWorkspaceFile("pkg/go.mod", goModWithReplace) 123401- env.AfterChange( 123402- LogMatching(protocol.Info, `packages\.Load #\d+\n`, 2, false), 123403- ) 123404- }) 123405-} 123406- 123407-// This test checks that gopls updates the set of files it watches when a 123408-// replace target is added to the go.mod. 123409-func TestWatchReplaceTargets(t *testing.T) { 123410- t.Skipf("skipping known-flaky test: see https://go.dev/issue/50748") 123411- 123412- WithOptions( 123413- ProxyFiles(workspaceProxy), 123414- WorkspaceFolders("pkg"), 123415- ).Run(t, workspaceModule, func(t *testing.T, env *Env) { 123416- // Add a replace directive and expect the files that gopls is watching 123417- // to change. 123418- dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename() 123419- goModWithReplace := fmt.Sprintf(`%s 123420-replace random.org => %s 123421-`, env.ReadWorkspaceFile("pkg/go.mod"), dir) 123422- env.WriteWorkspaceFile("pkg/go.mod", goModWithReplace) 123423- env.AfterChange( 123424- UnregistrationMatching("didChangeWatchedFiles"), 123425- RegistrationMatching("didChangeWatchedFiles"), 123426- ) 123427- }) 123428-} 123429- 123430-const workspaceModuleProxy = ` 123431--- [email protected]/go.mod -- 123432-module example.com 123433- 123434-go 1.12 123435--- [email protected]/blah/blah.go -- 123436-package blah 123437- 123438-import "fmt" 123439- 123440-func SaySomething() { 123441- fmt.Println("something") 123442-} 123443--- [email protected]/go.mod -- 123444-module b.com 123445- 123446-go 1.12 123447--- [email protected]/b/b.go -- 123448-package b 123449- 123450-func Hello() {} 123451-` 123452- 123453-func TestAutomaticWorkspaceModule_Interdependent(t *testing.T) { 123454- testenv.NeedsGo1Point(t, 18) // uses go.work 123455- const multiModule = ` 123456--- moda/a/go.mod -- 123457-module a.com 123458- 123459-require b.com v1.2.3 123460--- moda/a/go.sum -- 123461-b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI= 123462-b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8= 123463--- moda/a/a.go -- 123464-package a 123465- 123466-import ( 123467- "b.com/b" 123468-) 123469- 123470-func main() { 123471- var x int 123472- _ = b.Hello() 123473-} 123474--- modb/go.mod -- 123475-module b.com 123476- 123477--- modb/b/b.go -- 123478-package b 123479- 123480-func Hello() int { 123481- var x int 123482-} 123483-` 123484- WithOptions( 123485- ProxyFiles(workspaceModuleProxy), 123486- ).Run(t, multiModule, func(t *testing.T, env *Env) { 123487- env.RunGoCommand("work", "init") 123488- env.RunGoCommand("work", "use", "-r", ".") 123489- env.AfterChange( 123490- Diagnostics(env.AtRegexp("moda/a/a.go", "x")), 123491- Diagnostics(env.AtRegexp("modb/b/b.go", "x")), 123492- NoDiagnostics(env.AtRegexp("moda/a/a.go", `"b.com/b"`)), 123493- ) 123494- }) 123495-} 123496- 123497-func TestModuleWithExclude(t *testing.T) { 123498- const proxy = ` 123499--- [email protected]/go.mod -- 123500-module c.com 123501- 123502-go 1.12 123503- 123504-require b.com v1.2.3 123505--- [email protected]/blah/blah.go -- 123506-package blah 123507- 123508-import "fmt" 123509- 123510-func SaySomething() { 123511- fmt.Println("something") 123512-} 123513--- [email protected]/go.mod -- 123514-module b.com 123515- 123516-go 1.12 123517--- [email protected]/b/b.go -- 123518-package b 123519- 123520-func Hello() {} 123521--- [email protected]/go.mod -- 123522-module b.com 123523- 123524-go 1.12 123525-` 123526- const multiModule = ` 123527--- go.mod -- 123528-module a.com 123529- 123530-require c.com v1.2.3 123531- 123532-exclude b.com v1.2.3 123533--- go.sum -- 123534-c.com v1.2.3 h1:n07Dz9fYmpNqvZMwZi5NEqFcSHbvLa9lacMX+/g25tw= 123535-c.com v1.2.3/go.mod h1:/4TyYgU9Nu5tA4NymP5xyqE8R2VMzGD3TbJCwCOvHAg= 123536--- main.go -- 123537-package a 123538- 123539-func main() { 123540- var x int 123541-} 123542-` 123543- WithOptions( 123544- ProxyFiles(proxy), 123545- ).Run(t, multiModule, func(t *testing.T, env *Env) { 123546- env.OnceMet( 123547- InitialWorkspaceLoad, 123548- Diagnostics(env.AtRegexp("main.go", "x")), 123549- ) 123550- }) 123551-} 123552- 123553-// This change tests that the version of the module used changes after it has 123554-// been deleted from the workspace. 123555-// 123556-// TODO(golang/go#55331): delete this placeholder along with experimental 123557-// workspace module. 123558-func TestDeleteModule_Interdependent(t *testing.T) { 123559- testenv.NeedsGo1Point(t, 18) // uses go.work 123560- const multiModule = ` 123561--- go.work -- 123562-go 1.18 123563- 123564-use ( 123565- moda/a 123566- modb 123567-) 123568--- moda/a/go.mod -- 123569-module a.com 123570- 123571-require b.com v1.2.3 123572--- moda/a/go.sum -- 123573-b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI= 123574-b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8= 123575--- moda/a/a.go -- 123576-package a 123577- 123578-import ( 123579- "b.com/b" 123580-) 123581- 123582-func main() { 123583- var x int 123584- _ = b.Hello() 123585-} 123586--- modb/go.mod -- 123587-module b.com 123588- 123589--- modb/b/b.go -- 123590-package b 123591- 123592-func Hello() int { 123593- var x int 123594-} 123595-` 123596- WithOptions( 123597- ProxyFiles(workspaceModuleProxy), 123598- ).Run(t, multiModule, func(t *testing.T, env *Env) { 123599- env.OpenFile("moda/a/a.go") 123600- env.Await(env.DoneWithOpen()) 123601- 123602- originalLoc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 123603- original := env.Sandbox.Workdir.URIToPath(originalLoc.URI) 123604- if want := "modb/b/b.go"; !strings.HasSuffix(original, want) { 123605- t.Errorf("expected %s, got %v", want, original) 123606- } 123607- env.CloseBuffer(original) 123608- env.AfterChange() 123609- 123610- env.RemoveWorkspaceFile("modb/b/b.go") 123611- env.RemoveWorkspaceFile("modb/go.mod") 123612- env.WriteWorkspaceFile("go.work", "go 1.18\nuse moda/a") 123613- env.AfterChange() 123614- 123615- gotLoc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 123616- got := env.Sandbox.Workdir.URIToPath(gotLoc.URI) 123617- if want := "[email protected]/b/b.go"; !strings.HasSuffix(got, want) { 123618- t.Errorf("expected %s, got %v", want, got) 123619- } 123620- }) 123621-} 123622- 123623-// Tests that the version of the module used changes after it has been added 123624-// to the workspace. 123625-func TestCreateModule_Interdependent(t *testing.T) { 123626- testenv.NeedsGo1Point(t, 18) // uses go.work 123627- const multiModule = ` 123628--- go.work -- 123629-go 1.18 123630- 123631-use ( 123632- moda/a 123633-) 123634--- moda/a/go.mod -- 123635-module a.com 123636- 123637-require b.com v1.2.3 123638--- moda/a/go.sum -- 123639-b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI= 123640-b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8= 123641--- moda/a/a.go -- 123642-package a 123643- 123644-import ( 123645- "b.com/b" 123646-) 123647- 123648-func main() { 123649- var x int 123650- _ = b.Hello() 123651-} 123652-` 123653- WithOptions( 123654- ProxyFiles(workspaceModuleProxy), 123655- ).Run(t, multiModule, func(t *testing.T, env *Env) { 123656- env.OpenFile("moda/a/a.go") 123657- loc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 123658- original := env.Sandbox.Workdir.URIToPath(loc.URI) 123659- if want := "[email protected]/b/b.go"; !strings.HasSuffix(original, want) { 123660- t.Errorf("expected %s, got %v", want, original) 123661- } 123662- env.CloseBuffer(original) 123663- env.WriteWorkspaceFiles(map[string]string{ 123664- "go.work": `go 1.18 123665- 123666-use ( 123667- moda/a 123668- modb 123669-) 123670-`, 123671- "modb/go.mod": "module b.com", 123672- "modb/b/b.go": `package b 123673- 123674-func Hello() int { 123675- var x int 123676-} 123677-`, 123678- }) 123679- env.AfterChange(Diagnostics(env.AtRegexp("modb/b/b.go", "x"))) 123680- gotLoc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 123681- got := env.Sandbox.Workdir.URIToPath(gotLoc.URI) 123682- if want := "modb/b/b.go"; !strings.HasSuffix(got, want) { 123683- t.Errorf("expected %s, got %v", want, original) 123684- } 123685- }) 123686-} 123687- 123688-// This test confirms that a gopls workspace can recover from initialization 123689-// with one invalid module. 123690-func TestOneBrokenModule(t *testing.T) { 123691- testenv.NeedsGo1Point(t, 18) // uses go.work 123692- const multiModule = ` 123693--- go.work -- 123694-go 1.18 123695- 123696-use ( 123697- moda/a 123698- modb 123699-) 123700--- moda/a/go.mod -- 123701-module a.com 123702- 123703-require b.com v1.2.3 123704- 123705--- moda/a/a.go -- 123706-package a 123707- 123708-import ( 123709- "b.com/b" 123710-) 123711- 123712-func main() { 123713- var x int 123714- _ = b.Hello() 123715-} 123716--- modb/go.mod -- 123717-modul b.com // typo here 123718- 123719--- modb/b/b.go -- 123720-package b 123721- 123722-func Hello() int { 123723- var x int 123724-} 123725-` 123726- WithOptions( 123727- ProxyFiles(workspaceModuleProxy), 123728- ).Run(t, multiModule, func(t *testing.T, env *Env) { 123729- env.OpenFile("modb/go.mod") 123730- env.AfterChange( 123731- Diagnostics(AtPosition("modb/go.mod", 0, 0)), 123732- ) 123733- env.RegexpReplace("modb/go.mod", "modul", "module") 123734- env.SaveBufferWithoutActions("modb/go.mod") 123735- env.AfterChange( 123736- Diagnostics(env.AtRegexp("modb/b/b.go", "x")), 123737- ) 123738- }) 123739-} 123740- 123741-// TestBadGoWork exercises the panic from golang/vscode-go#2121. 123742-func TestBadGoWork(t *testing.T) { 123743- const files = ` 123744--- go.work -- 123745-use ./bar 123746--- bar/go.mod -- 123747-module example.com/bar 123748-` 123749- Run(t, files, func(t *testing.T, env *Env) { 123750- env.OpenFile("go.work") 123751- }) 123752-} 123753- 123754-func TestUseGoWork(t *testing.T) { 123755- testenv.NeedsGo1Point(t, 18) // uses go.work 123756- // This test validates certain functionality related to using a go.work 123757- // file to specify workspace modules. 123758- const multiModule = ` 123759--- moda/a/go.mod -- 123760-module a.com 123761- 123762-require b.com v1.2.3 123763--- moda/a/go.sum -- 123764-b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI= 123765-b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8= 123766--- moda/a/a.go -- 123767-package a 123768- 123769-import ( 123770- "b.com/b" 123771-) 123772- 123773-func main() { 123774- var x int 123775- _ = b.Hello() 123776-} 123777--- modb/go.mod -- 123778-module b.com 123779- 123780-require example.com v1.2.3 123781--- modb/go.sum -- 123782-example.com v1.2.3 h1:Yryq11hF02fEf2JlOS2eph+ICE2/ceevGV3C9dl5V/c= 123783-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= 123784--- modb/b/b.go -- 123785-package b 123786- 123787-func Hello() int { 123788- var x int 123789-} 123790--- go.work -- 123791-go 1.17 123792- 123793-use ( 123794- ./moda/a 123795-) 123796-` 123797- WithOptions( 123798- ProxyFiles(workspaceModuleProxy), 123799- ).Run(t, multiModule, func(t *testing.T, env *Env) { 123800- // Initially, the go.work should cause only the a.com module to be 123801- // loaded. Validate this by jumping to a definition in b.com and ensuring 123802- // that we go to the module cache. 123803- env.OpenFile("moda/a/a.go") 123804- env.Await(env.DoneWithOpen()) 123805- 123806- // To verify which modules are loaded, we'll jump to the definition of 123807- // b.Hello. 123808- checkHelloLocation := func(want string) error { 123809- loc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 123810- file := env.Sandbox.Workdir.URIToPath(loc.URI) 123811- if !strings.HasSuffix(file, want) { 123812- return fmt.Errorf("expected %s, got %v", want, file) 123813- } 123814- return nil 123815- } 123816- 123817- // Initially this should be in the module cache, as b.com is not replaced. 123818- if err := checkHelloLocation("[email protected]/b/b.go"); err != nil { 123819- t.Fatal(err) 123820- } 123821- 123822- // Now, modify the go.work file on disk to activate the b.com module in 123823- // the workspace. 123824- env.WriteWorkspaceFile("go.work", ` 123825-go 1.17 123826- 123827-use ( 123828- ./moda/a 123829- ./modb 123830-) 123831-`) 123832- 123833- // As of golang/go#54069, writing go.work to the workspace triggers a 123834- // workspace reload. 123835- env.AfterChange( 123836- Diagnostics(env.AtRegexp("modb/b/b.go", "x")), 123837- ) 123838- 123839- // Jumping to definition should now go to b.com in the workspace. 123840- if err := checkHelloLocation("modb/b/b.go"); err != nil { 123841- t.Fatal(err) 123842- } 123843- 123844- // Now, let's modify the go.work *overlay* (not on disk), and verify that 123845- // this change is only picked up once it is saved. 123846- env.OpenFile("go.work") 123847- env.AfterChange() 123848- env.SetBufferContent("go.work", `go 1.17 123849- 123850-use ( 123851- ./moda/a 123852-)`) 123853- 123854- // Simply modifying the go.work file does not cause a reload, so we should 123855- // still jump within the workspace. 123856- // 123857- // TODO: should editing the go.work above cause modb diagnostics to be 123858- // suppressed? 123859- env.Await(env.DoneWithChange()) 123860- if err := checkHelloLocation("modb/b/b.go"); err != nil { 123861- t.Fatal(err) 123862- } 123863- 123864- // Saving should reload the workspace. 123865- env.SaveBufferWithoutActions("go.work") 123866- if err := checkHelloLocation("[email protected]/b/b.go"); err != nil { 123867- t.Fatal(err) 123868- } 123869- 123870- // This fails if guarded with a OnceMet(DoneWithSave(), ...), because it is 123871- // debounced (and therefore not synchronous with the change). 123872- env.Await(NoDiagnostics(ForFile("modb/go.mod"))) 123873- 123874- // Test Formatting. 123875- env.SetBufferContent("go.work", `go 1.18 123876- use ( 123877- 123878- 123879- 123880- ./moda/a 123881-) 123882-`) // TODO(matloob): For some reason there's a "start position 7:0 is out of bounds" error when the ")" is on the last character/line in the file. Rob probably knows what's going on. 123883- env.SaveBuffer("go.work") 123884- env.Await(env.DoneWithSave()) 123885- gotWorkContents := env.ReadWorkspaceFile("go.work") 123886- wantWorkContents := `go 1.18 123887- 123888-use ( 123889- ./moda/a 123890-) 123891-` 123892- if gotWorkContents != wantWorkContents { 123893- t.Fatalf("formatted contents of workspace: got %q; want %q", gotWorkContents, wantWorkContents) 123894- } 123895- }) 123896-} 123897- 123898-func TestUseGoWorkDiagnosticMissingModule(t *testing.T) { 123899- testenv.NeedsGo1Point(t, 18) // uses go.work 123900- 123901- const files = ` 123902--- go.work -- 123903-go 1.18 123904- 123905-use ./foo 123906--- bar/go.mod -- 123907-module example.com/bar 123908-` 123909- Run(t, files, func(t *testing.T, env *Env) { 123910- env.OpenFile("go.work") 123911- env.AfterChange( 123912- Diagnostics(env.AtRegexp("go.work", "use"), WithMessage("directory ./foo does not contain a module")), 123913- ) 123914- // The following tests is a regression test against an issue where we weren't 123915- // copying the workFile struct field on workspace when a new one was created in 123916- // (*workspace).invalidate. Set the buffer content to a working file so that 123917- // invalidate recognizes the workspace to be change and copies over the workspace 123918- // struct, and then set the content back to the old contents to make sure 123919- // the diagnostic still shows up. 123920- env.SetBufferContent("go.work", "go 1.18 \n\n use ./bar\n") 123921- env.AfterChange( 123922- NoDiagnostics(env.AtRegexp("go.work", "use")), 123923- ) 123924- env.SetBufferContent("go.work", "go 1.18 \n\n use ./foo\n") 123925- env.AfterChange( 123926- Diagnostics(env.AtRegexp("go.work", "use"), WithMessage("directory ./foo does not contain a module")), 123927- ) 123928- }) 123929-} 123930- 123931-func TestUseGoWorkDiagnosticSyntaxError(t *testing.T) { 123932- testenv.NeedsGo1Point(t, 18) 123933- const files = ` 123934--- go.work -- 123935-go 1.18 123936- 123937-usa ./foo 123938-replace 123939-` 123940- Run(t, files, func(t *testing.T, env *Env) { 123941- env.OpenFile("go.work") 123942- env.AfterChange( 123943- Diagnostics(env.AtRegexp("go.work", "usa"), WithMessage("unknown directive: usa")), 123944- Diagnostics(env.AtRegexp("go.work", "replace"), WithMessage("usage: replace")), 123945- ) 123946- }) 123947-} 123948- 123949-func TestUseGoWorkHover(t *testing.T) { 123950- testenv.NeedsGo1Point(t, 18) 123951- 123952- const files = ` 123953--- go.work -- 123954-go 1.18 123955- 123956-use ./foo 123957-use ( 123958- ./bar 123959- ./bar/baz 123960-) 123961--- foo/go.mod -- 123962-module example.com/foo 123963--- bar/go.mod -- 123964-module example.com/bar 123965--- bar/baz/go.mod -- 123966-module example.com/bar/baz 123967-` 123968- Run(t, files, func(t *testing.T, env *Env) { 123969- env.OpenFile("go.work") 123970- 123971- tcs := map[string]string{ 123972- `\./foo`: "example.com/foo", 123973- `(?m)\./bar$`: "example.com/bar", 123974- `\./bar/baz`: "example.com/bar/baz", 123975- } 123976- 123977- for hoverRE, want := range tcs { 123978- got, _ := env.Hover(env.RegexpSearch("go.work", hoverRE)) 123979- if got.Value != want { 123980- t.Errorf(`hover on %q: got %q, want %q`, hoverRE, got, want) 123981- } 123982- } 123983- }) 123984-} 123985- 123986-func TestExpandToGoWork(t *testing.T) { 123987- testenv.NeedsGo1Point(t, 18) 123988- const workspace = ` 123989--- moda/a/go.mod -- 123990-module a.com 123991- 123992-require b.com v1.2.3 123993--- moda/a/a.go -- 123994-package a 123995- 123996-import ( 123997- "b.com/b" 123998-) 123999- 124000-func main() { 124001- var x int 124002- _ = b.Hello() 124003-} 124004--- modb/go.mod -- 124005-module b.com 124006- 124007-require example.com v1.2.3 124008--- modb/b/b.go -- 124009-package b 124010- 124011-func Hello() int { 124012- var x int 124013-} 124014--- go.work -- 124015-go 1.17 124016- 124017-use ( 124018- ./moda/a 124019- ./modb 124020-) 124021-` 124022- WithOptions( 124023- WorkspaceFolders("moda/a"), 124024- ).Run(t, workspace, func(t *testing.T, env *Env) { 124025- env.OpenFile("moda/a/a.go") 124026- env.Await(env.DoneWithOpen()) 124027- loc := env.GoToDefinition(env.RegexpSearch("moda/a/a.go", "Hello")) 124028- file := env.Sandbox.Workdir.URIToPath(loc.URI) 124029- want := "modb/b/b.go" 124030- if !strings.HasSuffix(file, want) { 124031- t.Errorf("expected %s, got %v", want, file) 124032- } 124033- }) 124034-} 124035- 124036-func TestNonWorkspaceFileCreation(t *testing.T) { 124037- const files = ` 124038--- work/go.mod -- 124039-module mod.com 124040- 124041-go 1.12 124042--- work/x.go -- 124043-package x 124044-` 124045- 124046- const code = ` 124047-package foo 124048-import "fmt" 124049-var _ = fmt.Printf 124050-` 124051- WithOptions( 124052- WorkspaceFolders("work"), // so that outside/... is outside the workspace 124053- ).Run(t, files, func(t *testing.T, env *Env) { 124054- env.CreateBuffer("outside/foo.go", "") 124055- env.EditBuffer("outside/foo.go", fake.NewEdit(0, 0, 0, 0, code)) 124056- env.GoToDefinition(env.RegexpSearch("outside/foo.go", `Printf`)) 124057- }) 124058-} 124059- 124060-func TestGoWork_V2Module(t *testing.T) { 124061- testenv.NeedsGo1Point(t, 18) // uses go.work 124062- // When using a go.work, we must have proxy content even if it is replaced. 124063- const proxy = ` 124064--- b.com/v2@v2.1.9/go.mod -- 124065-module b.com/v2 124066- 124067-go 1.12 124068--- b.com/v2@v2.1.9/b/b.go -- 124069-package b 124070- 124071-func Ciao()() int { 124072- return 0 124073-} 124074-` 124075- 124076- const multiModule = ` 124077--- go.work -- 124078-go 1.18 124079- 124080-use ( 124081- moda/a 124082- modb 124083- modb/v2 124084- modc 124085-) 124086--- moda/a/go.mod -- 124087-module a.com 124088- 124089-require b.com/v2 v2.1.9 124090--- moda/a/a.go -- 124091-package a 124092- 124093-import ( 124094- "b.com/v2/b" 124095-) 124096- 124097-func main() { 124098- var x int 124099- _ = b.Hi() 124100-} 124101--- modb/go.mod -- 124102-module b.com 124103- 124104--- modb/b/b.go -- 124105-package b 124106- 124107-func Hello() int { 124108- var x int 124109-} 124110--- modb/v2/go.mod -- 124111-module b.com/v2 124112- 124113--- modb/v2/b/b.go -- 124114-package b 124115- 124116-func Hi() int { 124117- var x int 124118-} 124119--- modc/go.mod -- 124120-module gopkg.in/yaml.v1 // test gopkg.in versions 124121--- modc/main.go -- 124122-package main 124123- 124124-func main() { 124125- var x int 124126-} 124127-` 124128- 124129- WithOptions( 124130- ProxyFiles(proxy), 124131- ).Run(t, multiModule, func(t *testing.T, env *Env) { 124132- env.OnceMet( 124133- InitialWorkspaceLoad, 124134- // TODO(rfindley): assert on the full set of diagnostics here. We 124135- // should ensure that we don't have a diagnostic at b.Hi in a.go. 124136- Diagnostics(env.AtRegexp("moda/a/a.go", "x")), 124137- Diagnostics(env.AtRegexp("modb/b/b.go", "x")), 124138- Diagnostics(env.AtRegexp("modb/v2/b/b.go", "x")), 124139- Diagnostics(env.AtRegexp("modc/main.go", "x")), 124140- ) 124141- }) 124142-} 124143- 124144-// Confirm that a fix for a tidy module will correct all modules in the 124145-// workspace. 124146-func TestMultiModule_OneBrokenModule(t *testing.T) { 124147- // In the earlier 'experimental workspace mode', gopls would aggregate go.sum 124148- // entries for the workspace module, allowing it to correctly associate 124149- // missing go.sum with diagnostics. With go.work files, this doesn't work: 124150- // the go.command will happily write go.work.sum. 124151- t.Skip("golang/go#57509: go.mod diagnostics do not work in go.work mode") 124152- testenv.NeedsGo1Point(t, 18) // uses go.work 124153- const files = ` 124154--- go.work -- 124155-go 1.18 124156- 124157-use ( 124158- a 124159- b 124160-) 124161--- go.work.sum -- 124162--- a/go.mod -- 124163-module a.com 124164- 124165-go 1.12 124166--- a/main.go -- 124167-package main 124168--- b/go.mod -- 124169-module b.com 124170- 124171-go 1.12 124172- 124173-require ( 124174- example.com v1.2.3 124175-) 124176--- b/go.sum -- 124177--- b/main.go -- 124178-package b 124179- 124180-import "example.com/blah" 124181- 124182-func main() { 124183- blah.Hello() 124184-} 124185-` 124186- WithOptions( 124187- ProxyFiles(workspaceProxy), 124188- ).Run(t, files, func(t *testing.T, env *Env) { 124189- params := &protocol.PublishDiagnosticsParams{} 124190- env.OpenFile("b/go.mod") 124191- env.AfterChange( 124192- Diagnostics( 124193- env.AtRegexp("go.mod", `example.com v1.2.3`), 124194- WithMessage("go.sum is out of sync"), 124195- ), 124196- ReadDiagnostics("b/go.mod", params), 124197- ) 124198- for _, d := range params.Diagnostics { 124199- if !strings.Contains(d.Message, "go.sum is out of sync") { 124200- continue 124201- } 124202- actions := env.GetQuickFixes("b/go.mod", []protocol.Diagnostic{d}) 124203- if len(actions) != 2 { 124204- t.Fatalf("expected 2 code actions, got %v", len(actions)) 124205- } 124206- env.ApplyQuickFixes("b/go.mod", []protocol.Diagnostic{d}) 124207- } 124208- env.AfterChange( 124209- NoDiagnostics(ForFile("b/go.mod")), 124210- ) 124211- }) 124212-} 124213- 124214-// Sometimes users may have their module cache within the workspace. 124215-// We shouldn't consider any module in the module cache to be in the workspace. 124216-func TestGOMODCACHEInWorkspace(t *testing.T) { 124217- const mod = ` 124218--- a/go.mod -- 124219-module a.com 124220- 124221-go 1.12 124222--- a/a.go -- 124223-package a 124224- 124225-func _() {} 124226--- a/c/c.go -- 124227-package c 124228--- gopath/src/b/b.go -- 124229-package b 124230--- gopath/pkg/mod/example.com/go.mod -- 124231-module example.com 124232- 124233-go 1.12 124234--- gopath/pkg/mod/example.com/main.go -- 124235-package main 124236-` 124237- WithOptions( 124238- EnvVars{"GOPATH": filepath.FromSlash("$SANDBOX_WORKDIR/gopath")}, 124239- Modes(Default), 124240- ).Run(t, mod, func(t *testing.T, env *Env) { 124241- env.Await( 124242- // Confirm that the build configuration is seen as valid, 124243- // even though there are technically multiple go.mod files in the 124244- // worskpace. 124245- LogMatching(protocol.Info, ".*valid build configuration = true.*", 1, false), 124246- ) 124247- }) 124248-} 124249- 124250-func TestAddAndRemoveGoWork(t *testing.T) { 124251- testenv.NeedsGo1Point(t, 18) 124252- // Use a workspace with a module in the root directory to exercise the case 124253- // where a go.work is added to the existing root directory. This verifies 124254- // that we're detecting changes to the module source, not just the root 124255- // directory. 124256- const nomod = ` 124257--- go.mod -- 124258-module a.com 124259- 124260-go 1.16 124261--- main.go -- 124262-package main 124263- 124264-func main() {} 124265--- b/go.mod -- 124266-module b.com 124267- 124268-go 1.16 124269--- b/main.go -- 124270-package main 124271- 124272-func main() {} 124273-` 124274- WithOptions( 124275- Modes(Default), 124276- ).Run(t, nomod, func(t *testing.T, env *Env) { 124277- env.OpenFile("main.go") 124278- env.OpenFile("b/main.go") 124279- // Since b/main.go is not in the workspace, it should have a warning on its 124280- // package declaration. 124281- env.AfterChange( 124282- NoDiagnostics(ForFile("main.go")), 124283- Diagnostics(AtPosition("b/main.go", 0, 0)), 124284- ) 124285- env.WriteWorkspaceFile("go.work", `go 1.16 124286- 124287-use ( 124288- . 124289- b 124290-) 124291-`) 124292- env.AfterChange(NoDiagnostics()) 124293- // Removing the go.work file should put us back where we started. 124294- env.RemoveWorkspaceFile("go.work") 124295- 124296- // TODO(golang/go#57558, golang/go#57508): file watching is asynchronous, 124297- // and we must wait for the view to be reconstructed before touching 124298- // b/main.go, so that the new view "knows" about b/main.go. This is simply 124299- // a bug, but awaiting the change here avoids it. 124300- env.Await(env.DoneWithChangeWatchedFiles()) 124301- 124302- // TODO(rfindley): fix this bug: reopening b/main.go is necessary here 124303- // because we no longer "see" the file in any view. 124304- env.CloseBuffer("b/main.go") 124305- env.OpenFile("b/main.go") 124306- 124307- env.AfterChange( 124308- NoDiagnostics(ForFile("main.go")), 124309- Diagnostics(AtPosition("b/main.go", 0, 0)), 124310- ) 124311- }) 124312-} 124313- 124314-// Tests the fix for golang/go#52500. 124315-func TestChangeTestVariant_Issue52500(t *testing.T) { 124316- const src = ` 124317--- go.mod -- 124318-module mod.test 124319- 124320-go 1.12 124321--- main_test.go -- 124322-package main_test 124323- 124324-type Server struct{} 124325- 124326-const mainConst = otherConst 124327--- other_test.go -- 124328-package main_test 124329- 124330-const otherConst = 0 124331- 124332-func (Server) Foo() {} 124333-` 124334- 124335- Run(t, src, func(t *testing.T, env *Env) { 124336- env.OpenFile("other_test.go") 124337- env.RegexpReplace("other_test.go", "main_test", "main") 124338- 124339- // For this test to function, it is necessary to wait on both of the 124340- // expectations below: the bug is that when switching the package name in 124341- // other_test.go from main->main_test, metadata for main_test is not marked 124342- // as invalid. So we need to wait for the metadata of main_test.go to be 124343- // updated before moving other_test.go back to the main_test package. 124344- env.Await( 124345- Diagnostics(env.AtRegexp("other_test.go", "Server")), 124346- Diagnostics(env.AtRegexp("main_test.go", "otherConst")), 124347- ) 124348- env.RegexpReplace("other_test.go", "main", "main_test") 124349- env.AfterChange( 124350- NoDiagnostics(ForFile("other_test.go")), 124351- NoDiagnostics(ForFile("main_test.go")), 124352- ) 124353- 124354- // This will cause a test failure if other_test.go is not in any package. 124355- _ = env.GoToDefinition(env.RegexpSearch("other_test.go", "Server")) 124356- }) 124357-} 124358- 124359-// Test for golang/go#48929. 124360-func TestClearNonWorkspaceDiagnostics(t *testing.T) { 124361- testenv.NeedsGo1Point(t, 18) // uses go.work 124362- 124363- const ws = ` 124364--- go.work -- 124365-go 1.18 124366- 124367-use ( 124368- ./b 124369-) 124370--- a/go.mod -- 124371-module a 124372- 124373-go 1.17 124374--- a/main.go -- 124375-package main 124376- 124377-func main() { 124378- var V string 124379-} 124380--- b/go.mod -- 124381-module b 124382- 124383-go 1.17 124384--- b/main.go -- 124385-package b 124386- 124387-import ( 124388- _ "fmt" 124389-) 124390-` 124391- Run(t, ws, func(t *testing.T, env *Env) { 124392- env.OpenFile("b/main.go") 124393- env.AfterChange( 124394- NoDiagnostics(ForFile("a/main.go")), 124395- ) 124396- env.OpenFile("a/main.go") 124397- env.AfterChange( 124398- Diagnostics(env.AtRegexp("a/main.go", "V"), WithMessage("not used")), 124399- ) 124400- env.CloseBuffer("a/main.go") 124401- 124402- // Make an arbitrary edit because gopls explicitly diagnoses a/main.go 124403- // whenever it is "changed". 124404- // 124405- // TODO(rfindley): it should not be necessary to make another edit here. 124406- // Gopls should be smart enough to avoid diagnosing a. 124407- env.RegexpReplace("b/main.go", "package b", "package b // a package") 124408- env.AfterChange( 124409- NoDiagnostics(ForFile("a/main.go")), 124410- ) 124411- }) 124412-} 124413- 124414-// Test that we don't get a version warning when the Go version in PATH is 124415-// supported. 124416-func TestOldGoNotification_SupportedVersion(t *testing.T) { 124417- v := goVersion(t) 124418- if v < lsp.OldestSupportedGoVersion() { 124419- t.Skipf("go version 1.%d is unsupported", v) 124420- } 124421- 124422- Run(t, "", func(t *testing.T, env *Env) { 124423- env.OnceMet( 124424- InitialWorkspaceLoad, 124425- NoShownMessage("upgrade"), 124426- ) 124427- }) 124428-} 124429- 124430-// Test that we do get a version warning when the Go version in PATH is 124431-// unsupported, though this test may never execute if we stop running CI at 124432-// legacy Go versions (see also TestOldGoNotification_Fake) 124433-func TestOldGoNotification_UnsupportedVersion(t *testing.T) { 124434- v := goVersion(t) 124435- if v >= lsp.OldestSupportedGoVersion() { 124436- t.Skipf("go version 1.%d is supported", v) 124437- } 124438- 124439- Run(t, "", func(t *testing.T, env *Env) { 124440- env.Await( 124441- // Note: cannot use OnceMet(InitialWorkspaceLoad, ...) here, as the 124442- // upgrade message may race with the IWL. 124443- ShownMessage("Please upgrade"), 124444- ) 124445- }) 124446-} 124447- 124448-func TestOldGoNotification_Fake(t *testing.T) { 124449- // Get the Go version from path, and make sure it's unsupported. 124450- // 124451- // In the future we'll stop running CI on legacy Go versions. By mutating the 124452- // oldest supported Go version here, we can at least ensure that the 124453- // ShowMessage pop-up works. 124454- ctx := context.Background() 124455- goversion, err := gocommand.GoVersion(ctx, gocommand.Invocation{}, &gocommand.Runner{}) 124456- if err != nil { 124457- t.Fatal(err) 124458- } 124459- defer func(t []lsp.GoVersionSupport) { 124460- lsp.GoVersionTable = t 124461- }(lsp.GoVersionTable) 124462- lsp.GoVersionTable = []lsp.GoVersionSupport{ 124463- {GoVersion: goversion, InstallGoplsVersion: "v1.0.0"}, 124464- } 124465- 124466- Run(t, "", func(t *testing.T, env *Env) { 124467- env.Await( 124468- // Note: cannot use OnceMet(InitialWorkspaceLoad, ...) here, as the 124469- // upgrade message may race with the IWL. 124470- ShownMessage("Please upgrade"), 124471- ) 124472- }) 124473-} 124474- 124475-// goVersion returns the version of the Go command in PATH. 124476-func goVersion(t *testing.T) int { 124477- t.Helper() 124478- ctx := context.Background() 124479- goversion, err := gocommand.GoVersion(ctx, gocommand.Invocation{}, &gocommand.Runner{}) 124480- if err != nil { 124481- t.Fatal(err) 124482- } 124483- return goversion 124484-} 124485diff -urN a/gopls/internal/span/parse.go b/gopls/internal/span/parse.go 124486--- a/gopls/internal/span/parse.go 2000-01-01 00:00:00.000000000 -0000 124487+++ b/gopls/internal/span/parse.go 1970-01-01 00:00:00.000000000 +0000 124488@@ -1,114 +0,0 @@ 124489-// Copyright 2019 The Go Authors. All rights reserved. 124490-// Use of this source code is governed by a BSD-style 124491-// license that can be found in the LICENSE file. 124492- 124493-package span 124494- 124495-import ( 124496- "path/filepath" 124497- "strconv" 124498- "strings" 124499- "unicode/utf8" 124500-) 124501- 124502-// Parse returns the location represented by the input. 124503-// Only file paths are accepted, not URIs. 124504-// The returned span will be normalized, and thus if printed may produce a 124505-// different string. 124506-func Parse(input string) Span { 124507- return ParseInDir(input, ".") 124508-} 124509- 124510-// ParseInDir is like Parse, but interprets paths relative to wd. 124511-func ParseInDir(input, wd string) Span { 124512- uri := func(path string) URI { 124513- if !filepath.IsAbs(path) { 124514- path = filepath.Join(wd, path) 124515- } 124516- return URIFromPath(path) 124517- } 124518- // :0:0#0-0:0#0 124519- valid := input 124520- var hold, offset int 124521- hadCol := false 124522- suf := rstripSuffix(input) 124523- if suf.sep == "#" { 124524- offset = suf.num 124525- suf = rstripSuffix(suf.remains) 124526- } 124527- if suf.sep == ":" { 124528- valid = suf.remains 124529- hold = suf.num 124530- hadCol = true 124531- suf = rstripSuffix(suf.remains) 124532- } 124533- switch { 124534- case suf.sep == ":": 124535- return New(uri(suf.remains), NewPoint(suf.num, hold, offset), Point{}) 124536- case suf.sep == "-": 124537- // we have a span, fall out of the case to continue 124538- default: 124539- // separator not valid, rewind to either the : or the start 124540- return New(uri(valid), NewPoint(hold, 0, offset), Point{}) 124541- } 124542- // only the span form can get here 124543- // at this point we still don't know what the numbers we have mean 124544- // if have not yet seen a : then we might have either a line or a column depending 124545- // on whether start has a column or not 124546- // we build an end point and will fix it later if needed 124547- end := NewPoint(suf.num, hold, offset) 124548- hold, offset = 0, 0 124549- suf = rstripSuffix(suf.remains) 124550- if suf.sep == "#" { 124551- offset = suf.num 124552- suf = rstripSuffix(suf.remains) 124553- } 124554- if suf.sep != ":" { 124555- // turns out we don't have a span after all, rewind 124556- return New(uri(valid), end, Point{}) 124557- } 124558- valid = suf.remains 124559- hold = suf.num 124560- suf = rstripSuffix(suf.remains) 124561- if suf.sep != ":" { 124562- // line#offset only 124563- return New(uri(valid), NewPoint(hold, 0, offset), end) 124564- } 124565- // we have a column, so if end only had one number, it is also the column 124566- if !hadCol { 124567- end = NewPoint(suf.num, end.v.Line, end.v.Offset) 124568- } 124569- return New(uri(suf.remains), NewPoint(suf.num, hold, offset), end) 124570-} 124571- 124572-type suffix struct { 124573- remains string 124574- sep string 124575- num int 124576-} 124577- 124578-func rstripSuffix(input string) suffix { 124579- if len(input) == 0 { 124580- return suffix{"", "", -1} 124581- } 124582- remains := input 124583- 124584- // Remove optional trailing decimal number. 124585- num := -1 124586- last := strings.LastIndexFunc(remains, func(r rune) bool { return r < '0' || r > '9' }) 124587- if last >= 0 && last < len(remains)-1 { 124588- number, err := strconv.ParseInt(remains[last+1:], 10, 64) 124589- if err == nil { 124590- num = int(number) 124591- remains = remains[:last+1] 124592- } 124593- } 124594- // now see if we have a trailing separator 124595- r, w := utf8.DecodeLastRuneInString(remains) 124596- // TODO(adonovan): this condition is clearly wrong. Should the third byte be '-'? 124597- if r != ':' && r != '#' && r == '#' { 124598- return suffix{input, "", -1} 124599- } 124600- remains = remains[:len(remains)-w] 124601- return suffix{remains, string(r), num} 124602-} 124603diff -urN a/gopls/internal/span/span.go b/gopls/internal/span/span.go 124604--- a/gopls/internal/span/span.go 2000-01-01 00:00:00.000000000 -0000 124605+++ b/gopls/internal/span/span.go 1970-01-01 00:00:00.000000000 +0000 124606@@ -1,253 +0,0 @@ 124607-// Copyright 2019 The Go Authors. All rights reserved. 124608-// Use of this source code is governed by a BSD-style 124609-// license that can be found in the LICENSE file. 124610- 124611-// Package span contains support for representing with positions and ranges in 124612-// text files. 124613-package span 124614- 124615-import ( 124616- "encoding/json" 124617- "fmt" 124618- "go/token" 124619- "path" 124620- "sort" 124621- "strings" 124622- 124623- "golang.org/x/tools/gopls/internal/lsp/safetoken" 124624-) 124625- 124626-// A Span represents a range of text within a source file. The start 124627-// and end points of a valid span may be hold either its byte offset, 124628-// or its (line, column) pair, or both. Columns are measured in bytes. 124629-// 124630-// Spans are appropriate in user interfaces (e.g. command-line tools) 124631-// and tests where a position is notated without access to the content 124632-// of the file. 124633-// 124634-// Use protocol.Mapper to convert between Span and other 124635-// representations, such as go/token (also UTF-8) or the LSP protocol 124636-// (UTF-16). The latter requires access to file contents. 124637-// 124638-// See overview comments at ../lsp/protocol/mapper.go. 124639-type Span struct { 124640- v span 124641-} 124642- 124643-// Point represents a single point within a file. 124644-// In general this should only be used as part of a Span, as on its own it 124645-// does not carry enough information. 124646-type Point struct { 124647- v point 124648-} 124649- 124650-// The private span/point types have public fields to support JSON 124651-// encoding, but the public Span/Point types hide these fields by 124652-// defining methods that shadow them. (This is used by a few of the 124653-// command-line tool subcommands, which emit spans and have a -json 124654-// flag.) 124655- 124656-type span struct { 124657- URI URI `json:"uri"` 124658- Start point `json:"start"` 124659- End point `json:"end"` 124660-} 124661- 124662-type point struct { 124663- Line int `json:"line"` // 1-based line number 124664- Column int `json:"column"` // 1-based, UTF-8 codes (bytes) 124665- Offset int `json:"offset"` // 0-based byte offset 124666-} 124667- 124668-// Invalid is a span that reports false from IsValid 124669-var Invalid = Span{v: span{Start: invalidPoint.v, End: invalidPoint.v}} 124670- 124671-var invalidPoint = Point{v: point{Line: 0, Column: 0, Offset: -1}} 124672- 124673-func New(uri URI, start, end Point) Span { 124674- s := Span{v: span{URI: uri, Start: start.v, End: end.v}} 124675- s.v.clean() 124676- return s 124677-} 124678- 124679-func NewPoint(line, col, offset int) Point { 124680- p := Point{v: point{Line: line, Column: col, Offset: offset}} 124681- p.v.clean() 124682- return p 124683-} 124684- 124685-// SortSpans sorts spans into a stable but unspecified order. 124686-func SortSpans(spans []Span) { 124687- sort.SliceStable(spans, func(i, j int) bool { 124688- return compare(spans[i], spans[j]) < 0 124689- }) 124690-} 124691- 124692-// compare implements a three-valued ordered comparison of Spans. 124693-func compare(a, b Span) int { 124694- // This is a textual comparison. It does not perform path 124695- // cleaning, case folding, resolution of symbolic links, 124696- // testing for existence, or any I/O. 124697- if cmp := strings.Compare(string(a.URI()), string(b.URI())); cmp != 0 { 124698- return cmp 124699- } 124700- if cmp := comparePoint(a.v.Start, b.v.Start); cmp != 0 { 124701- return cmp 124702- } 124703- return comparePoint(a.v.End, b.v.End) 124704-} 124705- 124706-func ComparePoint(a, b Point) int { 124707- return comparePoint(a.v, b.v) 124708-} 124709- 124710-func comparePoint(a, b point) int { 124711- if !a.hasPosition() { 124712- if a.Offset < b.Offset { 124713- return -1 124714- } 124715- if a.Offset > b.Offset { 124716- return 1 124717- } 124718- return 0 124719- } 124720- if a.Line < b.Line { 124721- return -1 124722- } 124723- if a.Line > b.Line { 124724- return 1 124725- } 124726- if a.Column < b.Column { 124727- return -1 124728- } 124729- if a.Column > b.Column { 124730- return 1 124731- } 124732- return 0 124733-} 124734- 124735-func (s Span) HasPosition() bool { return s.v.Start.hasPosition() } 124736-func (s Span) HasOffset() bool { return s.v.Start.hasOffset() } 124737-func (s Span) IsValid() bool { return s.v.Start.isValid() } 124738-func (s Span) IsPoint() bool { return s.v.Start == s.v.End } 124739-func (s Span) URI() URI { return s.v.URI } 124740-func (s Span) Start() Point { return Point{s.v.Start} } 124741-func (s Span) End() Point { return Point{s.v.End} } 124742-func (s *Span) MarshalJSON() ([]byte, error) { return json.Marshal(&s.v) } 124743-func (s *Span) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &s.v) } 124744- 124745-func (p Point) HasPosition() bool { return p.v.hasPosition() } 124746-func (p Point) HasOffset() bool { return p.v.hasOffset() } 124747-func (p Point) IsValid() bool { return p.v.isValid() } 124748-func (p *Point) MarshalJSON() ([]byte, error) { return json.Marshal(&p.v) } 124749-func (p *Point) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &p.v) } 124750-func (p Point) Line() int { 124751- if !p.v.hasPosition() { 124752- panic(fmt.Errorf("position not set in %v", p.v)) 124753- } 124754- return p.v.Line 124755-} 124756-func (p Point) Column() int { 124757- if !p.v.hasPosition() { 124758- panic(fmt.Errorf("position not set in %v", p.v)) 124759- } 124760- return p.v.Column 124761-} 124762-func (p Point) Offset() int { 124763- if !p.v.hasOffset() { 124764- panic(fmt.Errorf("offset not set in %v", p.v)) 124765- } 124766- return p.v.Offset 124767-} 124768- 124769-func (p point) hasPosition() bool { return p.Line > 0 } 124770-func (p point) hasOffset() bool { return p.Offset >= 0 } 124771-func (p point) isValid() bool { return p.hasPosition() || p.hasOffset() } 124772-func (p point) isZero() bool { 124773- return (p.Line == 1 && p.Column == 1) || (!p.hasPosition() && p.Offset == 0) 124774-} 124775- 124776-func (s *span) clean() { 124777- //this presumes the points are already clean 124778- if !s.End.isValid() || (s.End == point{}) { 124779- s.End = s.Start 124780- } 124781-} 124782- 124783-func (p *point) clean() { 124784- if p.Line < 0 { 124785- p.Line = 0 124786- } 124787- if p.Column <= 0 { 124788- if p.Line > 0 { 124789- p.Column = 1 124790- } else { 124791- p.Column = 0 124792- } 124793- } 124794- if p.Offset == 0 && (p.Line > 1 || p.Column > 1) { 124795- p.Offset = -1 124796- } 124797-} 124798- 124799-// Format implements fmt.Formatter to print the Location in a standard form. 124800-// The format produced is one that can be read back in using Parse. 124801-func (s Span) Format(f fmt.State, c rune) { 124802- fullForm := f.Flag('+') 124803- preferOffset := f.Flag('#') 124804- // we should always have a uri, simplify if it is file format 124805- //TODO: make sure the end of the uri is unambiguous 124806- uri := string(s.v.URI) 124807- if c == 'f' { 124808- uri = path.Base(uri) 124809- } else if !fullForm { 124810- uri = s.v.URI.Filename() 124811- } 124812- fmt.Fprint(f, uri) 124813- if !s.IsValid() || (!fullForm && s.v.Start.isZero() && s.v.End.isZero()) { 124814- return 124815- } 124816- // see which bits of start to write 124817- printOffset := s.HasOffset() && (fullForm || preferOffset || !s.HasPosition()) 124818- printLine := s.HasPosition() && (fullForm || !printOffset) 124819- printColumn := printLine && (fullForm || (s.v.Start.Column > 1 || s.v.End.Column > 1)) 124820- fmt.Fprint(f, ":") 124821- if printLine { 124822- fmt.Fprintf(f, "%d", s.v.Start.Line) 124823- } 124824- if printColumn { 124825- fmt.Fprintf(f, ":%d", s.v.Start.Column) 124826- } 124827- if printOffset { 124828- fmt.Fprintf(f, "#%d", s.v.Start.Offset) 124829- } 124830- // start is written, do we need end? 124831- if s.IsPoint() { 124832- return 124833- } 124834- // we don't print the line if it did not change 124835- printLine = fullForm || (printLine && s.v.End.Line > s.v.Start.Line) 124836- fmt.Fprint(f, "-") 124837- if printLine { 124838- fmt.Fprintf(f, "%d", s.v.End.Line) 124839- } 124840- if printColumn { 124841- if printLine { 124842- fmt.Fprint(f, ":") 124843- } 124844- fmt.Fprintf(f, "%d", s.v.End.Column) 124845- } 124846- if printOffset { 124847- fmt.Fprintf(f, "#%d", s.v.End.Offset) 124848- } 124849-} 124850- 124851-// SetRange implements packagestest.rangeSetter, allowing 124852-// gopls' test suites to use Spans instead of Range in parameters. 124853-func (span *Span) SetRange(file *token.File, start, end token.Pos) { 124854- point := func(pos token.Pos) Point { 124855- posn := safetoken.Position(file, pos) 124856- return NewPoint(posn.Line, posn.Column, posn.Offset) 124857- } 124858- *span = New(URIFromPath(file.Name()), point(start), point(end)) 124859-} 124860diff -urN a/gopls/internal/span/span_test.go b/gopls/internal/span/span_test.go 124861--- a/gopls/internal/span/span_test.go 2000-01-01 00:00:00.000000000 -0000 124862+++ b/gopls/internal/span/span_test.go 1970-01-01 00:00:00.000000000 +0000 124863@@ -1,57 +0,0 @@ 124864-// Copyright 2019 The Go Authors. All rights reserved. 124865-// Use of this source code is governed by a BSD-style 124866-// license that can be found in the LICENSE file. 124867- 124868-package span_test 124869- 124870-import ( 124871- "fmt" 124872- "path/filepath" 124873- "strings" 124874- "testing" 124875- 124876- "golang.org/x/tools/gopls/internal/span" 124877-) 124878- 124879-func TestFormat(t *testing.T) { 124880- formats := []string{"%v", "%#v", "%+v"} 124881- 124882- // Element 0 is the input, and the elements 0-2 are the expected 124883- // output in [%v %#v %+v] formats. Thus the first must be in 124884- // canonical form (invariant under span.Parse + fmt.Sprint). 124885- // The '#' form displays offsets; the '+' form outputs a URI. 124886- // If len=4, element 0 is a noncanonical input and 1-3 are expected outputs. 124887- for _, test := range [][]string{ 124888- {"C:/file_a", "C:/file_a", "file:///C:/file_a:#0"}, 124889- {"C:/file_b:1:2", "C:/file_b:1:2", "file:///C:/file_b:1:2"}, 124890- {"C:/file_c:1000", "C:/file_c:1000", "file:///C:/file_c:1000:1"}, 124891- {"C:/file_d:14:9", "C:/file_d:14:9", "file:///C:/file_d:14:9"}, 124892- {"C:/file_e:1:2-7", "C:/file_e:1:2-7", "file:///C:/file_e:1:2-1:7"}, 124893- {"C:/file_f:500-502", "C:/file_f:500-502", "file:///C:/file_f:500:1-502:1"}, 124894- {"C:/file_g:3:7-8", "C:/file_g:3:7-8", "file:///C:/file_g:3:7-3:8"}, 124895- {"C:/file_h:3:7-4:8", "C:/file_h:3:7-4:8", "file:///C:/file_h:3:7-4:8"}, 124896- {"C:/file_i:#100", "C:/file_i:#100", "file:///C:/file_i:#100"}, 124897- {"C:/file_j:#26-#28", "C:/file_j:#26-#28", "file:///C:/file_j:#26-0#28"}, // 0#28? 124898- {"C:/file_h:3:7#26-4:8#37", // not canonical 124899- "C:/file_h:3:7-4:8", "C:/file_h:#26-#37", "file:///C:/file_h:3:7#26-4:8#37"}} { 124900- input := test[0] 124901- spn := span.Parse(input) 124902- wants := test[0:3] 124903- if len(test) == 4 { 124904- wants = test[1:4] 124905- } 124906- for i, format := range formats { 124907- want := toPath(wants[i]) 124908- if got := fmt.Sprintf(format, spn); got != want { 124909- t.Errorf("Sprintf(%q, %q) = %q, want %q", format, input, got, want) 124910- } 124911- } 124912- } 124913-} 124914- 124915-func toPath(value string) string { 124916- if strings.HasPrefix(value, "file://") { 124917- return value 124918- } 124919- return filepath.FromSlash(value) 124920-} 124921diff -urN a/gopls/internal/span/uri.go b/gopls/internal/span/uri.go 124922--- a/gopls/internal/span/uri.go 2000-01-01 00:00:00.000000000 -0000 124923+++ b/gopls/internal/span/uri.go 1970-01-01 00:00:00.000000000 +0000 124924@@ -1,185 +0,0 @@ 124925-// Copyright 2019 The Go Authors. All rights reserved. 124926-// Use of this source code is governed by a BSD-style 124927-// license that can be found in the LICENSE file. 124928- 124929-package span 124930- 124931-import ( 124932- "fmt" 124933- "net/url" 124934- "os" 124935- "path/filepath" 124936- "runtime" 124937- "strings" 124938- "unicode" 124939-) 124940- 124941-const fileScheme = "file" 124942- 124943-// URI represents the full URI for a file. 124944-type URI string 124945- 124946-func (uri URI) IsFile() bool { 124947- return strings.HasPrefix(string(uri), "file://") 124948-} 124949- 124950-// Filename returns the file path for the given URI. 124951-// It is an error to call this on a URI that is not a valid filename. 124952-func (uri URI) Filename() string { 124953- filename, err := filename(uri) 124954- if err != nil { 124955- panic(err) 124956- } 124957- return filepath.FromSlash(filename) 124958-} 124959- 124960-func filename(uri URI) (string, error) { 124961- if uri == "" { 124962- return "", nil 124963- } 124964- 124965- // This conservative check for the common case 124966- // of a simple non-empty absolute POSIX filename 124967- // avoids the allocation of a net.URL. 124968- if strings.HasPrefix(string(uri), "file:///") { 124969- rest := string(uri)[len("file://"):] // leave one slash 124970- for i := 0; i < len(rest); i++ { 124971- b := rest[i] 124972- // Reject these cases: 124973- if b < ' ' || b == 0x7f || // control character 124974- b == '%' || b == '+' || // URI escape 124975- b == ':' || // Windows drive letter 124976- b == '@' || b == '&' || b == '?' { // authority or query 124977- goto slow 124978- } 124979- } 124980- return rest, nil 124981- } 124982-slow: 124983- 124984- u, err := url.ParseRequestURI(string(uri)) 124985- if err != nil { 124986- return "", err 124987- } 124988- if u.Scheme != fileScheme { 124989- return "", fmt.Errorf("only file URIs are supported, got %q from %q", u.Scheme, uri) 124990- } 124991- // If the URI is a Windows URI, we trim the leading "/" and uppercase 124992- // the drive letter, which will never be case sensitive. 124993- if isWindowsDriveURIPath(u.Path) { 124994- u.Path = strings.ToUpper(string(u.Path[1])) + u.Path[2:] 124995- } 124996- 124997- return u.Path, nil 124998-} 124999- 125000-// TODO(adonovan): document this function, and any invariants of 125001-// span.URI that it is supposed to establish. 125002-func URIFromURI(s string) URI { 125003- if !strings.HasPrefix(s, "file://") { 125004- return URI(s) 125005- } 125006- 125007- if !strings.HasPrefix(s, "file:///") { 125008- // VS Code sends URLs with only two slashes, which are invalid. golang/go#39789. 125009- s = "file:///" + s[len("file://"):] 125010- } 125011- // Even though the input is a URI, it may not be in canonical form. VS Code 125012- // in particular over-escapes :, @, etc. Unescape and re-encode to canonicalize. 125013- path, err := url.PathUnescape(s[len("file://"):]) 125014- if err != nil { 125015- panic(err) 125016- } 125017- 125018- // File URIs from Windows may have lowercase drive letters. 125019- // Since drive letters are guaranteed to be case insensitive, 125020- // we change them to uppercase to remain consistent. 125021- // For example, file:///c:/x/y/z becomes file:///C:/x/y/z. 125022- if isWindowsDriveURIPath(path) { 125023- path = path[:1] + strings.ToUpper(string(path[1])) + path[2:] 125024- } 125025- u := url.URL{Scheme: fileScheme, Path: path} 125026- return URI(u.String()) 125027-} 125028- 125029-// SameExistingFile reports whether two spans denote the 125030-// same existing file by querying the file system. 125031-func SameExistingFile(a, b URI) bool { 125032- fa, err := filename(a) 125033- if err != nil { 125034- return false 125035- } 125036- fb, err := filename(b) 125037- if err != nil { 125038- return false 125039- } 125040- infoa, err := os.Stat(filepath.FromSlash(fa)) 125041- if err != nil { 125042- return false 125043- } 125044- infob, err := os.Stat(filepath.FromSlash(fb)) 125045- if err != nil { 125046- return false 125047- } 125048- return os.SameFile(infoa, infob) 125049-} 125050- 125051-// URIFromPath returns a span URI for the supplied file path. 125052-// 125053-// For empty paths, URIFromPath returns the empty URI "". 125054-// For non-empty paths, URIFromPath returns a uri with the file:// scheme. 125055-func URIFromPath(path string) URI { 125056- if path == "" { 125057- return "" 125058- } 125059- // Handle standard library paths that contain the literal "$GOROOT". 125060- // TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT. 125061- const prefix = "$GOROOT" 125062- if len(path) >= len(prefix) && strings.EqualFold(prefix, path[:len(prefix)]) { 125063- suffix := path[len(prefix):] 125064- path = runtime.GOROOT() + suffix 125065- } 125066- if !isWindowsDrivePath(path) { 125067- if abs, err := filepath.Abs(path); err == nil { 125068- path = abs 125069- } 125070- } 125071- // Check the file path again, in case it became absolute. 125072- if isWindowsDrivePath(path) { 125073- path = "/" + strings.ToUpper(string(path[0])) + path[1:] 125074- } 125075- path = filepath.ToSlash(path) 125076- u := url.URL{ 125077- Scheme: fileScheme, 125078- Path: path, 125079- } 125080- return URI(u.String()) 125081-} 125082- 125083-// isWindowsDrivePath returns true if the file path is of the form used by 125084-// Windows. We check if the path begins with a drive letter, followed by a ":". 125085-// For example: C:/x/y/z. 125086-func isWindowsDrivePath(path string) bool { 125087- if len(path) < 3 { 125088- return false 125089- } 125090- return unicode.IsLetter(rune(path[0])) && path[1] == ':' 125091-} 125092- 125093-// isWindowsDriveURIPath returns true if the file URI is of the format used by 125094-// Windows URIs. The url.Parse package does not specially handle Windows paths 125095-// (see golang/go#6027), so we check if the URI path has a drive prefix (e.g. "/C:"). 125096-func isWindowsDriveURIPath(uri string) bool { 125097- if len(uri) < 4 { 125098- return false 125099- } 125100- return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':' 125101-} 125102- 125103-// Dir returns the URI for the directory containing uri. Dir panics if uri is 125104-// not a file uri. 125105-// 125106-// TODO(rfindley): add a unit test for various edge cases. 125107-func Dir(uri URI) URI { 125108- return URIFromPath(filepath.Dir(uri.Filename())) 125109-} 125110diff -urN a/gopls/internal/span/uri_test.go b/gopls/internal/span/uri_test.go 125111--- a/gopls/internal/span/uri_test.go 2000-01-01 00:00:00.000000000 -0000 125112+++ b/gopls/internal/span/uri_test.go 1970-01-01 00:00:00.000000000 +0000 125113@@ -1,117 +0,0 @@ 125114-// Copyright 2019 The Go Authors. All rights reserved. 125115-// Use of this source code is governed by a BSD-style 125116-// license that can be found in the LICENSE file. 125117- 125118-//go:build !windows 125119-// +build !windows 125120- 125121-package span_test 125122- 125123-import ( 125124- "testing" 125125- 125126- "golang.org/x/tools/gopls/internal/span" 125127-) 125128- 125129-// TestURI tests the conversion between URIs and filenames. The test cases 125130-// include Windows-style URIs and filepaths, but we avoid having OS-specific 125131-// tests by using only forward slashes, assuming that the standard library 125132-// functions filepath.ToSlash and filepath.FromSlash do not need testing. 125133-func TestURIFromPath(t *testing.T) { 125134- for _, test := range []struct { 125135- path, wantFile string 125136- wantURI span.URI 125137- }{ 125138- { 125139- path: ``, 125140- wantFile: ``, 125141- wantURI: span.URI(""), 125142- }, 125143- { 125144- path: `C:/Windows/System32`, 125145- wantFile: `C:/Windows/System32`, 125146- wantURI: span.URI("file:///C:/Windows/System32"), 125147- }, 125148- { 125149- path: `C:/Go/src/bob.go`, 125150- wantFile: `C:/Go/src/bob.go`, 125151- wantURI: span.URI("file:///C:/Go/src/bob.go"), 125152- }, 125153- { 125154- path: `c:/Go/src/bob.go`, 125155- wantFile: `C:/Go/src/bob.go`, 125156- wantURI: span.URI("file:///C:/Go/src/bob.go"), 125157- }, 125158- { 125159- path: `/path/to/dir`, 125160- wantFile: `/path/to/dir`, 125161- wantURI: span.URI("file:///path/to/dir"), 125162- }, 125163- { 125164- path: `/a/b/c/src/bob.go`, 125165- wantFile: `/a/b/c/src/bob.go`, 125166- wantURI: span.URI("file:///a/b/c/src/bob.go"), 125167- }, 125168- { 125169- path: `c:/Go/src/bob george/george/george.go`, 125170- wantFile: `C:/Go/src/bob george/george/george.go`, 125171- wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), 125172- }, 125173- } { 125174- got := span.URIFromPath(test.path) 125175- if got != test.wantURI { 125176- t.Errorf("URIFromPath(%q): got %q, expected %q", test.path, got, test.wantURI) 125177- } 125178- gotFilename := got.Filename() 125179- if gotFilename != test.wantFile { 125180- t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile) 125181- } 125182- } 125183-} 125184- 125185-func TestURIFromURI(t *testing.T) { 125186- for _, test := range []struct { 125187- inputURI, wantFile string 125188- wantURI span.URI 125189- }{ 125190- { 125191- inputURI: `file:///c:/Go/src/bob%20george/george/george.go`, 125192- wantFile: `C:/Go/src/bob george/george/george.go`, 125193- wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), 125194- }, 125195- { 125196- inputURI: `file:///C%3A/Go/src/bob%20george/george/george.go`, 125197- wantFile: `C:/Go/src/bob george/george/george.go`, 125198- wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), 125199- }, 125200- { 125201- inputURI: `file:///path/to/%25p%25ercent%25/per%25cent.go`, 125202- wantFile: `/path/to/%p%ercent%/per%cent.go`, 125203- wantURI: span.URI(`file:///path/to/%25p%25ercent%25/per%25cent.go`), 125204- }, 125205- { 125206- inputURI: `file:///C%3A/`, 125207- wantFile: `C:/`, 125208- wantURI: span.URI(`file:///C:/`), 125209- }, 125210- { 125211- inputURI: `file:///`, 125212- wantFile: `/`, 125213- wantURI: span.URI(`file:///`), 125214- }, 125215- { 125216- inputURI: `file://wsl%24/Ubuntu/home/wdcui/repo/VMEnclaves/cvm-runtime`, 125217- wantFile: `/wsl$/Ubuntu/home/wdcui/repo/VMEnclaves/cvm-runtime`, 125218- wantURI: span.URI(`file:///wsl$/Ubuntu/home/wdcui/repo/VMEnclaves/cvm-runtime`), 125219- }, 125220- } { 125221- got := span.URIFromURI(test.inputURI) 125222- if got != test.wantURI { 125223- t.Errorf("NewURI(%q): got %q, expected %q", test.inputURI, got, test.wantURI) 125224- } 125225- gotFilename := got.Filename() 125226- if gotFilename != test.wantFile { 125227- t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile) 125228- } 125229- } 125230-} 125231diff -urN a/gopls/internal/span/uri_windows_test.go b/gopls/internal/span/uri_windows_test.go 125232--- a/gopls/internal/span/uri_windows_test.go 2000-01-01 00:00:00.000000000 -0000 125233+++ b/gopls/internal/span/uri_windows_test.go 1970-01-01 00:00:00.000000000 +0000 125234@@ -1,112 +0,0 @@ 125235-// Copyright 2020 The Go Authors. All rights reserved. 125236-// Use of this source code is governed by a BSD-style 125237-// license that can be found in the LICENSE file. 125238- 125239-//go:build windows 125240-// +build windows 125241- 125242-package span_test 125243- 125244-import ( 125245- "testing" 125246- 125247- "golang.org/x/tools/gopls/internal/span" 125248-) 125249- 125250-// TestURI tests the conversion between URIs and filenames. The test cases 125251-// include Windows-style URIs and filepaths, but we avoid having OS-specific 125252-// tests by using only forward slashes, assuming that the standard library 125253-// functions filepath.ToSlash and filepath.FromSlash do not need testing. 125254-func TestURIFromPath(t *testing.T) { 125255- for _, test := range []struct { 125256- path, wantFile string 125257- wantURI span.URI 125258- }{ 125259- { 125260- path: ``, 125261- wantFile: ``, 125262- wantURI: span.URI(""), 125263- }, 125264- { 125265- path: `C:\Windows\System32`, 125266- wantFile: `C:\Windows\System32`, 125267- wantURI: span.URI("file:///C:/Windows/System32"), 125268- }, 125269- { 125270- path: `C:\Go\src\bob.go`, 125271- wantFile: `C:\Go\src\bob.go`, 125272- wantURI: span.URI("file:///C:/Go/src/bob.go"), 125273- }, 125274- { 125275- path: `c:\Go\src\bob.go`, 125276- wantFile: `C:\Go\src\bob.go`, 125277- wantURI: span.URI("file:///C:/Go/src/bob.go"), 125278- }, 125279- { 125280- path: `\path\to\dir`, 125281- wantFile: `C:\path\to\dir`, 125282- wantURI: span.URI("file:///C:/path/to/dir"), 125283- }, 125284- { 125285- path: `\a\b\c\src\bob.go`, 125286- wantFile: `C:\a\b\c\src\bob.go`, 125287- wantURI: span.URI("file:///C:/a/b/c/src/bob.go"), 125288- }, 125289- { 125290- path: `c:\Go\src\bob george\george\george.go`, 125291- wantFile: `C:\Go\src\bob george\george\george.go`, 125292- wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), 125293- }, 125294- } { 125295- got := span.URIFromPath(test.path) 125296- if got != test.wantURI { 125297- t.Errorf("URIFromPath(%q): got %q, expected %q", test.path, got, test.wantURI) 125298- } 125299- gotFilename := got.Filename() 125300- if gotFilename != test.wantFile { 125301- t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile) 125302- } 125303- } 125304-} 125305- 125306-func TestURIFromURI(t *testing.T) { 125307- for _, test := range []struct { 125308- inputURI, wantFile string 125309- wantURI span.URI 125310- }{ 125311- { 125312- inputURI: `file:///c:/Go/src/bob%20george/george/george.go`, 125313- wantFile: `C:\Go\src\bob george\george\george.go`, 125314- wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), 125315- }, 125316- { 125317- inputURI: `file:///C%3A/Go/src/bob%20george/george/george.go`, 125318- wantFile: `C:\Go\src\bob george\george\george.go`, 125319- wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), 125320- }, 125321- { 125322- inputURI: `file:///c:/path/to/%25p%25ercent%25/per%25cent.go`, 125323- wantFile: `C:\path\to\%p%ercent%\per%cent.go`, 125324- wantURI: span.URI(`file:///C:/path/to/%25p%25ercent%25/per%25cent.go`), 125325- }, 125326- { 125327- inputURI: `file:///C%3A/`, 125328- wantFile: `C:\`, 125329- wantURI: span.URI(`file:///C:/`), 125330- }, 125331- { 125332- inputURI: `file:///`, 125333- wantFile: `\`, 125334- wantURI: span.URI(`file:///`), 125335- }, 125336- } { 125337- got := span.URIFromURI(test.inputURI) 125338- if got != test.wantURI { 125339- t.Errorf("NewURI(%q): got %q, expected %q", test.inputURI, got, test.wantURI) 125340- } 125341- gotFilename := got.Filename() 125342- if gotFilename != test.wantFile { 125343- t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile) 125344- } 125345- } 125346-} 125347diff -urN a/gopls/internal/vulncheck/command.go b/gopls/internal/vulncheck/command.go 125348--- a/gopls/internal/vulncheck/command.go 2000-01-01 00:00:00.000000000 -0000 125349+++ b/gopls/internal/vulncheck/command.go 1970-01-01 00:00:00.000000000 +0000 125350@@ -1,381 +0,0 @@ 125351-// Copyright 2022 The Go Authors. All rights reserved. 125352-// Use of this source code is governed by a BSD-style 125353-// license that can be found in the LICENSE file. 125354- 125355-//go:build go1.18 125356-// +build go1.18 125357- 125358-package vulncheck 125359- 125360-import ( 125361- "context" 125362- "encoding/json" 125363- "errors" 125364- "fmt" 125365- "log" 125366- "os" 125367- "regexp" 125368- "sort" 125369- "strings" 125370- "sync" 125371- 125372- "golang.org/x/mod/semver" 125373- "golang.org/x/sync/errgroup" 125374- "golang.org/x/tools/go/packages" 125375- "golang.org/x/tools/gopls/internal/govulncheck" 125376- "golang.org/x/tools/gopls/internal/lsp/source" 125377- "golang.org/x/vuln/client" 125378- gvcapi "golang.org/x/vuln/exp/govulncheck" 125379- "golang.org/x/vuln/osv" 125380- "golang.org/x/vuln/vulncheck" 125381-) 125382- 125383-func init() { 125384- VulnerablePackages = vulnerablePackages 125385-} 125386- 125387-func findGOVULNDB(env []string) []string { 125388- for _, kv := range env { 125389- if strings.HasPrefix(kv, "GOVULNDB=") { 125390- return strings.Split(kv[len("GOVULNDB="):], ",") 125391- } 125392- } 125393- if GOVULNDB := os.Getenv("GOVULNDB"); GOVULNDB != "" { 125394- return strings.Split(GOVULNDB, ",") 125395- } 125396- return []string{"https://vuln.go.dev"} 125397-} 125398- 125399-// GoVersionForVulnTest is an internal environment variable used in gopls 125400-// testing to examine govulncheck behavior with a go version different 125401-// than what `go version` returns in the system. 125402-const GoVersionForVulnTest = "_GOPLS_TEST_VULNCHECK_GOVERSION" 125403- 125404-func init() { 125405- Main = func(cfg packages.Config, patterns ...string) error { 125406- // Set the mode that Source needs. 125407- cfg.Mode = packages.NeedName | packages.NeedImports | packages.NeedTypes | 125408- packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps | 125409- packages.NeedModule 125410- logf := log.New(os.Stderr, "", log.Ltime).Printf 125411- logf("Loading packages...") 125412- pkgs, err := packages.Load(&cfg, patterns...) 125413- if err != nil { 125414- logf("Failed to load packages: %v", err) 125415- return err 125416- } 125417- if n := packages.PrintErrors(pkgs); n > 0 { 125418- err := errors.New("failed to load packages due to errors") 125419- logf("%v", err) 125420- return err 125421- } 125422- logf("Loaded %d packages and their dependencies", len(pkgs)) 125423- cache, err := govulncheck.DefaultCache() 125424- if err != nil { 125425- return err 125426- } 125427- cli, err := client.NewClient(findGOVULNDB(cfg.Env), client.Options{ 125428- HTTPCache: cache, 125429- }) 125430- if err != nil { 125431- return err 125432- } 125433- res, err := gvcapi.Source(context.Background(), &gvcapi.Config{ 125434- Client: cli, 125435- GoVersion: os.Getenv(GoVersionForVulnTest), 125436- }, vulncheck.Convert(pkgs)) 125437- if err != nil { 125438- return err 125439- } 125440- affecting := 0 125441- for _, v := range res.Vulns { 125442- if v.IsCalled() { 125443- affecting++ 125444- } 125445- } 125446- logf("Found %d affecting vulns and %d unaffecting vulns in imported packages", affecting, len(res.Vulns)-affecting) 125447- if err := json.NewEncoder(os.Stdout).Encode(res); err != nil { 125448- return err 125449- } 125450- return nil 125451- } 125452-} 125453- 125454-var ( 125455- // Regexp for matching go tags. The groups are: 125456- // 1 the major.minor version 125457- // 2 the patch version, or empty if none 125458- // 3 the entire prerelease, if present 125459- // 4 the prerelease type ("beta" or "rc") 125460- // 5 the prerelease number 125461- tagRegexp = regexp.MustCompile(`^go(\d+\.\d+)(\.\d+|)((beta|rc|-pre)(\d+))?$`) 125462-) 125463- 125464-// This is a modified copy of pkgsite/internal/stdlib:VersionForTag. 125465-func GoTagToSemver(tag string) string { 125466- if tag == "" { 125467- return "" 125468- } 125469- 125470- tag = strings.Fields(tag)[0] 125471- // Special cases for go1. 125472- if tag == "go1" { 125473- return "v1.0.0" 125474- } 125475- if tag == "go1.0" { 125476- return "" 125477- } 125478- m := tagRegexp.FindStringSubmatch(tag) 125479- if m == nil { 125480- return "" 125481- } 125482- version := "v" + m[1] 125483- if m[2] != "" { 125484- version += m[2] 125485- } else { 125486- version += ".0" 125487- } 125488- if m[3] != "" { 125489- if !strings.HasPrefix(m[4], "-") { 125490- version += "-" 125491- } 125492- version += m[4] + "." + m[5] 125493- } 125494- return version 125495-} 125496- 125497-// semverToGoTag returns the Go standard library repository tag corresponding 125498-// to semver, a version string without the initial "v". 125499-// Go tags differ from standard semantic versions in a few ways, 125500-// such as beginning with "go" instead of "v". 125501-func semverToGoTag(v string) string { 125502- if strings.HasPrefix(v, "v0.0.0") { 125503- return "master" 125504- } 125505- // Special case: v1.0.0 => go1. 125506- if v == "v1.0.0" { 125507- return "go1" 125508- } 125509- if !semver.IsValid(v) { 125510- return fmt.Sprintf("<!%s:invalid semver>", v) 125511- } 125512- goVersion := semver.Canonical(v) 125513- prerelease := semver.Prerelease(goVersion) 125514- versionWithoutPrerelease := strings.TrimSuffix(goVersion, prerelease) 125515- patch := strings.TrimPrefix(versionWithoutPrerelease, semver.MajorMinor(goVersion)+".") 125516- if patch == "0" { 125517- versionWithoutPrerelease = strings.TrimSuffix(versionWithoutPrerelease, ".0") 125518- } 125519- goVersion = fmt.Sprintf("go%s", strings.TrimPrefix(versionWithoutPrerelease, "v")) 125520- if prerelease != "" { 125521- // Go prereleases look like "beta1" instead of "beta.1". 125522- // "beta1" is bad for sorting (since beta10 comes before beta9), so 125523- // require the dot form. 125524- i := finalDigitsIndex(prerelease) 125525- if i >= 1 { 125526- if prerelease[i-1] != '.' { 125527- return fmt.Sprintf("<!%s:final digits in a prerelease must follow a period>", v) 125528- } 125529- // Remove the dot. 125530- prerelease = prerelease[:i-1] + prerelease[i:] 125531- } 125532- goVersion += strings.TrimPrefix(prerelease, "-") 125533- } 125534- return goVersion 125535-} 125536- 125537-// finalDigitsIndex returns the index of the first digit in the sequence of digits ending s. 125538-// If s doesn't end in digits, it returns -1. 125539-func finalDigitsIndex(s string) int { 125540- // Assume ASCII (since the semver package does anyway). 125541- var i int 125542- for i = len(s) - 1; i >= 0; i-- { 125543- if s[i] < '0' || s[i] > '9' { 125544- break 125545- } 125546- } 125547- if i == len(s)-1 { 125548- return -1 125549- } 125550- return i + 1 125551-} 125552- 125553-// vulnerablePackages queries the vulndb and reports which vulnerabilities 125554-// apply to this snapshot. The result contains a set of packages, 125555-// grouped by vuln ID and by module. 125556-func vulnerablePackages(ctx context.Context, snapshot source.Snapshot, modfile source.FileHandle) (*govulncheck.Result, error) { 125557- // We want to report the intersection of vulnerable packages in the vulndb 125558- // and packages transitively imported by this module ('go list -deps all'). 125559- // We use snapshot.AllMetadata to retrieve the list of packages 125560- // as an approximation. 125561- // 125562- // TODO(hyangah): snapshot.AllMetadata is a superset of 125563- // `go list all` - e.g. when the workspace has multiple main modules 125564- // (multiple go.mod files), that can include packages that are not 125565- // used by this module. Vulncheck behavior with go.work is not well 125566- // defined. Figure out the meaning, and if we decide to present 125567- // the result as if each module is analyzed independently, make 125568- // gopls track a separate build list for each module and use that 125569- // information instead of snapshot.AllMetadata. 125570- metadata, err := snapshot.AllMetadata(ctx) 125571- if err != nil { 125572- return nil, err 125573- } 125574- 125575- // TODO(hyangah): handle vulnerabilities in the standard library. 125576- 125577- // Group packages by modules since vuln db is keyed by module. 125578- metadataByModule := map[source.PackagePath][]*source.Metadata{} 125579- for _, md := range metadata { 125580- mi := md.Module 125581- modulePath := source.PackagePath("stdlib") 125582- if mi != nil { 125583- modulePath = source.PackagePath(mi.Path) 125584- } 125585- metadataByModule[modulePath] = append(metadataByModule[modulePath], md) 125586- } 125587- 125588- // Request vuln entries from remote service. 125589- fsCache, err := govulncheck.DefaultCache() 125590- if err != nil { 125591- return nil, err 125592- } 125593- cli, err := client.NewClient( 125594- findGOVULNDB(snapshot.View().Options().EnvSlice()), 125595- client.Options{HTTPCache: govulncheck.NewInMemoryCache(fsCache)}) 125596- if err != nil { 125597- return nil, err 125598- } 125599- // Keys are osv.Entry.IDs 125600- vulnsResult := map[string]*govulncheck.Vuln{} 125601- var ( 125602- group errgroup.Group 125603- mu sync.Mutex 125604- ) 125605- 125606- goVersion := snapshot.View().Options().Env[GoVersionForVulnTest] 125607- if goVersion == "" { 125608- goVersion = snapshot.View().GoVersionString() 125609- } 125610- group.SetLimit(10) 125611- stdlibModule := &packages.Module{ 125612- Path: "stdlib", 125613- Version: goVersion, 125614- } 125615- for path, mds := range metadataByModule { 125616- path, mds := path, mds 125617- group.Go(func() error { 125618- effectiveModule := stdlibModule 125619- if m := mds[0].Module; m != nil { 125620- effectiveModule = m 125621- } 125622- for effectiveModule.Replace != nil { 125623- effectiveModule = effectiveModule.Replace 125624- } 125625- ver := effectiveModule.Version 125626- 125627- // TODO(go.dev/issues/56312): batch these requests for efficiency. 125628- vulns, err := cli.GetByModule(ctx, effectiveModule.Path) 125629- if err != nil { 125630- return err 125631- } 125632- if len(vulns) == 0 { // No known vulnerability. 125633- return nil 125634- } 125635- 125636- // set of packages in this module known to gopls. 125637- // This will be lazily initialized when we need it. 125638- var knownPkgs map[source.PackagePath]bool 125639- 125640- // Report vulnerabilities that affect packages of this module. 125641- for _, entry := range vulns { 125642- var vulnerablePkgs []*govulncheck.Package 125643- 125644- for _, a := range entry.Affected { 125645- if a.Package.Ecosystem != osv.GoEcosystem || a.Package.Name != effectiveModule.Path { 125646- continue 125647- } 125648- if !a.Ranges.AffectsSemver(ver) { 125649- continue 125650- } 125651- for _, imp := range a.EcosystemSpecific.Imports { 125652- if knownPkgs == nil { 125653- knownPkgs = toPackagePathSet(mds) 125654- } 125655- if knownPkgs[source.PackagePath(imp.Path)] { 125656- vulnerablePkgs = append(vulnerablePkgs, &govulncheck.Package{ 125657- Path: imp.Path, 125658- }) 125659- } 125660- } 125661- } 125662- if len(vulnerablePkgs) == 0 { 125663- continue 125664- } 125665- mu.Lock() 125666- vuln, ok := vulnsResult[entry.ID] 125667- if !ok { 125668- vuln = &govulncheck.Vuln{OSV: entry} 125669- vulnsResult[entry.ID] = vuln 125670- } 125671- vuln.Modules = append(vuln.Modules, &govulncheck.Module{ 125672- Path: string(path), 125673- FoundVersion: ver, 125674- FixedVersion: fixedVersion(effectiveModule.Path, entry.Affected), 125675- Packages: vulnerablePkgs, 125676- }) 125677- mu.Unlock() 125678- } 125679- return nil 125680- }) 125681- } 125682- if err := group.Wait(); err != nil { 125683- return nil, err 125684- } 125685- 125686- vulns := make([]*govulncheck.Vuln, 0, len(vulnsResult)) 125687- for _, v := range vulnsResult { 125688- vulns = append(vulns, v) 125689- } 125690- // Sort so the results are deterministic. 125691- sort.Slice(vulns, func(i, j int) bool { 125692- return vulns[i].OSV.ID < vulns[j].OSV.ID 125693- }) 125694- ret := &govulncheck.Result{ 125695- Vulns: vulns, 125696- Mode: govulncheck.ModeImports, 125697- } 125698- return ret, nil 125699-} 125700- 125701-// toPackagePathSet transforms the metadata to a set of package paths. 125702-func toPackagePathSet(mds []*source.Metadata) map[source.PackagePath]bool { 125703- pkgPaths := make(map[source.PackagePath]bool, len(mds)) 125704- for _, md := range mds { 125705- pkgPaths[md.PkgPath] = true 125706- } 125707- return pkgPaths 125708-} 125709- 125710-func fixedVersion(modulePath string, affected []osv.Affected) string { 125711- fixed := govulncheck.LatestFixed(modulePath, affected) 125712- if fixed != "" { 125713- fixed = versionString(modulePath, fixed) 125714- } 125715- return fixed 125716-} 125717- 125718-// versionString prepends a version string prefix (`v` or `go` 125719-// depending on the modulePath) to the given semver-style version string. 125720-func versionString(modulePath, version string) string { 125721- if version == "" { 125722- return "" 125723- } 125724- v := "v" + version 125725- // These are internal Go module paths used by the vuln DB 125726- // when listing vulns in standard library and the go command. 125727- if modulePath == "stdlib" || modulePath == "toolchain" { 125728- return semverToGoTag(v) 125729- } 125730- return v 125731-} 125732diff -urN a/gopls/internal/vulncheck/vulncheck.go b/gopls/internal/vulncheck/vulncheck.go 125733--- a/gopls/internal/vulncheck/vulncheck.go 2000-01-01 00:00:00.000000000 -0000 125734+++ b/gopls/internal/vulncheck/vulncheck.go 1970-01-01 00:00:00.000000000 +0000 125735@@ -1,25 +0,0 @@ 125736-// Copyright 2022 The Go Authors. All rights reserved. 125737-// Use of this source code is governed by a BSD-style 125738-// license that can be found in the LICENSE file. 125739- 125740-// Package vulncheck provides an analysis command 125741-// that runs vulnerability analysis using data from 125742-// golang.org/x/vuln/vulncheck. 125743-// This package requires go1.18 or newer. 125744-package vulncheck 125745- 125746-import ( 125747- "context" 125748- 125749- "golang.org/x/tools/go/packages" 125750- "golang.org/x/tools/gopls/internal/govulncheck" 125751- "golang.org/x/tools/gopls/internal/lsp/source" 125752-) 125753- 125754-// With go1.18+, this is swapped with the real implementation. 125755-var Main func(cfg packages.Config, patterns ...string) error = nil 125756- 125757-// VulnerablePackages queries the vulndb and reports which vulnerabilities 125758-// apply to this snapshot. The result contains a set of packages, 125759-// grouped by vuln ID and by module. 125760-var VulnerablePackages func(ctx context.Context, snapshot source.Snapshot, modfile source.FileHandle) (*govulncheck.Result, error) = nil 125761diff -urN a/gopls/internal/vulncheck/vulntest/db.go b/gopls/internal/vulncheck/vulntest/db.go 125762--- a/gopls/internal/vulncheck/vulntest/db.go 2000-01-01 00:00:00.000000000 -0000 125763+++ b/gopls/internal/vulncheck/vulntest/db.go 1970-01-01 00:00:00.000000000 +0000 125764@@ -1,303 +0,0 @@ 125765-// Copyright 2022 The Go Authors. All rights reserved. 125766-// Use of this source code is governed by a BSD-style 125767-// license that can be found in the LICENSE file. 125768- 125769-//go:build go1.18 125770-// +build go1.18 125771- 125772-// Package vulntest provides helpers for vulncheck functionality testing. 125773-package vulntest 125774- 125775-import ( 125776- "bytes" 125777- "context" 125778- "encoding/json" 125779- "fmt" 125780- "io/ioutil" 125781- "os" 125782- "path/filepath" 125783- "sort" 125784- "strings" 125785- "time" 125786- 125787- "golang.org/x/tools/gopls/internal/span" 125788- "golang.org/x/tools/txtar" 125789- "golang.org/x/vuln/client" 125790- "golang.org/x/vuln/osv" 125791-) 125792- 125793-// NewDatabase returns a read-only DB containing the provided 125794-// txtar-format collection of vulnerability reports. 125795-// Each vulnerability report is a YAML file whose format 125796-// is defined in golang.org/x/vulndb/doc/format.md. 125797-// A report file name must have the id as its base name, 125798-// and have .yaml as its extension. 125799-// 125800-// db, err := NewDatabase(ctx, reports) 125801-// ... 125802-// defer db.Clean() 125803-// client, err := NewClient(db) 125804-// ... 125805-// 125806-// The returned DB's Clean method must be called to clean up the 125807-// generated database. 125808-func NewDatabase(ctx context.Context, txtarReports []byte) (*DB, error) { 125809- disk, err := ioutil.TempDir("", "vulndb-test") 125810- if err != nil { 125811- return nil, err 125812- } 125813- if err := generateDB(ctx, txtarReports, disk, false); err != nil { 125814- os.RemoveAll(disk) 125815- return nil, err 125816- } 125817- 125818- return &DB{disk: disk}, nil 125819-} 125820- 125821-// DB is a read-only vulnerability database on disk. 125822-// Users can use this database with golang.org/x/vuln APIs 125823-// by setting the `VULNDB“ environment variable. 125824-type DB struct { 125825- disk string 125826-} 125827- 125828-// URI returns the file URI that can be used for VULNDB environment 125829-// variable. 125830-func (db *DB) URI() string { 125831- u := span.URIFromPath(db.disk) 125832- return string(u) 125833-} 125834- 125835-// Clean deletes the database. 125836-func (db *DB) Clean() error { 125837- return os.RemoveAll(db.disk) 125838-} 125839- 125840-// NewClient returns a vuln DB client that works with the given DB. 125841-func NewClient(db *DB) (client.Client, error) { 125842- return client.NewClient([]string{db.URI()}, client.Options{}) 125843-} 125844- 125845-// 125846-// The following was selectively copied from golang.org/x/vulndb/internal/database 125847-// 125848- 125849-const ( 125850- dbURL = "https://pkg.go.dev/vuln/" 125851- 125852- // idDirectory is the name of the directory that contains entries 125853- // listed by their IDs. 125854- idDirectory = "ID" 125855- 125856- // stdFileName is the name of the .json file in the vulndb repo 125857- // that will contain info on standard library vulnerabilities. 125858- stdFileName = "stdlib" 125859- 125860- // toolchainFileName is the name of the .json file in the vulndb repo 125861- // that will contain info on toolchain (cmd/...) vulnerabilities. 125862- toolchainFileName = "toolchain" 125863- 125864- // cmdModule is the name of the module containing Go toolchain 125865- // binaries. 125866- cmdModule = "cmd" 125867- 125868- // stdModule is the name of the module containing Go std packages. 125869- stdModule = "std" 125870-) 125871- 125872-// generateDB generates the file-based vuln DB in the directory jsonDir. 125873-func generateDB(ctx context.Context, txtarData []byte, jsonDir string, indent bool) error { 125874- archive := txtar.Parse(txtarData) 125875- 125876- jsonVulns, entries, err := generateEntries(ctx, archive) 125877- if err != nil { 125878- return err 125879- } 125880- 125881- index := make(client.DBIndex, len(jsonVulns)) 125882- for modulePath, vulns := range jsonVulns { 125883- epath, err := client.EscapeModulePath(modulePath) 125884- if err != nil { 125885- return err 125886- } 125887- if err := writeVulns(filepath.Join(jsonDir, epath), vulns, indent); err != nil { 125888- return err 125889- } 125890- for _, v := range vulns { 125891- if v.Modified.After(index[modulePath]) { 125892- index[modulePath] = v.Modified 125893- } 125894- } 125895- } 125896- if err := writeJSON(filepath.Join(jsonDir, "index.json"), index, indent); err != nil { 125897- return err 125898- } 125899- if err := writeAliasIndex(jsonDir, entries, indent); err != nil { 125900- return err 125901- } 125902- return writeEntriesByID(filepath.Join(jsonDir, idDirectory), entries, indent) 125903-} 125904- 125905-func generateEntries(_ context.Context, archive *txtar.Archive) (map[string][]osv.Entry, []osv.Entry, error) { 125906- now := time.Now() 125907- jsonVulns := map[string][]osv.Entry{} 125908- var entries []osv.Entry 125909- for _, f := range archive.Files { 125910- if !strings.HasSuffix(f.Name, ".yaml") { 125911- continue 125912- } 125913- r, err := readReport(bytes.NewReader(f.Data)) 125914- if err != nil { 125915- return nil, nil, err 125916- } 125917- name := strings.TrimSuffix(filepath.Base(f.Name), filepath.Ext(f.Name)) 125918- linkName := fmt.Sprintf("%s%s", dbURL, name) 125919- entry, modulePaths := generateOSVEntry(name, linkName, now, *r) 125920- for _, modulePath := range modulePaths { 125921- jsonVulns[modulePath] = append(jsonVulns[modulePath], entry) 125922- } 125923- entries = append(entries, entry) 125924- } 125925- return jsonVulns, entries, nil 125926-} 125927- 125928-func writeVulns(outPath string, vulns []osv.Entry, indent bool) error { 125929- if err := os.MkdirAll(filepath.Dir(outPath), 0755); err != nil { 125930- return fmt.Errorf("failed to create directory %q: %s", filepath.Dir(outPath), err) 125931- } 125932- return writeJSON(outPath+".json", vulns, indent) 125933-} 125934- 125935-func writeEntriesByID(idDir string, entries []osv.Entry, indent bool) error { 125936- // Write a directory containing entries by ID. 125937- if err := os.MkdirAll(idDir, 0755); err != nil { 125938- return fmt.Errorf("failed to create directory %q: %v", idDir, err) 125939- } 125940- var idIndex []string 125941- for _, e := range entries { 125942- outPath := filepath.Join(idDir, e.ID+".json") 125943- if err := writeJSON(outPath, e, indent); err != nil { 125944- return err 125945- } 125946- idIndex = append(idIndex, e.ID) 125947- } 125948- // Write an index.json in the ID directory with a list of all the IDs. 125949- return writeJSON(filepath.Join(idDir, "index.json"), idIndex, indent) 125950-} 125951- 125952-// Write a JSON file containing a map from alias to GO IDs. 125953-func writeAliasIndex(dir string, entries []osv.Entry, indent bool) error { 125954- aliasToGoIDs := map[string][]string{} 125955- for _, e := range entries { 125956- for _, a := range e.Aliases { 125957- aliasToGoIDs[a] = append(aliasToGoIDs[a], e.ID) 125958- } 125959- } 125960- return writeJSON(filepath.Join(dir, "aliases.json"), aliasToGoIDs, indent) 125961-} 125962- 125963-func writeJSON(filename string, value any, indent bool) (err error) { 125964- j, err := jsonMarshal(value, indent) 125965- if err != nil { 125966- return err 125967- } 125968- return os.WriteFile(filename, j, 0644) 125969-} 125970- 125971-func jsonMarshal(v any, indent bool) ([]byte, error) { 125972- if indent { 125973- return json.MarshalIndent(v, "", " ") 125974- } 125975- return json.Marshal(v) 125976-} 125977- 125978-// generateOSVEntry create an osv.Entry for a report. In addition to the report, it 125979-// takes the ID for the vuln and a URL that will point to the entry in the vuln DB. 125980-// It returns the osv.Entry and a list of module paths that the vuln affects. 125981-func generateOSVEntry(id, url string, lastModified time.Time, r Report) (osv.Entry, []string) { 125982- entry := osv.Entry{ 125983- ID: id, 125984- Published: r.Published, 125985- Modified: lastModified, 125986- Withdrawn: r.Withdrawn, 125987- Details: r.Description, 125988- } 125989- 125990- moduleMap := make(map[string]bool) 125991- for _, m := range r.Modules { 125992- switch m.Module { 125993- case stdModule: 125994- moduleMap[stdFileName] = true 125995- case cmdModule: 125996- moduleMap[toolchainFileName] = true 125997- default: 125998- moduleMap[m.Module] = true 125999- } 126000- entry.Affected = append(entry.Affected, generateAffected(m, url)) 126001- } 126002- for _, ref := range r.References { 126003- entry.References = append(entry.References, osv.Reference{ 126004- Type: string(ref.Type), 126005- URL: ref.URL, 126006- }) 126007- } 126008- 126009- var modulePaths []string 126010- for module := range moduleMap { 126011- modulePaths = append(modulePaths, module) 126012- } 126013- // TODO: handle missing fields - Aliases 126014- 126015- return entry, modulePaths 126016-} 126017- 126018-func generateAffectedRanges(versions []VersionRange) osv.Affects { 126019- a := osv.AffectsRange{Type: osv.TypeSemver} 126020- if len(versions) == 0 || versions[0].Introduced == "" { 126021- a.Events = append(a.Events, osv.RangeEvent{Introduced: "0"}) 126022- } 126023- for _, v := range versions { 126024- if v.Introduced != "" { 126025- a.Events = append(a.Events, osv.RangeEvent{Introduced: v.Introduced.Canonical()}) 126026- } 126027- if v.Fixed != "" { 126028- a.Events = append(a.Events, osv.RangeEvent{Fixed: v.Fixed.Canonical()}) 126029- } 126030- } 126031- return osv.Affects{a} 126032-} 126033- 126034-func generateImports(m *Module) (imps []osv.EcosystemSpecificImport) { 126035- for _, p := range m.Packages { 126036- syms := append([]string{}, p.Symbols...) 126037- syms = append(syms, p.DerivedSymbols...) 126038- sort.Strings(syms) 126039- imps = append(imps, osv.EcosystemSpecificImport{ 126040- Path: p.Package, 126041- GOOS: p.GOOS, 126042- GOARCH: p.GOARCH, 126043- Symbols: syms, 126044- }) 126045- } 126046- return imps 126047-} 126048-func generateAffected(m *Module, url string) osv.Affected { 126049- name := m.Module 126050- switch name { 126051- case stdModule: 126052- name = "stdlib" 126053- case cmdModule: 126054- name = "toolchain" 126055- } 126056- return osv.Affected{ 126057- Package: osv.Package{ 126058- Name: name, 126059- Ecosystem: osv.GoEcosystem, 126060- }, 126061- Ranges: generateAffectedRanges(m.Versions), 126062- DatabaseSpecific: osv.DatabaseSpecific{URL: url}, 126063- EcosystemSpecific: osv.EcosystemSpecific{ 126064- Imports: generateImports(m), 126065- }, 126066- } 126067-} 126068diff -urN a/gopls/internal/vulncheck/vulntest/db_test.go b/gopls/internal/vulncheck/vulntest/db_test.go 126069--- a/gopls/internal/vulncheck/vulntest/db_test.go 2000-01-01 00:00:00.000000000 -0000 126070+++ b/gopls/internal/vulncheck/vulntest/db_test.go 1970-01-01 00:00:00.000000000 +0000 126071@@ -1,61 +0,0 @@ 126072-// Copyright 2022 The Go Authors. All rights reserved. 126073-// Use of this source code is governed by a BSD-style 126074-// license that can be found in the LICENSE file. 126075- 126076-//go:build go1.18 126077-// +build go1.18 126078- 126079-package vulntest 126080- 126081-import ( 126082- "context" 126083- "encoding/json" 126084- "testing" 126085-) 126086- 126087-func TestNewDatabase(t *testing.T) { 126088- ctx := context.Background() 126089- in := []byte(` 126090--- GO-2020-0001.yaml -- 126091-modules: 126092- - module: github.com/gin-gonic/gin 126093- versions: 126094- - fixed: 1.6.0 126095- packages: 126096- - package: github.com/gin-gonic/gin 126097- symbols: 126098- - defaultLogFormatter 126099-description: | 126100- Something. 126101-published: 2021-04-14T20:04:52Z 126102-references: 126103- - fix: https://github.com/gin-gonic/gin/pull/2237 126104-`) 126105- 126106- db, err := NewDatabase(ctx, in) 126107- if err != nil { 126108- t.Fatal(err) 126109- } 126110- defer db.Clean() 126111- 126112- cli, err := NewClient(db) 126113- if err != nil { 126114- t.Fatal(err) 126115- } 126116- got, err := cli.GetByID(ctx, "GO-2020-0001") 126117- if err != nil { 126118- t.Fatal(err) 126119- } 126120- if got.ID != "GO-2020-0001" { 126121- m, _ := json.Marshal(got) 126122- t.Errorf("got %s\nwant GO-2020-0001 entry", m) 126123- } 126124- gotAll, err := cli.GetByModule(ctx, "github.com/gin-gonic/gin") 126125- if err != nil { 126126- t.Fatal(err) 126127- } 126128- if len(gotAll) != 1 || gotAll[0].ID != "GO-2020-0001" { 126129- m, _ := json.Marshal(got) 126130- t.Errorf("got %s\nwant GO-2020-0001 entry", m) 126131- } 126132-} 126133diff -urN a/gopls/internal/vulncheck/vulntest/report.go b/gopls/internal/vulncheck/vulntest/report.go 126134--- a/gopls/internal/vulncheck/vulntest/report.go 2000-01-01 00:00:00.000000000 -0000 126135+++ b/gopls/internal/vulncheck/vulntest/report.go 1970-01-01 00:00:00.000000000 +0000 126136@@ -1,176 +0,0 @@ 126137-// Copyright 2022 The Go Authors. All rights reserved. 126138-// Use of this source code is governed by a BSD-style 126139-// license that can be found in the LICENSE file. 126140- 126141-//go:build go1.18 126142-// +build go1.18 126143- 126144-package vulntest 126145- 126146-import ( 126147- "fmt" 126148- "io" 126149- "os" 126150- "strings" 126151- "time" 126152- 126153- "golang.org/x/mod/semver" 126154- "gopkg.in/yaml.v3" 126155-) 126156- 126157-// 126158-// The following was selectively copied from golang.org/x/vulndb/internal/report 126159-// 126160- 126161-// readReport reads a Report in YAML format. 126162-func readReport(in io.Reader) (*Report, error) { 126163- d := yaml.NewDecoder(in) 126164- // Require that all fields in the file are in the struct. 126165- // This corresponds to v2's UnmarshalStrict. 126166- d.KnownFields(true) 126167- var r Report 126168- if err := d.Decode(&r); err != nil { 126169- return nil, fmt.Errorf("yaml.Decode: %v", err) 126170- } 126171- return &r, nil 126172-} 126173- 126174-// Report represents a vulnerability report in the vulndb. 126175-// Remember to update doc/format.md when this structure changes. 126176-type Report struct { 126177- Modules []*Module `yaml:",omitempty"` 126178- 126179- // Description is the CVE description from an existing CVE. If we are 126180- // assigning a CVE ID ourselves, use CVEMetadata.Description instead. 126181- Description string `yaml:",omitempty"` 126182- Published time.Time `yaml:",omitempty"` 126183- Withdrawn *time.Time `yaml:",omitempty"` 126184- 126185- References []*Reference `yaml:",omitempty"` 126186-} 126187- 126188-// Write writes r to filename in YAML format. 126189-func (r *Report) Write(filename string) (err error) { 126190- f, err := os.Create(filename) 126191- if err != nil { 126192- return err 126193- } 126194- err = r.encode(f) 126195- err2 := f.Close() 126196- if err == nil { 126197- err = err2 126198- } 126199- return err 126200-} 126201- 126202-// ToString encodes r to a YAML string. 126203-func (r *Report) ToString() (string, error) { 126204- var b strings.Builder 126205- if err := r.encode(&b); err != nil { 126206- return "", err 126207- } 126208- return b.String(), nil 126209-} 126210- 126211-func (r *Report) encode(w io.Writer) error { 126212- e := yaml.NewEncoder(w) 126213- defer e.Close() 126214- e.SetIndent(4) 126215- return e.Encode(r) 126216-} 126217- 126218-type VersionRange struct { 126219- Introduced Version `yaml:"introduced,omitempty"` 126220- Fixed Version `yaml:"fixed,omitempty"` 126221-} 126222- 126223-type Module struct { 126224- Module string `yaml:",omitempty"` 126225- Versions []VersionRange `yaml:",omitempty"` 126226- Packages []*Package `yaml:",omitempty"` 126227-} 126228- 126229-type Package struct { 126230- Package string `yaml:",omitempty"` 126231- GOOS []string `yaml:"goos,omitempty"` 126232- GOARCH []string `yaml:"goarch,omitempty"` 126233- // Symbols originally identified as vulnerable. 126234- Symbols []string `yaml:",omitempty"` 126235- // Additional vulnerable symbols, computed from Symbols via static analysis 126236- // or other technique. 126237- DerivedSymbols []string `yaml:"derived_symbols,omitempty"` 126238-} 126239- 126240-// Version is an SemVer 2.0.0 semantic version with no leading "v" prefix, 126241-// as used by OSV. 126242-type Version string 126243- 126244-// V returns the version with a "v" prefix. 126245-func (v Version) V() string { 126246- return "v" + string(v) 126247-} 126248- 126249-// IsValid reports whether v is a valid semantic version string. 126250-func (v Version) IsValid() bool { 126251- return semver.IsValid(v.V()) 126252-} 126253- 126254-// Before reports whether v < v2. 126255-func (v Version) Before(v2 Version) bool { 126256- return semver.Compare(v.V(), v2.V()) < 0 126257-} 126258- 126259-// Canonical returns the canonical formatting of the version. 126260-func (v Version) Canonical() string { 126261- return strings.TrimPrefix(semver.Canonical(v.V()), "v") 126262-} 126263- 126264-// Reference type is a reference (link) type. 126265-type ReferenceType string 126266- 126267-const ( 126268- ReferenceTypeAdvisory = ReferenceType("ADVISORY") 126269- ReferenceTypeArticle = ReferenceType("ARTICLE") 126270- ReferenceTypeReport = ReferenceType("REPORT") 126271- ReferenceTypeFix = ReferenceType("FIX") 126272- ReferenceTypePackage = ReferenceType("PACKAGE") 126273- ReferenceTypeEvidence = ReferenceType("EVIDENCE") 126274- ReferenceTypeWeb = ReferenceType("WEB") 126275-) 126276- 126277-// ReferenceTypes is the set of reference types defined in OSV. 126278-var ReferenceTypes = []ReferenceType{ 126279- ReferenceTypeAdvisory, 126280- ReferenceTypeArticle, 126281- ReferenceTypeReport, 126282- ReferenceTypeFix, 126283- ReferenceTypePackage, 126284- ReferenceTypeEvidence, 126285- ReferenceTypeWeb, 126286-} 126287- 126288-// A Reference is a link to some external resource. 126289-// 126290-// For ease of typing, References are represented in the YAML as a 126291-// single-element mapping of type to URL. 126292-type Reference struct { 126293- Type ReferenceType `json:"type,omitempty"` 126294- URL string `json:"url,omitempty"` 126295-} 126296- 126297-func (r *Reference) MarshalYAML() (interface{}, error) { 126298- return map[string]string{ 126299- strings.ToLower(string(r.Type)): r.URL, 126300- }, nil 126301-} 126302- 126303-func (r *Reference) UnmarshalYAML(n *yaml.Node) (err error) { 126304- if n.Kind != yaml.MappingNode || len(n.Content) != 2 || n.Content[0].Kind != yaml.ScalarNode || n.Content[1].Kind != yaml.ScalarNode { 126305- return &yaml.TypeError{Errors: []string{ 126306- fmt.Sprintf("line %d: report.Reference must contain a mapping with one value", n.Line), 126307- }} 126308- } 126309- r.Type = ReferenceType(strings.ToUpper(n.Content[0].Value)) 126310- r.URL = n.Content[1].Value 126311- return nil 126312-} 126313diff -urN a/gopls/internal/vulncheck/vulntest/report_test.go b/gopls/internal/vulncheck/vulntest/report_test.go 126314--- a/gopls/internal/vulncheck/vulntest/report_test.go 2000-01-01 00:00:00.000000000 -0000 126315+++ b/gopls/internal/vulncheck/vulntest/report_test.go 1970-01-01 00:00:00.000000000 +0000 126316@@ -1,52 +0,0 @@ 126317-// Copyright 2022 The Go Authors. All rights reserved. 126318-// Use of this source code is governed by a BSD-style 126319-// license that can be found in the LICENSE file. 126320- 126321-//go:build go1.18 126322-// +build go1.18 126323- 126324-package vulntest 126325- 126326-import ( 126327- "bytes" 126328- "io" 126329- "io/ioutil" 126330- "os" 126331- "path/filepath" 126332- "testing" 126333- 126334- "github.com/google/go-cmp/cmp" 126335-) 126336- 126337-func readAll(t *testing.T, filename string) io.Reader { 126338- d, err := ioutil.ReadFile(filename) 126339- if err != nil { 126340- t.Fatal(err) 126341- } 126342- return bytes.NewReader(d) 126343-} 126344- 126345-func TestRoundTrip(t *testing.T) { 126346- // A report shouldn't change after being read and then written. 126347- in := filepath.Join("testdata", "report.yaml") 126348- r, err := readReport(readAll(t, in)) 126349- if err != nil { 126350- t.Fatal(err) 126351- } 126352- out := filepath.Join(t.TempDir(), "report.yaml") 126353- if err := r.Write(out); err != nil { 126354- t.Fatal(err) 126355- } 126356- 126357- want, err := os.ReadFile(in) 126358- if err != nil { 126359- t.Fatal(err) 126360- } 126361- got, err := os.ReadFile(out) 126362- if err != nil { 126363- t.Fatal(err) 126364- } 126365- if diff := cmp.Diff(want, got); diff != "" { 126366- t.Errorf("mismatch (-want, +got):\n%s", diff) 126367- } 126368-} 126369diff -urN a/gopls/internal/vulncheck/vulntest/stdlib.go b/gopls/internal/vulncheck/vulntest/stdlib.go 126370--- a/gopls/internal/vulncheck/vulntest/stdlib.go 2000-01-01 00:00:00.000000000 -0000 126371+++ b/gopls/internal/vulncheck/vulntest/stdlib.go 1970-01-01 00:00:00.000000000 +0000 126372@@ -1,26 +0,0 @@ 126373-// Copyright 2022 The Go Authors. All rights reserved. 126374-// Use of this source code is governed by a BSD-style 126375-// license that can be found in the LICENSE file. 126376- 126377-//go:build go1.18 126378-// +build go1.18 126379- 126380-package vulntest 126381- 126382-import ( 126383- "strings" 126384- 126385- "golang.org/x/mod/module" 126386-) 126387- 126388-// maybeStdlib reports whether the given import path could be part of the Go 126389-// standard library, by reporting whether the first component lacks a '.'. 126390-func maybeStdlib(path string) bool { 126391- if err := module.CheckImportPath(path); err != nil { 126392- return false 126393- } 126394- if i := strings.IndexByte(path, '/'); i != -1 { 126395- path = path[:i] 126396- } 126397- return !strings.Contains(path, ".") 126398-} 126399diff -urN a/gopls/internal/vulncheck/vulntest/stdlib_test.go b/gopls/internal/vulncheck/vulntest/stdlib_test.go 126400--- a/gopls/internal/vulncheck/vulntest/stdlib_test.go 2000-01-01 00:00:00.000000000 -0000 126401+++ b/gopls/internal/vulncheck/vulntest/stdlib_test.go 1970-01-01 00:00:00.000000000 +0000 126402@@ -1,27 +0,0 @@ 126403-// Copyright 2022 The Go Authors. All rights reserved. 126404-// Use of this source code is governed by a BSD-style 126405-// license that can be found in the LICENSE file. 126406- 126407-//go:build go1.18 126408-// +build go1.18 126409- 126410-package vulntest 126411- 126412-import "testing" 126413- 126414-func TestMaybeStdlib(t *testing.T) { 126415- for _, test := range []struct { 126416- in string 126417- want bool 126418- }{ 126419- {"", false}, 126420- {"math/crypto", true}, 126421- {"github.com/pkg/errors", false}, 126422- {"Path is unknown", false}, 126423- } { 126424- got := maybeStdlib(test.in) 126425- if got != test.want { 126426- t.Errorf("%q: got %t, want %t", test.in, got, test.want) 126427- } 126428- } 126429-} 126430diff -urN a/gopls/internal/vulncheck/vulntest/testdata/report.yaml b/gopls/internal/vulncheck/vulntest/testdata/report.yaml 126431--- a/gopls/internal/vulncheck/vulntest/testdata/report.yaml 2000-01-01 00:00:00.000000000 -0000 126432+++ b/gopls/internal/vulncheck/vulntest/testdata/report.yaml 1970-01-01 00:00:00.000000000 +0000 126433@@ -1,15 +0,0 @@ 126434-modules: 126435- - module: github.com/gin-gonic/gin 126436- versions: 126437- - fixed: 1.6.0 126438- packages: 126439- - package: github.com/gin-gonic/gin 126440- symbols: 126441- - defaultLogFormatter 126442-description: | 126443- The default Formatter for the Logger middleware (LoggerConfig.Formatter), 126444- which is included in the Default engine, allows attackers to inject arbitrary 126445- log entries by manipulating the request path. 126446-references: 126447- - fix: https://github.com/gin-gonic/gin/pull/1234 126448- - fix: https://github.com/gin-gonic/gin/commit/abcdefg 126449diff -urN a/gopls/main.go b/gopls/main.go 126450--- a/gopls/main.go 2000-01-01 00:00:00.000000000 -0000 126451+++ b/gopls/main.go 1970-01-01 00:00:00.000000000 +0000 126452@@ -1,33 +0,0 @@ 126453-// Copyright 2019 The Go Authors. All rights reserved. 126454-// Use of this source code is governed by a BSD-style 126455-// license that can be found in the LICENSE file. 126456- 126457-// Gopls (pronounced “go please”) is an LSP server for Go. 126458-// The Language Server Protocol allows any text editor 126459-// to be extended with IDE-like features; 126460-// see https://langserver.org/ for details. 126461-// 126462-// See https://github.com/golang/tools/blob/master/gopls/README.md 126463-// for the most up-to-date documentation. 126464-package main // import "golang.org/x/tools/gopls" 126465- 126466-//go:generate go run doc/generate.go 126467- 126468-import ( 126469- "context" 126470- "golang.org/x/tools/internal/analysisinternal" 126471- "os" 126472- 126473- "golang.org/x/tools/gopls/internal/hooks" 126474- "golang.org/x/tools/gopls/internal/lsp/cmd" 126475- "golang.org/x/tools/internal/tool" 126476-) 126477- 126478-func main() { 126479- // In 1.18, diagnostics for Fuzz tests must not be used by cmd/vet. 126480- // So the code for Fuzz tests diagnostics is guarded behind flag analysisinternal.DiagnoseFuzzTests 126481- // Turn on analysisinternal.DiagnoseFuzzTests for gopls 126482- analysisinternal.DiagnoseFuzzTests = true 126483- ctx := context.Background() 126484- tool.Main(ctx, cmd.New("gopls", "", nil, hooks.Options), os.Args[1:]) 126485-} 126486diff -urN a/gopls/README.md b/gopls/README.md 126487--- a/gopls/README.md 2000-01-01 00:00:00.000000000 -0000 126488+++ b/gopls/README.md 1970-01-01 00:00:00.000000000 +0000 126489@@ -1,131 +0,0 @@ 126490-# `gopls`, the Go language server 126491- 126492-[](https://pkg.go.dev/golang.org/x/tools/gopls) 126493- 126494-`gopls` (pronounced "Go please") is the official Go [language server] developed 126495-by the Go team. It provides IDE features to any [LSP]-compatible editor. 126496- 126497-<!--TODO(rfindley): Add gifs here.--> 126498- 126499-You should not need to interact with `gopls` directly--it will be automatically 126500-integrated into your editor. The specific features and settings vary slightly 126501-by editor, so we recommend that you proceed to the 126502-[documentation for your editor](#editors) below. 126503- 126504-## Editors 126505- 126506-To get started with `gopls`, install an LSP plugin in your editor of choice. 126507- 126508-* [VS Code](https://github.com/golang/vscode-go/blob/master/README.md) 126509-* [Vim / Neovim](doc/vim.md) 126510-* [Emacs](doc/emacs.md) 126511-* [Atom](https://github.com/MordFustang21/ide-gopls) 126512-* [Sublime Text](doc/subl.md) 126513-* [Acme](https://github.com/fhs/acme-lsp) 126514-* [Lapce](https://github.com/lapce-community/lapce-go) 126515- 126516-If you use `gopls` with an editor that is not on this list, please send us a CL 126517-[updating this documentation](doc/contributing.md). 126518- 126519-## Installation 126520- 126521-For the most part, you should not need to install or update `gopls`. Your 126522-editor should handle that step for you. 126523- 126524-If you do want to get the latest stable version of `gopls`, run the following 126525-command: 126526- 126527-```sh 126528-go install golang.org/x/tools/gopls@latest 126529-``` 126530- 126531-Learn more in the 126532-[advanced installation instructions](doc/advanced.md#installing-unreleased-versions). 126533- 126534-Learn more about gopls releases in the [release policy](doc/releases.md). 126535- 126536-## Setting up your workspace 126537- 126538-`gopls` supports both Go module, multi-module and GOPATH modes. See the 126539-[workspace documentation](doc/workspace.md) for information on supported 126540-workspace layouts. 126541- 126542-## Configuration 126543- 126544-You can configure `gopls` to change your editor experience or view additional 126545-debugging information. Configuration options will be made available by your 126546-editor, so see your [editor's instructions](#editors) for specific details. A 126547-full list of `gopls` settings can be found in the [settings documentation](doc/settings.md). 126548- 126549-### Environment variables 126550- 126551-`gopls` inherits your editor's environment, so be aware of any environment 126552-variables you configure. Some editors, such as VS Code, allow users to 126553-selectively override the values of some environment variables. 126554- 126555-## Support Policy 126556- 126557-Gopls is maintained by engineers on the 126558-[Go tools team](https://github.com/orgs/golang/teams/tools-team/members), 126559-who actively monitor the 126560-[Go](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+label%3Agopls) 126561-and 126562-[VS Code Go](https://github.com/golang/vscode-go/issues) issue trackers. 126563- 126564-### Supported Go versions 126565- 126566-`gopls` follows the 126567-[Go Release Policy](https://golang.org/doc/devel/release.html#policy), 126568-meaning that it officially supports the last 2 major Go releases. Per 126569-[issue #39146](https://go.dev/issues/39146), we attempt to maintain best-effort 126570-support for the last 4 major Go releases, but this support extends only to not 126571-breaking the build and avoiding easily fixable regressions. 126572- 126573-In the context of this discussion, gopls "supports" a Go version if it supports 126574-being built with that Go version as well as integrating with the `go` command 126575-of that Go version. 126576- 126577-The following table shows the final gopls version that supports a given Go 126578-version. Go releases more recent than any in the table can be used with any 126579-version of gopls. 126580- 126581-| Go Version | Final gopls version with support (without warnings) | 126582-| ----------- | --------------------------------------------------- | 126583-| Go 1.12 | [[email protected]](https://github.com/golang/tools/releases/tag/gopls%2Fv0.7.5) | 126584-| Go 1.15 | [[email protected]](https://github.com/golang/tools/releases/tag/gopls%2Fv0.9.5) | 126585- 126586-Our extended support is enforced via [continuous integration with older Go 126587-versions](doc/contributing.md#ci). This legacy Go CI may not block releases: 126588-test failures may be skipped rather than fixed. Furthermore, if a regression in 126589-an older Go version causes irreconcilable CI failures, we may drop support for 126590-that Go version in CI if it is 3 or 4 Go versions old. 126591- 126592-### Supported build systems 126593- 126594-`gopls` currently only supports the `go` command, so if you are using 126595-a different build system, `gopls` will not work well. Bazel is not officially 126596-supported, but may be made to work with an appropriately configured 126597-`go/packages` driver. See 126598-[bazelbuild/rules_go#512](https://github.com/bazelbuild/rules_go/issues/512) 126599-for more information. 126600-You can follow [these instructions](https://github.com/bazelbuild/rules_go/wiki/Editor-setup) 126601-to configure your `gopls` to work with Bazel. 126602- 126603-### Troubleshooting 126604- 126605-If you are having issues with `gopls`, please follow the steps described in the 126606-[troubleshooting guide](doc/troubleshooting.md). 126607- 126608-## Additional information 126609- 126610-* [Features](doc/features.md) 126611-* [Command-line interface](doc/command-line.md) 126612-* [Advanced topics](doc/advanced.md) 126613-* [Contributing to `gopls`](doc/contributing.md) 126614-* [Integrating `gopls` with an editor](doc/design/integrating.md) 126615-* [Design requirements and decisions](doc/design/design.md) 126616-* [Implementation details](doc/design/implementation.md) 126617-* [Open issues](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+label%3Agopls) 126618- 126619-[language server]: https://langserver.org 126620-[LSP]: https://microsoft.github.io/language-server-protocol/ 126621diff -urN a/gopls/release/release.go b/gopls/release/release.go 126622--- a/gopls/release/release.go 2000-01-01 00:00:00.000000000 -0000 126623+++ b/gopls/release/release.go 1970-01-01 00:00:00.000000000 +0000 126624@@ -1,156 +0,0 @@ 126625-// Copyright 2020 The Go Authors. All rights reserved. 126626-// Use of this source code is governed by a BSD-style 126627-// license that can be found in the LICENSE file. 126628-// 126629-// Package release checks that the a given version of gopls is ready for 126630-// release. It can also tag and publish the release. 126631-// 126632-// To run: 126633-// 126634-// $ cd $GOPATH/src/golang.org/x/tools/gopls 126635-// $ go run release/release.go -version=<version> 126636-package main 126637- 126638-import ( 126639- "flag" 126640- "fmt" 126641- "go/types" 126642- "io/ioutil" 126643- "log" 126644- "os" 126645- "path/filepath" 126646- "strconv" 126647- "strings" 126648- 126649- exec "golang.org/x/sys/execabs" 126650- 126651- "golang.org/x/mod/modfile" 126652- "golang.org/x/mod/semver" 126653- "golang.org/x/tools/go/packages" 126654-) 126655- 126656-var versionFlag = flag.String("version", "", "version to tag") 126657- 126658-func main() { 126659- flag.Parse() 126660- 126661- if *versionFlag == "" { 126662- log.Fatalf("must provide -version flag") 126663- } 126664- if !semver.IsValid(*versionFlag) { 126665- log.Fatalf("invalid version %s", *versionFlag) 126666- } 126667- if semver.Major(*versionFlag) != "v0" { 126668- log.Fatalf("expected major version v0, got %s", semver.Major(*versionFlag)) 126669- } 126670- if semver.Build(*versionFlag) != "" { 126671- log.Fatalf("unexpected build suffix: %s", *versionFlag) 126672- } 126673- // Validate that the user is running the program from the gopls module. 126674- wd, err := os.Getwd() 126675- if err != nil { 126676- log.Fatal(err) 126677- } 126678- if filepath.Base(wd) != "gopls" { 126679- log.Fatalf("must run from the gopls module") 126680- } 126681- // Confirm that they have updated the hardcoded version. 126682- if err := validateHardcodedVersion(*versionFlag); err != nil { 126683- log.Fatal(err) 126684- } 126685- // Confirm that the versions in the go.mod file are correct. 126686- if err := validateGoModFile(wd); err != nil { 126687- log.Fatal(err) 126688- } 126689- fmt.Println("Validated that the release is ready.") 126690- os.Exit(0) 126691-} 126692- 126693-// validateHardcodedVersion reports whether the version hardcoded in the gopls 126694-// binary is equivalent to the version being published. It reports an error if 126695-// not. 126696-func validateHardcodedVersion(version string) error { 126697- const debugPkg = "golang.org/x/tools/gopls/internal/lsp/debug" 126698- pkgs, err := packages.Load(&packages.Config{ 126699- Mode: packages.NeedName | packages.NeedFiles | 126700- packages.NeedCompiledGoFiles | packages.NeedImports | 126701- packages.NeedTypes | packages.NeedTypesSizes, 126702- }, debugPkg) 126703- if err != nil { 126704- return err 126705- } 126706- if len(pkgs) != 1 { 126707- return fmt.Errorf("expected 1 package, got %v", len(pkgs)) 126708- } 126709- pkg := pkgs[0] 126710- if len(pkg.Errors) > 0 { 126711- return fmt.Errorf("failed to load %q: first error: %w", debugPkg, pkg.Errors[0]) 126712- } 126713- obj := pkg.Types.Scope().Lookup("Version") 126714- c, ok := obj.(*types.Const) 126715- if !ok { 126716- return fmt.Errorf("no constant named Version") 126717- } 126718- hardcodedVersion, err := strconv.Unquote(c.Val().ExactString()) 126719- if err != nil { 126720- return err 126721- } 126722- if semver.Prerelease(hardcodedVersion) != "" { 126723- return fmt.Errorf("unexpected pre-release for hardcoded version: %s", hardcodedVersion) 126724- } 126725- // Don't worry about pre-release tags and expect that there is no build 126726- // suffix. 126727- version = strings.TrimSuffix(version, semver.Prerelease(version)) 126728- if hardcodedVersion != version { 126729- return fmt.Errorf("expected version to be %s, got %s", *versionFlag, hardcodedVersion) 126730- } 126731- return nil 126732-} 126733- 126734-func validateGoModFile(goplsDir string) error { 126735- filename := filepath.Join(goplsDir, "go.mod") 126736- data, err := ioutil.ReadFile(filename) 126737- if err != nil { 126738- return err 126739- } 126740- gomod, err := modfile.Parse(filename, data, nil) 126741- if err != nil { 126742- return err 126743- } 126744- // Confirm that there is no replace directive in the go.mod file. 126745- if len(gomod.Replace) > 0 { 126746- return fmt.Errorf("expected no replace directives, got %v", len(gomod.Replace)) 126747- } 126748- // Confirm that the version of x/tools in the gopls/go.mod file points to 126749- // the second-to-last commit. (The last commit will be the one to update the 126750- // go.mod file.) 126751- cmd := exec.Command("git", "rev-parse", "@~") 126752- stdout, err := cmd.Output() 126753- if err != nil { 126754- return err 126755- } 126756- hash := string(stdout) 126757- // Find the golang.org/x/tools require line and compare the versions. 126758- var version string 126759- for _, req := range gomod.Require { 126760- if req.Mod.Path == "golang.org/x/tools" { 126761- version = req.Mod.Version 126762- break 126763- } 126764- } 126765- if version == "" { 126766- return fmt.Errorf("no require for golang.org/x/tools") 126767- } 126768- split := strings.Split(version, "-") 126769- if len(split) != 3 { 126770- return fmt.Errorf("unexpected pseudoversion format %s", version) 126771- } 126772- last := split[len(split)-1] 126773- if last == "" { 126774- return fmt.Errorf("unexpected pseudoversion format %s", version) 126775- } 126776- if !strings.HasPrefix(hash, last) { 126777- return fmt.Errorf("golang.org/x/tools pseudoversion should be at commit %s, instead got %s", hash, last) 126778- } 126779- return nil 126780-} 126781diff -urN a/gopls/test/debug/debug_test.go b/gopls/test/debug/debug_test.go 126782--- a/gopls/test/debug/debug_test.go 2000-01-01 00:00:00.000000000 -0000 126783+++ b/gopls/test/debug/debug_test.go 1970-01-01 00:00:00.000000000 +0000 126784@@ -1,141 +0,0 @@ 126785-// Copyright 2020 The Go Authors. All rights reserved. 126786-// Use of this source code is governed by a BSD-style 126787-// license that can be found in the LICENSE file. 126788- 126789-package debug_test 126790- 126791-// Provide 'static type checking' of the templates. This guards against changes is various 126792-// gopls datastructures causing template execution to fail. The checking is done by 126793-// the github.com/jba/templatecheck package. Before that is run, the test checks that 126794-// its list of templates and their arguments corresponds to the arguments in 126795-// calls to render(). The test assumes that all uses of templates are done through render(). 126796- 126797-import ( 126798- "go/ast" 126799- "html/template" 126800- "runtime" 126801- "sort" 126802- "strings" 126803- "testing" 126804- 126805- "github.com/jba/templatecheck" 126806- "golang.org/x/tools/go/packages" 126807- "golang.org/x/tools/gopls/internal/lsp/cache" 126808- "golang.org/x/tools/gopls/internal/lsp/debug" 126809-) 126810- 126811-var templates = map[string]struct { 126812- tmpl *template.Template 126813- data interface{} // a value of the needed type 126814-}{ 126815- "MainTmpl": {debug.MainTmpl, &debug.Instance{}}, 126816- "DebugTmpl": {debug.DebugTmpl, nil}, 126817- "RPCTmpl": {debug.RPCTmpl, &debug.Rpcs{}}, 126818- "TraceTmpl": {debug.TraceTmpl, debug.TraceResults{}}, 126819- "CacheTmpl": {debug.CacheTmpl, &cache.Cache{}}, 126820- "SessionTmpl": {debug.SessionTmpl, &cache.Session{}}, 126821- "ViewTmpl": {debug.ViewTmpl, &cache.View{}}, 126822- "ClientTmpl": {debug.ClientTmpl, &debug.Client{}}, 126823- "ServerTmpl": {debug.ServerTmpl, &debug.Server{}}, 126824- "FileTmpl": {debug.FileTmpl, &cache.Overlay{}}, 126825- "InfoTmpl": {debug.InfoTmpl, "something"}, 126826- "MemoryTmpl": {debug.MemoryTmpl, runtime.MemStats{}}, 126827-} 126828- 126829-func TestTemplates(t *testing.T) { 126830- if runtime.GOOS == "android" { 126831- t.Skip("this test is not supported for Android") 126832- } 126833- cfg := &packages.Config{ 126834- Mode: packages.NeedTypesInfo | packages.LoadAllSyntax, // figure out what's necessary PJW 126835- } 126836- pkgs, err := packages.Load(cfg, "golang.org/x/tools/gopls/internal/lsp/debug") 126837- if err != nil { 126838- t.Fatal(err) 126839- } 126840- if len(pkgs) != 1 { 126841- t.Fatalf("expected a single package, but got %d", len(pkgs)) 126842- } 126843- p := pkgs[0] 126844- if len(p.Errors) != 0 { 126845- t.Fatalf("compiler error, e.g. %v", p.Errors[0]) 126846- } 126847- // find the calls to render in serve.go 126848- tree := treeOf(p, "serve.go") 126849- if tree == nil { 126850- t.Fatalf("found no syntax tree for %s", "serve.go") 126851- } 126852- renders := callsOf(p, tree, "render") 126853- if len(renders) == 0 { 126854- t.Fatalf("found no calls to render") 126855- } 126856- var found = make(map[string]bool) 126857- for _, r := range renders { 126858- if len(r.Args) != 2 { 126859- // template, func 126860- t.Fatalf("got %d args, expected 2", len(r.Args)) 126861- } 126862- t0, ok := p.TypesInfo.Types[r.Args[0]] 126863- if !ok || !t0.IsValue() || t0.Type.String() != "*html/template.Template" { 126864- t.Fatalf("no type info for template") 126865- } 126866- if id, ok := r.Args[0].(*ast.Ident); !ok { 126867- t.Errorf("expected *ast.Ident, got %T", r.Args[0]) 126868- } else { 126869- found[id.Name] = true 126870- } 126871- } 126872- // make sure found and templates have the same templates 126873- for k := range found { 126874- if _, ok := templates[k]; !ok { 126875- t.Errorf("code has template %s, but test does not", k) 126876- } 126877- } 126878- for k := range templates { 126879- if _, ok := found[k]; !ok { 126880- t.Errorf("test has template %s, code does not", k) 126881- } 126882- } 126883- // now check all the known templates, in alphabetic order, for determinacy 126884- keys := []string{} 126885- for k := range templates { 126886- keys = append(keys, k) 126887- } 126888- sort.Strings(keys) 126889- for _, k := range keys { 126890- v := templates[k] 126891- // the FuncMap is an annoyance; should not be necessary 126892- if err := templatecheck.CheckHTML(v.tmpl, v.data); err != nil { 126893- t.Errorf("%s: %v", k, err) 126894- } 126895- } 126896-} 126897- 126898-func callsOf(p *packages.Package, tree *ast.File, name string) []*ast.CallExpr { 126899- var ans []*ast.CallExpr 126900- f := func(n ast.Node) bool { 126901- x, ok := n.(*ast.CallExpr) 126902- if !ok { 126903- return true 126904- } 126905- if y, ok := x.Fun.(*ast.Ident); ok { 126906- if y.Name == name { 126907- ans = append(ans, x) 126908- } 126909- } 126910- return true 126911- } 126912- ast.Inspect(tree, f) 126913- return ans 126914-} 126915- 126916-func treeOf(p *packages.Package, fname string) *ast.File { 126917- for _, tree := range p.Syntax { 126918- loc := tree.Package 126919- pos := p.Fset.PositionFor(loc, false) 126920- if strings.HasSuffix(pos.Filename, fname) { 126921- return tree 126922- } 126923- } 126924- return nil 126925-} 126926diff -urN a/gopls/test/json_test.go b/gopls/test/json_test.go 126927--- a/gopls/test/json_test.go 2000-01-01 00:00:00.000000000 -0000 126928+++ b/gopls/test/json_test.go 1970-01-01 00:00:00.000000000 +0000 126929@@ -1,140 +0,0 @@ 126930-// Copyright 2021 The Go Authors. All rights reserved. 126931-// Use of this source code is governed by a BSD-style 126932-// license that can be found in the LICENSE file. 126933- 126934-package gopls_test 126935- 126936-import ( 126937- "encoding/json" 126938- "fmt" 126939- "regexp" 126940- "strings" 126941- "testing" 126942- 126943- "github.com/google/go-cmp/cmp" 126944- "golang.org/x/tools/gopls/internal/lsp/protocol" 126945-) 126946- 126947-// verify that type errors in Initialize lsp messages don't cause 126948-// any other unmarshalling errors. The code looks at single values and the 126949-// first component of array values. Each occurrence is replaced by something 126950-// of a different type, the resulting string unmarshalled, and compared to 126951-// the unmarshalling of the unchanged strings. The test passes if there is no 126952-// more than a single difference reported. That is, if changing a single value 126953-// in the message changes no more than a single value in the unmarshalled struct, 126954-// it is safe to ignore *json.UnmarshalTypeError. 126955- 126956-// strings are changed to numbers or bools (true) 126957-// bools are changed to numbers or strings 126958-// numbers are changed to strings or bools 126959- 126960-// a recent Initialize message taken from a log (at some point 126961-// some field incompatibly changed from bool to int32) 126962-const input = `{"processId":46408,"clientInfo":{"name":"Visual Studio Code - Insiders","version":"1.76.0-insider"},"locale":"en-us","rootPath":"/Users/pjw/hakim","rootUri":"file:///Users/pjw/hakim","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional","normalizesLineEndings":true,"changeAnnotationSupport":{"groupsOnLabel":true}},"configuration":true,"didChangeWatchedFiles":{"dynamicRegistration":true,"relativePatternSupport":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]},"resolveSupport":{"properties":["location.range"]}},"codeLens":{"refreshSupport":true},"executeCommand":{"dynamicRegistration":true},"didChangeConfiguration":{"dynamicRegistration":true},"workspaceFolders":true,"semanticTokens":{"refreshSupport":true},"fileOperations":{"dynamicRegistration":true,"didCreate":true,"didRename":true,"didDelete":true,"willCreate":true,"willRename":true,"willDelete":true},"inlineValue":{"refreshSupport":true},"inlayHint":{"refreshSupport":true},"diagnostics":{"refreshSupport":true}},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"codeDescriptionSupport":true,"dataSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true,"resolveSupport":{"properties":["documentation","detail","additionalTextEdits"]},"insertTextModeSupport":{"valueSet":[1,2]},"labelDetailsSupport":true},"insertTextMode":2,"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]},"completionList":{"itemDefaults":["commitCharacters","editRange","insertTextFormat","insertTextMode"]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true},"activeParameterSupport":true},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]},"labelSupport":true},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"disabledSupport":true,"dataSupport":true,"resolveSupport":{"properties":["edit"]},"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"honorsChangeAnnotations":false},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true,"prepareSupportDefaultBehavior":1,"honorsChangeAnnotations":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true,"foldingRangeKind":{"valueSet":["comment","imports","region"]},"foldingRange":{"collapsedText":false}},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"callHierarchy":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator","decorator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"],"formats":["relative"],"requests":{"range":true,"full":{"delta":true}},"multilineTokenSupport":false,"overlappingTokenSupport":false,"serverCancelSupport":true,"augmentsSyntaxTokens":true},"linkedEditingRange":{"dynamicRegistration":true},"typeHierarchy":{"dynamicRegistration":true},"inlineValue":{"dynamicRegistration":true},"inlayHint":{"dynamicRegistration":true,"resolveSupport":{"properties":["tooltip","textEdits","label.tooltip","label.location","label.command"]}},"diagnostic":{"dynamicRegistration":true,"relatedDocumentSupport":false}},"window":{"showMessage":{"messageActionItem":{"additionalPropertiesSupport":true}},"showDocument":{"support":true},"workDoneProgress":true},"general":{"staleRequestSupport":{"cancel":true,"retryOnContentModified":["textDocument/semanticTokens/full","textDocument/semanticTokens/range","textDocument/semanticTokens/full/delta"]},"regularExpressions":{"engine":"ECMAScript","version":"ES2020"},"markdown":{"parser":"marked","version":"1.1.0"},"positionEncodings":["utf-16"]},"notebookDocument":{"synchronization":{"dynamicRegistration":true,"executionSummarySupport":true}}},"initializationOptions":{"usePlaceholders":true,"completionDocumentation":true,"verboseOutput":false,"build.directoryFilters":["-foof","-internal/lsp/protocol/typescript"],"codelenses":{"reference":true,"gc_details":true},"analyses":{"fillstruct":true,"staticcheck":true,"unusedparams":false,"composites":false},"semanticTokens":true,"noSemanticString":true,"noSemanticNumber":true,"templateExtensions":["tmpl","gotmpl"],"ui.completion.matcher":"Fuzzy","ui.inlayhint.hints":{"assignVariableTypes":false,"compositeLiteralFields":false,"compositeLiteralTypes":false,"constantValues":false,"functionTypeParameters":false,"parameterNames":false,"rangeVariableTypes":false},"ui.vulncheck":"Off","allExperiments":true},"trace":"off","workspaceFolders":[{"uri":"file:///Users/pjw/hakim","name":"hakim"}]}` 126963- 126964-type DiffReporter struct { 126965- path cmp.Path 126966- diffs []string 126967-} 126968- 126969-func (r *DiffReporter) PushStep(ps cmp.PathStep) { 126970- r.path = append(r.path, ps) 126971-} 126972- 126973-func (r *DiffReporter) Report(rs cmp.Result) { 126974- if !rs.Equal() { 126975- vx, vy := r.path.Last().Values() 126976- r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy)) 126977- } 126978-} 126979- 126980-func (r *DiffReporter) PopStep() { 126981- r.path = r.path[:len(r.path)-1] 126982-} 126983- 126984-func (r *DiffReporter) String() string { 126985- return strings.Join(r.diffs, "\n") 126986-} 126987- 126988-func TestStringChanges(t *testing.T) { 126989- // string as value 126990- stringLeaf := regexp.MustCompile(`:("[^"]*")`) 126991- leafs := stringLeaf.FindAllStringSubmatchIndex(input, -1) 126992- allDeltas(t, leafs, "23", "true") 126993- // string as first element of array 126994- stringArray := regexp.MustCompile(`[[]("[^"]*")`) 126995- arrays := stringArray.FindAllStringSubmatchIndex(input, -1) 126996- allDeltas(t, arrays, "23", "true") 126997-} 126998- 126999-func TestBoolChanges(t *testing.T) { 127000- boolLeaf := regexp.MustCompile(`:(true|false)(,|})`) 127001- leafs := boolLeaf.FindAllStringSubmatchIndex(input, -1) 127002- allDeltas(t, leafs, "23", `"xx"`) 127003- boolArray := regexp.MustCompile(`:[[](true|false)(,|])`) 127004- arrays := boolArray.FindAllStringSubmatchIndex(input, -1) 127005- allDeltas(t, arrays, "23", `"xx"`) 127006-} 127007- 127008-func TestNumberChanges(t *testing.T) { 127009- numLeaf := regexp.MustCompile(`:(\d+)(,|})`) 127010- leafs := numLeaf.FindAllStringSubmatchIndex(input, -1) 127011- allDeltas(t, leafs, "true", `"xx"`) 127012- numArray := regexp.MustCompile(`:[[](\d+)(,|])`) 127013- arrays := numArray.FindAllStringSubmatchIndex(input, -1) 127014- allDeltas(t, arrays, "true", `"xx"`) 127015-} 127016- 127017-// v is a set of matches. check that substituting any repl never 127018-// creates more than 1 unmarshaling error 127019-func allDeltas(t *testing.T, v [][]int, repls ...string) { 127020- t.Helper() 127021- for _, repl := range repls { 127022- for i, x := range v { 127023- err := tryChange(x[2], x[3], repl) 127024- if err != nil { 127025- t.Errorf("%d:%q %v", i, input[x[2]:x[3]], err) 127026- } 127027- } 127028- } 127029-} 127030- 127031-func tryChange(start, end int, repl string) error { 127032- var p, q protocol.ParamInitialize 127033- mod := input[:start] + repl + input[end:] 127034- excerpt := func() (string, string) { 127035- a := start - 5 127036- if a < 0 { 127037- a = 0 127038- } 127039- b := end + 5 127040- if b > len(input) { 127041- // trusting repl to be no longer than what it replaces 127042- b = len(input) 127043- } 127044- ma := input[a:b] 127045- mb := mod[a:b] 127046- return ma, mb 127047- } 127048- 127049- if err := json.Unmarshal([]byte(input), &p); err != nil { 127050- return fmt.Errorf("%s %v", repl, err) 127051- } 127052- switch err := json.Unmarshal([]byte(mod), &q).(type) { 127053- case nil: //ok 127054- case *json.UnmarshalTypeError: 127055- break 127056- case *protocol.UnmarshalError: 127057- return nil // cmp.Diff produces several diffs for custom unmrshalers 127058- default: 127059- return fmt.Errorf("%T unexpected unmarshal error", err) 127060- } 127061- 127062- var r DiffReporter 127063- cmp.Diff(p, q, cmp.Reporter(&r)) 127064- if len(r.diffs) > 1 { // 0 is possible, e.g., for interface{} 127065- ma, mb := excerpt() 127066- return fmt.Errorf("got %d diffs for %q\n%s\n%s", len(r.diffs), repl, ma, mb) 127067- } 127068- return nil 127069-} 127070