cmd/guru: compute referrers as packages are type checked
This CL makes little observable difference to the behavior but paves the
way for streaming 'referrers' and (later) 'implements' queries which
scan the entire workspace, but print each result as soon as it is found.
The go/loader package now exposes a hook, AfterTypeCheck, that lets
clients inspect each package as soon as it is type-checked, and also
modify it, for instance to release unneeded data structures.
A 'referrers' query applied to an exported object must scan the entire
workspace. It uses this hook so to gather uses of the query object in
streaming fashion. However, for now, it still accumulates the results
and prints them all at the end, though I propose to change that in a
follow-up.
Code details:
- The referrers logic had a 2-iteration loop to load first the query
package and then if necessary the enlarged program. The second
iteration has now been unrolled and split into globalReferrers.
- Queries for package names (whether in a package declaration or
a qualified identifier) have been split off into packageReferrers.
It now loads all direct importers of the query package,
which catches some references that were missing before.
(It used to inspect only the forward dependencies of the query
package.)
Also:
- Referrers.Pos (the position of query identifier) was removed from the
JSON output. It's a nuisance to compute now, and it's already
absent from the plain output.
(In a follow-up, I plan to simplify the information content of the
JSON output exactly what is currently printed in the plain output.)
Change-Id: Ia5677636dc7b0fe4461a5d393107665757fb9a97
Reviewed-on: https://go-review.googlesource.com/19794
Reviewed-by: Daniel Morsing <daniel.morsing@gmail.com>
diff --git a/go/loader/loader.go b/go/loader/loader.go
index 23cb68c..1ed0d3e 100644
--- a/go/loader/loader.go
+++ b/go/loader/loader.go
@@ -107,6 +107,25 @@
//
// It must be safe to call concurrently from multiple goroutines.
FindPackage func(ctxt *build.Context, fromDir, importPath string, mode build.ImportMode) (*build.Package, error)
+
+ // AfterTypeCheck is called immediately after a list of files
+ // has been type-checked and appended to info.Files.
+ //
+ // This optional hook function is the earliest opportunity for
+ // the client to observe the output of the type checker,
+ // which may be useful to reduce analysis latency when loading
+ // a large program.
+ //
+ // The function is permitted to modify info.Info, for instance
+ // to clear data structures that are no longer needed, which can
+ // dramatically reduce peak memory consumption.
+ //
+ // The function may be called twice for the same PackageInfo:
+ // once for the files of the package and again for the
+ // in-package test files.
+ //
+ // It must be safe to call concurrently from multiple goroutines.
+ AfterTypeCheck func(info *PackageInfo, files []*ast.File)
}
// A PkgSpec specifies a non-importable package to be created by Load.
@@ -971,8 +990,6 @@
// dependency edges that should be checked for potential cycles.
//
func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) {
- info.Files = append(info.Files, files...)
-
// Ensure the dependencies are loaded, in parallel.
var fromPath string
if cycleCheck {
@@ -990,6 +1007,11 @@
// Ignore the returned (first) error since we
// already collect them all in the PackageInfo.
info.checker.Files(files)
+ info.Files = append(info.Files, files...)
+
+ if imp.conf.AfterTypeCheck != nil {
+ imp.conf.AfterTypeCheck(info, files)
+ }
if trace {
fmt.Fprintf(os.Stderr, "%s: stop %q\n",