1
0
mirror of https://github.com/golang/go synced 2024-11-19 03:44:40 -07:00
go/internal/lsp/cache/pkg.go
Rebecca Stambler f0068bd333 internal/lsp: remove misleading check span
This span resulted in misleading information, since it would appear any
time you called the Check function. This function often returns cached
results, so it's not particularly useful.

Change-Id: I26be652a99b906fb2e8703ff9af86fbe2ef5fc5d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/201219
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-10-16 19:48:01 +00:00

164 lines
3.8 KiB
Go

// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cache
import (
"context"
"go/ast"
"go/types"
"sync"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
errors "golang.org/x/xerrors"
)
// pkg contains the type information needed by the source package.
type pkg struct {
view *view
// ID and package path have their own types to avoid being used interchangeably.
id packageID
pkgPath packagePath
mode source.ParseMode
files []source.ParseGoHandle
errors []packages.Error
imports map[packagePath]*pkg
types *types.Package
typesInfo *types.Info
typesSizes types.Sizes
diagMu sync.Mutex
diagnostics map[*analysis.Analyzer][]source.Diagnostic
}
// Declare explicit types for package paths and IDs to ensure that we never use
// an ID where a path belongs, and vice versa. If we confused the two, it would
// result in confusing errors because package IDs often look like package paths.
type packageID string
type packagePath string
func (p *pkg) ID() string {
return string(p.id)
}
func (p *pkg) PkgPath() string {
return string(p.pkgPath)
}
func (p *pkg) Files() []source.ParseGoHandle {
return p.files
}
func (p *pkg) File(uri span.URI) (source.ParseGoHandle, error) {
for _, ph := range p.Files() {
if ph.File().Identity().URI == uri {
return ph, nil
}
}
return nil, errors.Errorf("no ParseGoHandle for %s", uri)
}
func (p *pkg) GetSyntax(ctx context.Context) []*ast.File {
var syntax []*ast.File
for _, ph := range p.files {
file, _, _, err := ph.Cached(ctx)
if err == nil {
syntax = append(syntax, file)
}
}
return syntax
}
func (p *pkg) GetErrors() []packages.Error {
return p.errors
}
func (p *pkg) GetTypes() *types.Package {
return p.types
}
func (p *pkg) GetTypesInfo() *types.Info {
return p.typesInfo
}
func (p *pkg) GetTypesSizes() types.Sizes {
return p.typesSizes
}
func (p *pkg) IsIllTyped() bool {
return p.types == nil || p.typesInfo == nil || p.typesSizes == nil
}
func (p *pkg) GetImport(ctx context.Context, pkgPath string) (source.Package, error) {
if imp := p.imports[packagePath(pkgPath)]; imp != nil {
return imp, nil
}
// Don't return a nil pointer because that still satisfies the interface.
return nil, errors.Errorf("no imported package for %s", pkgPath)
}
func (p *pkg) SetDiagnostics(a *analysis.Analyzer, diags []source.Diagnostic) {
p.diagMu.Lock()
defer p.diagMu.Unlock()
if p.diagnostics == nil {
p.diagnostics = make(map[*analysis.Analyzer][]source.Diagnostic)
}
p.diagnostics[a] = diags
}
func (p *pkg) FindDiagnostic(pdiag protocol.Diagnostic) (*source.Diagnostic, error) {
p.diagMu.Lock()
defer p.diagMu.Unlock()
for a, diagnostics := range p.diagnostics {
if a.Name != pdiag.Source {
continue
}
for _, d := range diagnostics {
if d.Message != pdiag.Message {
continue
}
if protocol.CompareRange(d.Range, pdiag.Range) != 0 {
continue
}
return &d, nil
}
}
return nil, errors.Errorf("no matching diagnostic for %v", pdiag)
}
func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, source.Package, error) {
// Special case for ignored files.
if p.view.Ignore(uri) {
return p.view.findIgnoredFile(ctx, uri)
}
queue := []*pkg{p}
seen := make(map[string]bool)
for len(queue) > 0 {
pkg := queue[0]
queue = queue[1:]
seen[pkg.ID()] = true
for _, ph := range pkg.files {
if ph.File().Identity().URI == uri {
return ph, pkg, nil
}
}
for _, dep := range pkg.imports {
if !seen[dep.ID()] {
queue = append(queue, dep)
}
}
}
return nil, nil, errors.Errorf("no file for %s", uri)
}