internal/lsp: create types for package paths and IDs
This change replaces the strings that were previously used for both the ID and package path fields. This is a precursor to the change that will replace the uses of package path with package ID. Change-Id: I353e98aedede9b85c7a183fdd49048ff43b1e26d Reviewed-on: https://go-review.googlesource.com/c/tools/+/181757 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
d303ba255a
commit
6050b95026
|
@ -22,24 +22,24 @@ type importer struct {
|
||||||
|
|
||||||
// seen maintains the set of previously imported packages.
|
// seen maintains the set of previously imported packages.
|
||||||
// If we have seen a package that is already in this map, we have a circular import.
|
// If we have seen a package that is already in this map, we have a circular import.
|
||||||
seen map[string]struct{}
|
seen map[packagePath]struct{}
|
||||||
|
|
||||||
// topLevelPkgID is the ID of the package from which type-checking began.
|
// topLevelPkgID is the ID of the package from which type-checking began.
|
||||||
topLevelPkgID string
|
topLevelPkgID packageID
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
fset *token.FileSet
|
fset *token.FileSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imp *importer) Import(pkgPath string) (*types.Package, error) {
|
func (imp *importer) Import(pkgPath string) (*types.Package, error) {
|
||||||
pkg, err := imp.getPkg(pkgPath)
|
pkg, err := imp.getPkg(packagePath(pkgPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pkg.types, nil
|
return pkg.types, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imp *importer) getPkg(pkgPath string) (*pkg, error) {
|
func (imp *importer) getPkg(pkgPath packagePath) (*pkg, error) {
|
||||||
if _, ok := imp.seen[pkgPath]; ok {
|
if _, ok := imp.seen[pkgPath]; ok {
|
||||||
return nil, fmt.Errorf("circular import detected")
|
return nil, fmt.Errorf("circular import detected")
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ func (imp *importer) getPkg(pkgPath string) (*pkg, error) {
|
||||||
return e.pkg, nil
|
return e.pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imp *importer) typeCheck(pkgPath string) (*pkg, error) {
|
func (imp *importer) typeCheck(pkgPath packagePath) (*pkg, error) {
|
||||||
meta, ok := imp.view.mcache.packages[pkgPath]
|
meta, ok := imp.view.mcache.packages[pkgPath]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("no metadata for %v", pkgPath)
|
return nil, fmt.Errorf("no metadata for %v", pkgPath)
|
||||||
|
@ -89,7 +89,7 @@ func (imp *importer) typeCheck(pkgPath string) (*pkg, error) {
|
||||||
id: meta.id,
|
id: meta.id,
|
||||||
pkgPath: meta.pkgPath,
|
pkgPath: meta.pkgPath,
|
||||||
files: meta.files,
|
files: meta.files,
|
||||||
imports: make(map[string]*pkg),
|
imports: make(map[packagePath]*pkg),
|
||||||
typesSizes: meta.typesSizes,
|
typesSizes: meta.typesSizes,
|
||||||
typesInfo: &types.Info{
|
typesInfo: &types.Info{
|
||||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||||
|
@ -117,13 +117,13 @@ func (imp *importer) typeCheck(pkgPath string) (*pkg, error) {
|
||||||
} else if len(files) == 0 { // not the unsafe package, no parsed files
|
} else if len(files) == 0 { // not the unsafe package, no parsed files
|
||||||
return nil, fmt.Errorf("no parsed files for package %s", pkg.pkgPath)
|
return nil, fmt.Errorf("no parsed files for package %s", pkg.pkgPath)
|
||||||
} else {
|
} else {
|
||||||
pkg.types = types.NewPackage(meta.pkgPath, meta.name)
|
pkg.types = types.NewPackage(string(meta.pkgPath), meta.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg.syntax = files
|
pkg.syntax = files
|
||||||
|
|
||||||
// Handle circular imports by copying previously seen imports.
|
// Handle circular imports by copying previously seen imports.
|
||||||
seen := make(map[string]struct{})
|
seen := make(map[packagePath]struct{})
|
||||||
for k, v := range imp.seen {
|
for k, v := range imp.seen {
|
||||||
seen[k] = v
|
seen[k] = v
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,9 +131,9 @@ func (f *goFile) GetActiveReverseDeps(ctx context.Context) []source.GoFile {
|
||||||
f.view.mcache.mu.Lock()
|
f.view.mcache.mu.Lock()
|
||||||
defer f.view.mcache.mu.Unlock()
|
defer f.view.mcache.mu.Unlock()
|
||||||
|
|
||||||
seen := make(map[string]struct{}) // visited packages
|
seen := make(map[packagePath]struct{}) // visited packages
|
||||||
results := make(map[*goFile]struct{})
|
results := make(map[*goFile]struct{})
|
||||||
f.view.reverseDeps(ctx, seen, results, pkg.PkgPath())
|
f.view.reverseDeps(ctx, seen, results, packagePath(pkg.PkgPath()))
|
||||||
|
|
||||||
var files []source.GoFile
|
var files []source.GoFile
|
||||||
for rd := range results {
|
for rd := range results {
|
||||||
|
@ -149,7 +149,7 @@ func (f *goFile) GetActiveReverseDeps(ctx context.Context) []source.GoFile {
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *view) reverseDeps(ctx context.Context, seen map[string]struct{}, results map[*goFile]struct{}, pkgPath string) {
|
func (v *view) reverseDeps(ctx context.Context, seen map[packagePath]struct{}, results map[*goFile]struct{}, pkgPath packagePath) {
|
||||||
if _, ok := seen[pkgPath]; ok {
|
if _, ok := seen[pkgPath]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ func (v *view) loadParseTypecheck(ctx context.Context, f *goFile) ([]packages.Er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the metadata's current missing imports, if any.
|
// Save the metadata's current missing imports, if any.
|
||||||
var originalMissingImports map[string]struct{}
|
var originalMissingImports map[packagePath]struct{}
|
||||||
if f.meta != nil {
|
if f.meta != nil {
|
||||||
originalMissingImports = f.meta.missingImports
|
originalMissingImports = f.meta.missingImports
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (v *view) loadParseTypecheck(ctx context.Context, f *goFile) ([]packages.Er
|
||||||
|
|
||||||
imp := &importer{
|
imp := &importer{
|
||||||
view: v,
|
view: v,
|
||||||
seen: make(map[string]struct{}),
|
seen: make(map[packagePath]struct{}),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
fset: f.FileSet(),
|
fset: f.FileSet(),
|
||||||
topLevelPkgID: f.meta.id,
|
topLevelPkgID: f.meta.id,
|
||||||
|
@ -48,7 +48,7 @@ func (v *view) loadParseTypecheck(ctx context.Context, f *goFile) ([]packages.Er
|
||||||
|
|
||||||
// Start prefetching direct imports.
|
// Start prefetching direct imports.
|
||||||
for importPath := range f.meta.children {
|
for importPath := range f.meta.children {
|
||||||
go imp.Import(importPath)
|
go imp.Import(string(importPath))
|
||||||
}
|
}
|
||||||
// Type-check package.
|
// Type-check package.
|
||||||
pkg, err := imp.getPkg(f.meta.pkgPath)
|
pkg, err := imp.getPkg(f.meta.pkgPath)
|
||||||
|
@ -65,7 +65,7 @@ func (v *view) loadParseTypecheck(ctx context.Context, f *goFile) ([]packages.Er
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sameSet(x, y map[string]struct{}) bool {
|
func sameSet(x, y map[packagePath]struct{}) bool {
|
||||||
if len(x) != len(y) {
|
if len(x) != len(y) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func (v *view) checkMetadata(ctx context.Context, f *goFile) ([]packages.Error,
|
||||||
return pkg.Errors, fmt.Errorf("package %s has errors, skipping type-checking", pkg.PkgPath)
|
return pkg.Errors, fmt.Errorf("package %s has errors, skipping type-checking", pkg.PkgPath)
|
||||||
}
|
}
|
||||||
// Build the import graph for this package.
|
// Build the import graph for this package.
|
||||||
v.link(ctx, pkg.PkgPath, pkg, nil)
|
v.link(ctx, packagePath(pkg.PkgPath), pkg, nil)
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -136,16 +136,16 @@ func (v *view) parseImports(ctx context.Context, f *goFile) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *view) link(ctx context.Context, pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
|
func (v *view) link(ctx context.Context, pkgPath packagePath, pkg *packages.Package, parent *metadata) *metadata {
|
||||||
m, ok := v.mcache.packages[pkgPath]
|
m, ok := v.mcache.packages[pkgPath]
|
||||||
if !ok {
|
if !ok {
|
||||||
m = &metadata{
|
m = &metadata{
|
||||||
pkgPath: pkgPath,
|
pkgPath: pkgPath,
|
||||||
id: pkg.ID,
|
id: packageID(pkg.ID),
|
||||||
typesSizes: pkg.TypesSizes,
|
typesSizes: pkg.TypesSizes,
|
||||||
parents: make(map[string]bool),
|
parents: make(map[packagePath]bool),
|
||||||
children: make(map[string]bool),
|
children: make(map[packagePath]bool),
|
||||||
missingImports: make(map[string]struct{}),
|
missingImports: make(map[packagePath]struct{}),
|
||||||
}
|
}
|
||||||
v.mcache.packages[pkgPath] = m
|
v.mcache.packages[pkgPath] = m
|
||||||
}
|
}
|
||||||
|
@ -168,15 +168,16 @@ func (v *view) link(ctx context.Context, pkgPath string, pkg *packages.Package,
|
||||||
}
|
}
|
||||||
for importPath, importPkg := range pkg.Imports {
|
for importPath, importPkg := range pkg.Imports {
|
||||||
if len(importPkg.Errors) > 0 {
|
if len(importPkg.Errors) > 0 {
|
||||||
m.missingImports[pkg.PkgPath] = struct{}{}
|
m.missingImports[pkgPath] = struct{}{}
|
||||||
}
|
}
|
||||||
if _, ok := m.children[importPath]; !ok {
|
importPkgPath := packagePath(importPath)
|
||||||
v.link(ctx, importPath, importPkg, m)
|
if _, ok := m.children[importPkgPath]; !ok {
|
||||||
|
v.link(ctx, importPkgPath, importPkg, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear out any imports that have been removed.
|
// Clear out any imports that have been removed.
|
||||||
for importPath := range m.children {
|
for importPath := range m.children {
|
||||||
if _, ok := pkg.Imports[importPath]; !ok {
|
if _, ok := pkg.Imports[string(importPath)]; !ok {
|
||||||
delete(m.children, importPath)
|
delete(m.children, importPath)
|
||||||
if child, ok := v.mcache.packages[importPath]; ok {
|
if child, ok := v.mcache.packages[importPath]; ok {
|
||||||
delete(child.parents, pkgPath)
|
delete(child.parents, pkgPath)
|
||||||
|
|
|
@ -18,11 +18,14 @@ 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 {
|
||||||
id, pkgPath string
|
// ID and package path have their own types to avoid being used interchangeably.
|
||||||
|
id packageID
|
||||||
|
pkgPath packagePath
|
||||||
|
|
||||||
files []string
|
files []string
|
||||||
syntax []*astFile
|
syntax []*astFile
|
||||||
errors []packages.Error
|
errors []packages.Error
|
||||||
imports map[string]*pkg
|
imports map[packagePath]*pkg
|
||||||
types *types.Package
|
types *types.Package
|
||||||
typesInfo *types.Info
|
typesInfo *types.Info
|
||||||
typesSizes types.Sizes
|
typesSizes types.Sizes
|
||||||
|
@ -35,6 +38,12 @@ type pkg struct {
|
||||||
analyses map[*analysis.Analyzer]*analysisEntry
|
analyses map[*analysis.Analyzer]*analysisEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// packageID is a type that abstracts a package ID.
|
||||||
|
type packageID string
|
||||||
|
|
||||||
|
// packagePath is a type that abstracts a package path.
|
||||||
|
type packagePath string
|
||||||
|
|
||||||
type analysisEntry struct {
|
type analysisEntry struct {
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
succeeded bool
|
succeeded bool
|
||||||
|
@ -108,11 +117,11 @@ func (pkg *pkg) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*sour
|
||||||
if len(a.FactTypes) > 0 {
|
if len(a.FactTypes) > 0 {
|
||||||
importPaths := make([]string, 0, len(pkg.imports))
|
importPaths := make([]string, 0, len(pkg.imports))
|
||||||
for importPath := range pkg.imports {
|
for importPath := range pkg.imports {
|
||||||
importPaths = append(importPaths, importPath)
|
importPaths = append(importPaths, string(importPath))
|
||||||
}
|
}
|
||||||
sort.Strings(importPaths) // for determinism
|
sort.Strings(importPaths) // for determinism
|
||||||
for _, importPath := range importPaths {
|
for _, importPath := range importPaths {
|
||||||
dep, ok := pkg.imports[importPath]
|
dep, ok := pkg.imports[packagePath(importPath)]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -129,7 +138,7 @@ func (pkg *pkg) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*sour
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *pkg) PkgPath() string {
|
func (pkg *pkg) PkgPath() string {
|
||||||
return pkg.pkgPath
|
return string(pkg.pkgPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *pkg) GetFilenames() []string {
|
func (pkg *pkg) GetFilenames() []string {
|
||||||
|
@ -165,7 +174,7 @@ func (pkg *pkg) IsIllTyped() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *pkg) GetImport(pkgPath string) source.Package {
|
func (pkg *pkg) GetImport(pkgPath string) source.Package {
|
||||||
if imp := pkg.imports[pkgPath]; imp != nil {
|
if imp := pkg.imports[packagePath(pkgPath)]; imp != nil {
|
||||||
return imp
|
return imp
|
||||||
}
|
}
|
||||||
// Don't return a nil pointer because that still satisfies the interface.
|
// Don't return a nil pointer because that still satisfies the interface.
|
||||||
|
|
|
@ -81,10 +81,10 @@ func (s *session) NewView(name string, folder span.URI) source.View {
|
||||||
filesByURI: make(map[span.URI]viewFile),
|
filesByURI: make(map[span.URI]viewFile),
|
||||||
filesByBase: make(map[string][]viewFile),
|
filesByBase: make(map[string][]viewFile),
|
||||||
mcache: &metadataCache{
|
mcache: &metadataCache{
|
||||||
packages: make(map[string]*metadata),
|
packages: make(map[packagePath]*metadata),
|
||||||
},
|
},
|
||||||
pcache: &packageCache{
|
pcache: &packageCache{
|
||||||
packages: make(map[string]*entry),
|
packages: make(map[packagePath]*entry),
|
||||||
},
|
},
|
||||||
ignoredURIs: make(map[span.URI]struct{}),
|
ignoredURIs: make(map[span.URI]struct{}),
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,23 +71,25 @@ type view struct {
|
||||||
|
|
||||||
type metadataCache struct {
|
type metadataCache struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
packages map[string]*metadata
|
packages map[packagePath]*metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
type metadata struct {
|
type metadata struct {
|
||||||
id, pkgPath, name string
|
id packageID
|
||||||
|
pkgPath packagePath
|
||||||
|
name string
|
||||||
files []string
|
files []string
|
||||||
typesSizes types.Sizes
|
typesSizes types.Sizes
|
||||||
parents, children map[string]bool
|
parents, children map[packagePath]bool
|
||||||
|
|
||||||
// missingImports is the set of unresolved imports for this package.
|
// missingImports is the set of unresolved imports for this package.
|
||||||
// It contains any packages with `go list` errors.
|
// It contains any packages with `go list` errors.
|
||||||
missingImports map[string]struct{}
|
missingImports map[packagePath]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type packageCache struct {
|
type packageCache struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
packages map[string]*entry
|
packages map[packagePath]*entry
|
||||||
}
|
}
|
||||||
|
|
||||||
type entry struct {
|
type entry struct {
|
||||||
|
@ -227,20 +229,10 @@ func (v *view) SetContent(ctx context.Context, uri span.URI, content []byte) err
|
||||||
// invalidateContent invalidates the content of a Go file,
|
// invalidateContent invalidates the content of a Go file,
|
||||||
// including any position and type information that depends on it.
|
// including any position and type information that depends on it.
|
||||||
func (f *goFile) invalidateContent() {
|
func (f *goFile) invalidateContent() {
|
||||||
f.view.pcache.mu.Lock()
|
|
||||||
f.handleMu.Lock()
|
f.handleMu.Lock()
|
||||||
defer func() {
|
defer f.handleMu.Unlock()
|
||||||
f.handleMu.Unlock()
|
|
||||||
f.view.pcache.mu.Unlock()
|
|
||||||
}()
|
|
||||||
|
|
||||||
f.ast = nil
|
f.invalidateAST()
|
||||||
f.token = nil
|
|
||||||
|
|
||||||
// Remove the package and all of its reverse dependencies from the cache.
|
|
||||||
if f.pkg != nil {
|
|
||||||
f.view.remove(f.pkg.pkgPath, map[string]struct{}{})
|
|
||||||
}
|
|
||||||
f.handle = nil
|
f.handle = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,14 +247,14 @@ func (f *goFile) invalidateAST() {
|
||||||
|
|
||||||
// Remove the package and all of its reverse dependencies from the cache.
|
// Remove the package and all of its reverse dependencies from the cache.
|
||||||
if f.pkg != nil {
|
if f.pkg != nil {
|
||||||
f.view.remove(f.pkg.pkgPath, map[string]struct{}{})
|
f.view.remove(f.pkg.pkgPath, map[packagePath]struct{}{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove invalidates a package and its reverse dependencies in the view's
|
// remove invalidates a package and its reverse dependencies in the view's
|
||||||
// package cache. It is assumed that the caller has locked both the mutexes
|
// package cache. It is assumed that the caller has locked both the mutexes
|
||||||
// of both the mcache and the pcache.
|
// of both the mcache and the pcache.
|
||||||
func (v *view) remove(pkgPath string, seen map[string]struct{}) {
|
func (v *view) remove(pkgPath packagePath, seen map[packagePath]struct{}) {
|
||||||
if _, ok := seen[pkgPath]; ok {
|
if _, ok := seen[pkgPath]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue