Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5ed33df

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/lsp/source: rename: prep for incrementality
This change moves into rename.go various declarations that, thanks to recent work, are only used for renaming. (The moved functions have not changed.) It also extracts the lengthy "package name" special case into a separate function, and adds a few comments. The checkRenaming call has been pulled out of renameObj into the callers. In one of these, it was not needed. Change-Id: I4e2d354c098296980b6bcc2fe8ddc2e212e10aa8 Reviewed-on: https://go-review.googlesource.com/c/tools/+/463895 Run-TryBot: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent e0659d1 commit 5ed33df

File tree

5 files changed

+521
-523
lines changed

5 files changed

+521
-523
lines changed

gopls/internal/lsp/protocol/mapper.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ func (m *Mapper) OffsetMappedRange(start, end int) (MappedRange, error) {
460460
// Construct one by calling Mapper.OffsetMappedRange with start/end offsets.
461461
// From the go/token domain, call safetoken.Offsets first,
462462
// or use a helper such as ParsedGoFile.MappedPosRange.
463+
//
464+
// Two MappedRanges produced the same Mapper are equal if and only if they
465+
// denote the same range. Two MappedRanges produced by different Mappers
466+
// are unequal even when they represent the same range of the same file.
463467
type MappedRange struct {
464468
Mapper *Mapper
465469
start, end int // valid byte offsets: 0 <= start <= end <= len(Mapper.Content)

gopls/internal/lsp/source/implementation.go

Lines changed: 5 additions & 232 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,13 @@
55
package source
66

77
import (
8-
"context"
98
"errors"
10-
"fmt"
119
"go/ast"
1210
"go/token"
1311
"go/types"
14-
15-
"golang.org/x/tools/gopls/internal/lsp/protocol"
16-
"golang.org/x/tools/gopls/internal/lsp/safetoken"
17-
"golang.org/x/tools/gopls/internal/span"
18-
"golang.org/x/tools/internal/event"
1912
)
2013

21-
var ErrNotAType = errors.New("not a type name or method")
14+
// TODO(adonovan): move these declarations elsewhere.
2215

2316
// concreteImplementsIntf returns true if a is an interface type implemented by
2417
// concrete type b, or vice versa.
@@ -44,234 +37,14 @@ func concreteImplementsIntf(a, b types.Type) bool {
4437
return types.AssignableTo(a, b)
4538
}
4639

47-
// A qualifiedObject is the result of resolving a reference from an
48-
// identifier to an object.
49-
type qualifiedObject struct {
50-
// definition
51-
obj types.Object // the referenced object
52-
pkg Package // the Package that defines the object (nil => universe)
53-
54-
// reference (optional)
55-
node ast.Node // the reference (*ast.Ident or *ast.ImportSpec) to the object
56-
sourcePkg Package // the Package containing node
57-
}
58-
5940
var (
60-
errBuiltin = errors.New("builtin object")
41+
// TODO(adonovan): why do various RPC handlers related to
42+
// IncomingCalls return (nil, nil) on the protocol in response
43+
// to this error? That seems like a violation of the protocol.
44+
// Is it perhaps a workaround for VSCode behavior?
6145
errNoObjectFound = errors.New("no object found")
6246
)
6347

64-
// qualifiedObjsAtProtocolPos returns info for all the types.Objects referenced
65-
// at the given position, for the following selection of packages:
66-
//
67-
// 1. all packages (including all test variants), in their workspace parse mode
68-
// 2. if not included above, at least one package containing uri in full parse mode
69-
//
70-
// Finding objects in (1) ensures that we locate references within all
71-
// workspace packages, including in x_test packages. Including (2) ensures that
72-
// we find local references in the current package, for non-workspace packages
73-
// that may be open.
74-
func qualifiedObjsAtProtocolPos(ctx context.Context, s Snapshot, uri span.URI, pp protocol.Position) ([]qualifiedObject, error) {
75-
fh, err := s.GetFile(ctx, uri)
76-
if err != nil {
77-
return nil, err
78-
}
79-
content, err := fh.Read()
80-
if err != nil {
81-
return nil, err
82-
}
83-
m := protocol.NewMapper(uri, content)
84-
offset, err := m.PositionOffset(pp)
85-
if err != nil {
86-
return nil, err
87-
}
88-
return qualifiedObjsAtLocation(ctx, s, positionKey{uri, offset}, map[positionKey]bool{})
89-
}
90-
91-
// A positionKey identifies a byte offset within a file (URI).
92-
//
93-
// When a file has been parsed multiple times in the same FileSet,
94-
// there may be multiple token.Pos values denoting the same logical
95-
// position. In such situations, a positionKey may be used for
96-
// de-duplication.
97-
type positionKey struct {
98-
uri span.URI
99-
offset int
100-
}
101-
102-
// qualifiedObjsAtLocation finds all objects referenced at offset in uri,
103-
// across all packages in the snapshot.
104-
func qualifiedObjsAtLocation(ctx context.Context, s Snapshot, key positionKey, seen map[positionKey]bool) ([]qualifiedObject, error) {
105-
if seen[key] {
106-
return nil, nil
107-
}
108-
seen[key] = true
109-
110-
// We search for referenced objects starting with all packages containing the
111-
// current location, and then repeating the search for every distinct object
112-
// location discovered.
113-
//
114-
// In the common case, there should be at most one additional location to
115-
// consider: the definition of the object referenced by the location. But we
116-
// try to be comprehensive in case we ever support variations on build
117-
// constraints.
118-
metas, err := s.MetadataForFile(ctx, key.uri)
119-
if err != nil {
120-
return nil, err
121-
}
122-
ids := make([]PackageID, len(metas))
123-
for i, m := range metas {
124-
ids[i] = m.ID
125-
}
126-
pkgs, err := s.TypeCheck(ctx, TypecheckWorkspace, ids...)
127-
if err != nil {
128-
return nil, err
129-
}
130-
131-
// In order to allow basic references/rename/implementations to function when
132-
// non-workspace packages are open, ensure that we have at least one fully
133-
// parsed package for the current file. This allows us to find references
134-
// inside the open package. Use WidestPackage to capture references in test
135-
// files.
136-
hasFullPackage := false
137-
for _, pkg := range pkgs {
138-
if pkg.ParseMode() == ParseFull {
139-
hasFullPackage = true
140-
break
141-
}
142-
}
143-
if !hasFullPackage {
144-
pkg, _, err := PackageForFile(ctx, s, key.uri, TypecheckFull, WidestPackage)
145-
if err != nil {
146-
return nil, err
147-
}
148-
pkgs = append(pkgs, pkg)
149-
}
150-
151-
// report objects in the order we encounter them. This ensures that the first
152-
// result is at the cursor...
153-
var qualifiedObjs []qualifiedObject
154-
// ...but avoid duplicates.
155-
seenObjs := map[types.Object]bool{}
156-
157-
for _, searchpkg := range pkgs {
158-
pgf, err := searchpkg.File(key.uri)
159-
if err != nil {
160-
return nil, err
161-
}
162-
pos := pgf.Tok.Pos(key.offset)
163-
164-
// TODO(adonovan): replace this section with a call to objectsAt().
165-
path := pathEnclosingObjNode(pgf.File, pos)
166-
if path == nil {
167-
continue
168-
}
169-
var objs []types.Object
170-
switch leaf := path[0].(type) {
171-
case *ast.Ident:
172-
// If leaf represents an implicit type switch object or the type
173-
// switch "assign" variable, expand to all of the type switch's
174-
// implicit objects.
175-
if implicits, _ := typeSwitchImplicits(searchpkg.GetTypesInfo(), path); len(implicits) > 0 {
176-
objs = append(objs, implicits...)
177-
} else {
178-
obj := searchpkg.GetTypesInfo().ObjectOf(leaf)
179-
if obj == nil {
180-
return nil, fmt.Errorf("%w for %q", errNoObjectFound, leaf.Name)
181-
}
182-
objs = append(objs, obj)
183-
}
184-
case *ast.ImportSpec:
185-
// Look up the implicit *types.PkgName.
186-
obj := searchpkg.GetTypesInfo().Implicits[leaf]
187-
if obj == nil {
188-
return nil, fmt.Errorf("%w for import %s", errNoObjectFound, UnquoteImportPath(leaf))
189-
}
190-
objs = append(objs, obj)
191-
}
192-
193-
// Get all of the transitive dependencies of the search package.
194-
pkgSet := map[*types.Package]Package{
195-
searchpkg.GetTypes(): searchpkg,
196-
}
197-
deps := recursiveDeps(s, searchpkg.Metadata())[1:]
198-
// Ignore the error from type checking, but check if the context was
199-
// canceled (which would have caused TypeCheck to exit early).
200-
depPkgs, _ := s.TypeCheck(ctx, TypecheckWorkspace, deps...)
201-
if ctx.Err() != nil {
202-
return nil, ctx.Err()
203-
}
204-
for _, dep := range depPkgs {
205-
// Since we ignored the error from type checking, pkg may be nil.
206-
if dep != nil {
207-
pkgSet[dep.GetTypes()] = dep
208-
}
209-
}
210-
211-
for _, obj := range objs {
212-
if obj.Parent() == types.Universe {
213-
return nil, fmt.Errorf("%q: %w", obj.Name(), errBuiltin)
214-
}
215-
pkg, ok := pkgSet[obj.Pkg()]
216-
if !ok {
217-
event.Error(ctx, fmt.Sprintf("no package for obj %s: %v", obj, obj.Pkg()), err)
218-
continue
219-
}
220-
qualifiedObjs = append(qualifiedObjs, qualifiedObject{
221-
obj: obj,
222-
pkg: pkg,
223-
sourcePkg: searchpkg,
224-
node: path[0],
225-
})
226-
seenObjs[obj] = true
227-
228-
// If the qualified object is in another file (or more likely, another
229-
// package), it's possible that there is another copy of it in a package
230-
// that we haven't searched, e.g. a test variant. See golang/go#47564.
231-
//
232-
// In order to be sure we've considered all packages, call
233-
// qualifiedObjsAtLocation recursively for all locations we encounter. We
234-
// could probably be more precise here, only continuing the search if obj
235-
// is in another package, but this should be good enough to find all
236-
// uses.
237-
238-
if key, found := packagePositionKey(pkg, obj.Pos()); found {
239-
otherObjs, err := qualifiedObjsAtLocation(ctx, s, key, seen)
240-
if err != nil {
241-
return nil, err
242-
}
243-
for _, other := range otherObjs {
244-
if !seenObjs[other.obj] {
245-
qualifiedObjs = append(qualifiedObjs, other)
246-
seenObjs[other.obj] = true
247-
}
248-
}
249-
} else {
250-
return nil, fmt.Errorf("missing file for position of %q in %q", obj.Name(), obj.Pkg().Name())
251-
}
252-
}
253-
}
254-
// Return an error if no objects were found since callers will assume that
255-
// the slice has at least 1 element.
256-
if len(qualifiedObjs) == 0 {
257-
return nil, errNoObjectFound
258-
}
259-
return qualifiedObjs, nil
260-
}
261-
262-
// packagePositionKey finds the positionKey for the given pos.
263-
//
264-
// The second result reports whether the position was found.
265-
func packagePositionKey(pkg Package, pos token.Pos) (positionKey, bool) {
266-
for _, pgf := range pkg.CompiledGoFiles() {
267-
offset, err := safetoken.Offset(pgf.Tok, pos)
268-
if err == nil {
269-
return positionKey{pgf.URI, offset}, true
270-
}
271-
}
272-
return positionKey{}, false
273-
}
274-
27548
// pathEnclosingObjNode returns the AST path to the object-defining
27649
// node associated with pos. "Object-defining" means either an
27750
// *ast.Ident mapped directly to a types.Object or an ast.Node mapped

gopls/internal/lsp/source/implementation2.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,9 @@ func implementations2(ctx context.Context, snapshot Snapshot, fh FileHandle, pp
137137
queryType = recv.Type()
138138
queryMethodID = obj.Id()
139139
}
140-
default:
141-
return nil, fmt.Errorf("%s is not a type or method", id.Name)
142140
}
143141
if queryType == nil {
144-
return nil, ErrNotAType
142+
return nil, fmt.Errorf("%s is not a type or method", id.Name)
145143
}
146144

147145
// Compute the method-set fingerprint used as a key to the global search.

0 commit comments

Comments
 (0)