internal/lsp: don't associate package with snapshot

This change effectively reverts CL 202039. This CL was a mistake, as it
creates a cycle. Snapshots hold CheckPackageHandles, which in turn hold
pkgs.

Change-Id: I944304cb365f0ef98b5e54ea38edea6cece40453
Reviewed-on: https://go-review.googlesource.com/c/tools/+/202740
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
Rebecca Stambler 2019-10-23 16:10:24 -04:00
parent c8fcd6ab79
commit 2b779830f9
9 changed files with 45 additions and 44 deletions

View File

@ -270,7 +270,7 @@ func (imp *importer) typeCheck(ctx context.Context, cph *checkPackageHandle) (*p
} }
pkg := &pkg{ pkg := &pkg{
snapshot: imp.snapshot, view: imp.snapshot.view,
id: cph.m.id, id: cph.m.id,
mode: cph.mode, mode: cph.mode,
pkgPath: cph.m.pkgPath, pkgPath: cph.m.pkgPath,

View File

@ -27,7 +27,7 @@ func sourceError(ctx context.Context, pkg *pkg, e interface{}) (*source.Error, e
fixes []source.SuggestedFix fixes []source.SuggestedFix
related []source.RelatedInformation related []source.RelatedInformation
) )
fset := pkg.snapshot.view.session.cache.fset fset := pkg.view.session.cache.fset
switch e := e.(type) { switch e := e.(type) {
case packages.Error: case packages.Error:
if e.Pos == "" { if e.Pos == "" {
@ -64,18 +64,18 @@ func sourceError(ctx context.Context, pkg *pkg, e interface{}) (*source.Error, e
spn, err = typeErrorRange(ctx, fset, pkg, e.Pos) spn, err = typeErrorRange(ctx, fset, pkg, e.Pos)
case *analysis.Diagnostic: case *analysis.Diagnostic:
spn, err = span.NewRange(pkg.snapshot.view.session.cache.fset, e.Pos, e.End).Span() spn, err = span.NewRange(fset, e.Pos, e.End).Span()
if err != nil { if err != nil {
return nil, err return nil, err
} }
msg = e.Message msg = e.Message
kind = source.Analysis kind = source.Analysis
category = e.Category category = e.Category
fixes, err = suggestedFixes(ctx, pkg, e) fixes, err = suggestedFixes(ctx, fset, pkg, e)
if err != nil { if err != nil {
return nil, err return nil, err
} }
related, err = relatedInformation(ctx, pkg, e) related, err = relatedInformation(ctx, fset, pkg, e)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -95,12 +95,12 @@ func sourceError(ctx context.Context, pkg *pkg, e interface{}) (*source.Error, e
}, nil }, nil
} }
func suggestedFixes(ctx context.Context, pkg *pkg, diag *analysis.Diagnostic) ([]source.SuggestedFix, error) { func suggestedFixes(ctx context.Context, fset *token.FileSet, pkg *pkg, diag *analysis.Diagnostic) ([]source.SuggestedFix, error) {
var fixes []source.SuggestedFix var fixes []source.SuggestedFix
for _, fix := range diag.SuggestedFixes { for _, fix := range diag.SuggestedFixes {
edits := make(map[span.URI][]protocol.TextEdit) edits := make(map[span.URI][]protocol.TextEdit)
for _, e := range fix.TextEdits { for _, e := range fix.TextEdits {
spn, err := span.NewRange(pkg.Snapshot().View().Session().Cache().FileSet(), e.Pos, e.End).Span() spn, err := span.NewRange(fset, e.Pos, e.End).Span()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -121,10 +121,10 @@ func suggestedFixes(ctx context.Context, pkg *pkg, diag *analysis.Diagnostic) ([
return fixes, nil return fixes, nil
} }
func relatedInformation(ctx context.Context, pkg *pkg, diag *analysis.Diagnostic) ([]source.RelatedInformation, error) { func relatedInformation(ctx context.Context, fset *token.FileSet, pkg *pkg, diag *analysis.Diagnostic) ([]source.RelatedInformation, error) {
var out []source.RelatedInformation var out []source.RelatedInformation
for _, related := range diag.Related { for _, related := range diag.Related {
spn, err := span.NewRange(pkg.Snapshot().View().Session().Cache().FileSet(), related.Pos, related.End).Span() spn, err := span.NewRange(fset, related.Pos, related.End).Span()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,7 +19,7 @@ import (
// pkg contains the type information needed by the source package. // pkg contains the type information needed by the source package.
type pkg struct { type pkg struct {
snapshot *snapshot view *view
// ID and package path have their own types to avoid being used interchangeably. // ID and package path have their own types to avoid being used interchangeably.
id packageID id packageID
@ -43,8 +43,8 @@ type pkg struct {
type packageID string type packageID string
type packagePath string type packagePath string
func (p *pkg) Snapshot() source.Snapshot { func (p *pkg) View() source.View {
return p.snapshot return p.view
} }
func (p *pkg) ID() string { func (p *pkg) ID() string {
@ -139,8 +139,8 @@ func (p *pkg) FindDiagnostic(pdiag protocol.Diagnostic) (*source.Diagnostic, err
func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, source.Package, error) { func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, source.Package, error) {
// Special case for ignored files. // Special case for ignored files.
if p.snapshot.view.Ignore(uri) { if p.view.Ignore(uri) {
return p.snapshot.view.findIgnoredFile(ctx, uri) return p.view.findIgnoredFile(ctx, uri)
} }
queue := []*pkg{p} queue := []*pkg{p}

View File

@ -136,7 +136,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) { if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
return CompletionItem{}, errors.Errorf("no file for %s", obj.Name()) return CompletionItem{}, errors.Errorf("no file for %s", obj.Name())
} }
ident, err := findIdentifier(c.ctx, pkg, file, obj.Pos()) ident, err := findIdentifier(c.ctx, c.snapshot, pkg, file, obj.Pos())
if err != nil { if err != nil {
return CompletionItem{}, err return CompletionItem{}, err
} }

View File

@ -47,7 +47,7 @@ func (i *IdentifierInfo) Hover(ctx context.Context) (*HoverInformation, error) {
switch x := h.source.(type) { switch x := h.source.(type) {
case ast.Node: case ast.Node:
var b strings.Builder var b strings.Builder
if err := format.Node(&b, i.Snapshot().View().Session().Cache().FileSet(), x); err != nil { if err := format.Node(&b, i.Snapshot.View().Session().Cache().FileSet(), x); err != nil {
return nil, err return nil, err
} }
h.Signature = b.String() h.Signature = b.String()

View File

@ -20,8 +20,9 @@ import (
// IdentifierInfo holds information about an identifier in Go source. // IdentifierInfo holds information about an identifier in Go source.
type IdentifierInfo struct { type IdentifierInfo struct {
Name string Name string
File ParseGoHandle File ParseGoHandle
Snapshot Snapshot
mappedRange mappedRange
Type struct { Type struct {
@ -37,10 +38,6 @@ type IdentifierInfo struct {
qf types.Qualifier qf types.Qualifier
} }
func (i *IdentifierInfo) Snapshot() Snapshot {
return i.pkg.Snapshot()
}
type Declaration struct { type Declaration struct {
mappedRange mappedRange
node ast.Node node ast.Node
@ -51,7 +48,7 @@ type Declaration struct {
// Identifier returns identifier information for a position // Identifier returns identifier information for a position
// in a file, accounting for a potentially incomplete selector. // in a file, accounting for a potentially incomplete selector.
func Identifier(ctx context.Context, view View, f File, pos protocol.Position) (*IdentifierInfo, error) { func Identifier(ctx context.Context, view View, f File, pos protocol.Position) (*IdentifierInfo, error) {
_, cphs, err := view.CheckPackageHandles(ctx, f) snapshot, cphs, err := view.CheckPackageHandles(ctx, f)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,17 +76,17 @@ func Identifier(ctx context.Context, view View, f File, pos protocol.Position) (
if err != nil { if err != nil {
return nil, err return nil, err
} }
return findIdentifier(ctx, pkg, file, rng.Start) return findIdentifier(ctx, snapshot, pkg, file, rng.Start)
} }
func findIdentifier(ctx context.Context, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) { func findIdentifier(ctx context.Context, snapshot Snapshot, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
if result, err := identifier(ctx, pkg, file, pos); err != nil || result != nil { if result, err := identifier(ctx, snapshot, pkg, file, pos); err != nil || result != nil {
return result, err return result, err
} }
// If the position is not an identifier but immediately follows // If the position is not an identifier but immediately follows
// an identifier or selector period (as is common when // an identifier or selector period (as is common when
// requesting a completion), use the path to the preceding node. // requesting a completion), use the path to the preceding node.
ident, err := identifier(ctx, pkg, file, pos-1) ident, err := identifier(ctx, snapshot, pkg, file, pos-1)
if ident == nil && err == nil { if ident == nil && err == nil {
err = errors.New("no identifier found") err = errors.New("no identifier found")
} }
@ -97,21 +94,21 @@ func findIdentifier(ctx context.Context, pkg Package, file *ast.File, pos token.
} }
// identifier checks a single position for a potential identifier. // identifier checks a single position for a potential identifier.
func identifier(ctx context.Context, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) { func identifier(ctx context.Context, snapshot Snapshot, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
ctx, done := trace.StartSpan(ctx, "source.identifier") ctx, done := trace.StartSpan(ctx, "source.identifier")
defer done() defer done()
var err error var err error
// Handle import specs separately, as there is no formal position for a package declaration. // Handle import specs separately, as there is no formal position for a package declaration.
if result, err := importSpec(ctx, pkg, file, pos); result != nil || err != nil { if result, err := importSpec(ctx, snapshot, pkg, file, pos); result != nil || err != nil {
return result, err return result, err
} }
path, _ := astutil.PathEnclosingInterval(file, pos, pos) path, _ := astutil.PathEnclosingInterval(file, pos, pos)
if path == nil { if path == nil {
return nil, errors.Errorf("can't find node enclosing position") return nil, errors.Errorf("can't find node enclosing position")
} }
view := pkg.Snapshot().View() view := pkg.View()
uri := span.FileURI(view.Session().Cache().FileSet().Position(pos).Filename) uri := span.FileURI(view.Session().Cache().FileSet().Position(pos).Filename)
var ph ParseGoHandle var ph ParseGoHandle
for _, h := range pkg.Files() { for _, h := range pkg.Files() {
@ -120,10 +117,11 @@ func identifier(ctx context.Context, pkg Package, file *ast.File, pos token.Pos)
} }
} }
result := &IdentifierInfo{ result := &IdentifierInfo{
File: ph, File: ph,
qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()), Snapshot: snapshot,
pkg: pkg, qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()),
ident: searchForIdent(path[0]), pkg: pkg,
ident: searchForIdent(path[0]),
} }
// No identifier at the given position. // No identifier at the given position.
if result.ident == nil { if result.ident == nil {
@ -244,7 +242,7 @@ func hasErrorType(obj types.Object) bool {
} }
func objToNode(ctx context.Context, pkg Package, obj types.Object) (ast.Decl, error) { func objToNode(ctx context.Context, pkg Package, obj types.Object) (ast.Decl, error) {
view := pkg.Snapshot().View() view := pkg.View()
uri := span.FileURI(view.Session().Cache().FileSet().Position(obj.Pos()).Filename) uri := span.FileURI(view.Session().Cache().FileSet().Position(obj.Pos()).Filename)
ph, _, err := pkg.FindFile(ctx, uri) ph, _, err := pkg.FindFile(ctx, uri)
if err != nil { if err != nil {
@ -280,7 +278,7 @@ func objToNode(ctx context.Context, pkg Package, obj types.Object) (ast.Decl, er
} }
// importSpec handles positions inside of an *ast.ImportSpec. // importSpec handles positions inside of an *ast.ImportSpec.
func importSpec(ctx context.Context, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) { func importSpec(ctx context.Context, snapshot Snapshot, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
var imp *ast.ImportSpec var imp *ast.ImportSpec
for _, spec := range file.Imports { for _, spec := range file.Imports {
if spec.Path.Pos() <= pos && pos < spec.Path.End() { if spec.Path.Pos() <= pos && pos < spec.Path.End() {
@ -294,7 +292,7 @@ func importSpec(ctx context.Context, pkg Package, file *ast.File, pos token.Pos)
if err != nil { if err != nil {
return nil, errors.Errorf("import path not quoted: %s (%v)", imp.Path.Value, err) return nil, errors.Errorf("import path not quoted: %s (%v)", imp.Path.Value, err)
} }
uri := span.FileURI(pkg.Snapshot().View().Session().Cache().FileSet().Position(pos).Filename) uri := span.FileURI(pkg.View().Session().Cache().FileSet().Position(pos).Filename)
var ph ParseGoHandle var ph ParseGoHandle
for _, h := range pkg.Files() { for _, h := range pkg.Files() {
if h.File().Identity().URI == uri { if h.File().Identity().URI == uri {
@ -302,9 +300,10 @@ func importSpec(ctx context.Context, pkg Package, file *ast.File, pos token.Pos)
} }
} }
result := &IdentifierInfo{ result := &IdentifierInfo{
File: ph, File: ph,
Name: importPath, Snapshot: snapshot,
pkg: pkg, Name: importPath,
pkg: pkg,
} }
if result.mappedRange, err = posToMappedRange(ctx, pkg, imp.Path.Pos(), imp.Path.End()); err != nil { if result.mappedRange, err = posToMappedRange(ctx, pkg, imp.Path.Pos(), imp.Path.End()); err != nil {
return nil, err return nil, err

View File

@ -151,7 +151,7 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fh := i.Snapshot().Handle(ctx, f) fh := i.Snapshot.Handle(ctx, f)
data, _, err := fh.Read(ctx) data, _, err := fh.Read(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -225,6 +225,7 @@ func getPkgNameIdentifier(ctx context.Context, ident *IdentifierInfo, pkgName *t
return nil, err return nil, err
} }
return &IdentifierInfo{ return &IdentifierInfo{
Snapshot: ident.Snapshot,
Name: pkgName.Name(), Name: pkgName.Name(),
mappedRange: decl.mappedRange, mappedRange: decl.mappedRange,
File: ident.File, File: ident.File,

View File

@ -159,7 +159,7 @@ func posToMappedRange(ctx context.Context, pkg Package, pos, end token.Pos) (map
if err != nil { if err != nil {
return mappedRange{}, err return mappedRange{}, err
} }
return posToRange(ctx, pkg.Snapshot().View(), m, pos, end) return posToRange(ctx, pkg.View(), m, pos, end)
} }
func posToRange(ctx context.Context, view View, m *protocol.ColumnMapper, pos, end token.Pos) (mappedRange, error) { func posToRange(ctx context.Context, view View, m *protocol.ColumnMapper, pos, end token.Pos) (mappedRange, error) {
@ -176,7 +176,7 @@ func posToRange(ctx context.Context, view View, m *protocol.ColumnMapper, pos, e
} }
func posToMapper(ctx context.Context, pkg Package, pos token.Pos) (*protocol.ColumnMapper, error) { func posToMapper(ctx context.Context, pkg Package, pos token.Pos) (*protocol.ColumnMapper, error) {
posn := pkg.Snapshot().View().Session().Cache().FileSet().Position(pos) posn := pkg.View().Session().Cache().FileSet().Position(pos)
ph, _, err := pkg.FindFile(ctx, span.FileURI(posn.Filename)) ph, _, err := pkg.FindFile(ctx, span.FileURI(posn.Filename))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -274,7 +274,6 @@ type File interface {
// Package represents a Go package that has been type-checked. It maintains // Package represents a Go package that has been type-checked. It maintains
// only the relevant fields of a *go/packages.Package. // only the relevant fields of a *go/packages.Package.
type Package interface { type Package interface {
Snapshot() Snapshot
ID() string ID() string
PkgPath() string PkgPath() string
Files() []ParseGoHandle Files() []ParseGoHandle
@ -295,6 +294,8 @@ type Package interface {
// FindFile returns the AST and type information for a file that may // FindFile returns the AST and type information for a file that may
// belong to or be part of a dependency of the given package. // belong to or be part of a dependency of the given package.
FindFile(ctx context.Context, uri span.URI) (ParseGoHandle, Package, error) FindFile(ctx context.Context, uri span.URI) (ParseGoHandle, Package, error)
View() View
} }
type Error struct { type Error struct {