internal/lsp: add analyses to the snapshot

This change makes sure that actionHandles are cached within the
snapshot, to minimize the cost of re-computing action handles on each
run of go/analysis.

Change-Id: If6191c5224285eb207aebb997787ea551a47fbaa
Reviewed-on: https://go-review.googlesource.com/c/tools/+/201098
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Rebecca Stambler 2019-10-14 16:13:06 -04:00
parent 18e3458ac9
commit f936694f27
5 changed files with 62 additions and 4 deletions

View File

@ -17,6 +17,11 @@ import (
errors "golang.org/x/xerrors" errors "golang.org/x/xerrors"
) )
type actionKey struct {
pkg packageKey
analyzer string // analyzer name
}
func (s *snapshot) Analyze(ctx context.Context, id string, analyzers []*analysis.Analyzer) (map[*analysis.Analyzer][]*analysis.Diagnostic, error) { func (s *snapshot) Analyze(ctx context.Context, id string, analyzers []*analysis.Analyzer) (map[*analysis.Analyzer][]*analysis.Diagnostic, error) {
var roots []*actionHandle var roots []*actionHandle
@ -79,6 +84,10 @@ type packageFactKey struct {
} }
func (s *snapshot) actionHandle(ctx context.Context, id packageID, mode source.ParseMode, a *analysis.Analyzer) (*actionHandle, error) { func (s *snapshot) actionHandle(ctx context.Context, id packageID, mode source.ParseMode, a *analysis.Analyzer) (*actionHandle, error) {
ah := s.getAction(id, mode, a.Name)
if ah != nil {
return ah, nil
}
cph := s.getPackage(id, mode) cph := s.getPackage(id, mode)
if cph == nil { if cph == nil {
return nil, errors.Errorf("no CheckPackageHandle for %s:%v", id, mode == source.ParseExported) return nil, errors.Errorf("no CheckPackageHandle for %s:%v", id, mode == source.ParseExported)
@ -90,7 +99,7 @@ func (s *snapshot) actionHandle(ctx context.Context, id packageID, mode source.P
if err != nil { if err != nil {
return nil, err return nil, err
} }
ah := &actionHandle{ ah = &actionHandle{
analyzer: a, analyzer: a,
pkg: pkg, pkg: pkg,
} }
@ -118,12 +127,13 @@ func (s *snapshot) actionHandle(ctx context.Context, id packageID, mode source.P
ah.deps = append(ah.deps, depActionHandle) ah.deps = append(ah.deps, depActionHandle)
} }
} }
h := s.view.session.cache.store.Bind(actionKey(a, cph), func(ctx context.Context) interface{} { h := s.view.session.cache.store.Bind(buildActionKey(a, cph), func(ctx context.Context) interface{} {
data := &actionData{} data := &actionData{}
data.diagnostics, data.result, data.err = ah.exec(ctx, s.view.session.cache.fset) data.diagnostics, data.result, data.err = ah.exec(ctx, s.view.session.cache.fset)
return data return data
}) })
ah.handle = h ah.handle = h
s.addAction(ah)
return ah, nil return ah, nil
} }
@ -136,7 +146,7 @@ func (ah *actionHandle) analyze(ctx context.Context) ([]*analysis.Diagnostic, in
return data.diagnostics, data.result, data.err return data.diagnostics, data.result, data.err
} }
func actionKey(a *analysis.Analyzer, cph *checkPackageHandle) string { func buildActionKey(a *analysis.Analyzer, cph *checkPackageHandle) string {
return hashContents([]byte(fmt.Sprintf("%s %s", a, string(cph.key)))) return hashContents([]byte(fmt.Sprintf("%s %s", a, string(cph.key))))
} }

View File

@ -266,6 +266,7 @@ func (imp *importer) typeCheck(ctx context.Context, cph *checkPackageHandle) (*p
pkg := &pkg{ pkg := &pkg{
view: imp.snapshot.view, view: imp.snapshot.view,
id: cph.m.id, id: cph.m.id,
mode: cph.mode,
pkgPath: cph.m.pkgPath, pkgPath: cph.m.pkgPath,
files: cph.Files(), files: cph.Files(),
imports: make(map[packagePath]*pkg), imports: make(map[packagePath]*pkg),

View File

@ -24,6 +24,7 @@ type pkg struct {
// 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
mode source.ParseMode
pkgPath packagePath pkgPath packagePath
files []source.ParseGoHandle files []source.ParseGoHandle
errors []packages.Error errors []packages.Error

View File

@ -104,6 +104,7 @@ func (s *session) NewView(ctx context.Context, name string, folder span.URI, opt
metadata: make(map[packageID]*metadata), metadata: make(map[packageID]*metadata),
files: make(map[span.URI]source.FileHandle), files: make(map[span.URI]source.FileHandle),
importedBy: make(map[packageID][]packageID), importedBy: make(map[packageID][]packageID),
actions: make(map[actionKey]*actionHandle),
}, },
ignoredURIs: make(map[span.URI]struct{}), ignoredURIs: make(map[span.URI]struct{}),
builtin: &builtinPkg{}, builtin: &builtinPkg{},

View File

@ -29,9 +29,12 @@ type snapshot struct {
// It may invalidated when a file's content changes. // It may invalidated when a file's content changes.
files map[span.URI]source.FileHandle files map[span.URI]source.FileHandle
// packages maps a file URI to a set of CheckPackageHandles to which that file belongs. // packages maps a packageKey to a set of CheckPackageHandles to which that file belongs.
// It may be invalidated when a file's content changes. // It may be invalidated when a file's content changes.
packages map[packageKey]*checkPackageHandle packages map[packageKey]*checkPackageHandle
// actions maps an actionkey to its actionHandle.
actions map[actionKey]*actionHandle
} }
func (s *snapshot) View() source.View { func (s *snapshot) View() source.View {
@ -93,6 +96,37 @@ func (s *snapshot) getPackage(id packageID, m source.ParseMode) *checkPackageHan
return s.packages[key] return s.packages[key]
} }
func (s *snapshot) getAction(id packageID, m source.ParseMode, analyzer string) *actionHandle {
s.mu.Lock()
defer s.mu.Unlock()
key := actionKey{
pkg: packageKey{
id: id,
mode: m,
},
analyzer: analyzer,
}
return s.actions[key]
}
func (s *snapshot) addAction(ah *actionHandle) {
s.mu.Lock()
defer s.mu.Unlock()
key := actionKey{
analyzer: ah.analyzer.Name,
pkg: packageKey{
id: ah.pkg.id,
mode: ah.pkg.mode,
},
}
if _, ok := s.actions[key]; ok {
return
}
s.actions[key] = ah
}
func (s *snapshot) getMetadataForURI(uri span.URI) (metadata []*metadata) { func (s *snapshot) getMetadataForURI(uri span.URI) (metadata []*metadata) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
@ -175,6 +209,7 @@ func (s *snapshot) clone(ctx context.Context, withoutURI *span.URI, withoutTypes
importedBy: make(map[packageID][]packageID), importedBy: make(map[packageID][]packageID),
metadata: make(map[packageID]*metadata), metadata: make(map[packageID]*metadata),
packages: make(map[packageKey]*checkPackageHandle), packages: make(map[packageKey]*checkPackageHandle),
actions: make(map[actionKey]*actionHandle),
files: make(map[span.URI]source.FileHandle), files: make(map[span.URI]source.FileHandle),
} }
// Copy all of the FileHandles except for the one that was invalidated. // Copy all of the FileHandles except for the one that was invalidated.
@ -216,6 +251,16 @@ func (s *snapshot) clone(ctx context.Context, withoutURI *span.URI, withoutTypes
} }
result.packages[k] = v result.packages[k] = v
} }
// Copy the package analysis information.
for k, v := range s.actions {
if _, ok := withoutTypesIDs[k.pkg.id]; ok {
continue
}
if _, ok := withoutMetadataIDs[k.pkg.id]; ok {
continue
}
result.actions[k] = v
}
// Copy the package metadata. // Copy the package metadata.
for k, v := range s.metadata { for k, v := range s.metadata {
if _, ok := withoutMetadataIDs[k]; ok { if _, ok := withoutMetadataIDs[k]; ok {