go/analysis: proposed fact enumeration API

Updates golang/go#29616

Change-Id: Ibaf10526ea35f06b853ad55451a50750c764fab4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/174379
Run-TryBot: Michael Matloob <matloob@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/go/analysis/analysis.go b/go/analysis/analysis.go
index 4d8a6e5..8eb7316 100644
--- a/go/analysis/analysis.go
+++ b/go/analysis/analysis.go
@@ -128,10 +128,32 @@
 	// See comments for ExportObjectFact.
 	ExportPackageFact func(fact Fact)
 
+	// AllPackageFacts returns a new slice containing all package facts in unspecified order.
+	// WARNING: This is an experimental API and may change in the future.
+	AllPackageFacts func() []PackageFact
+
+	// AllObjectFacts returns a new slice containing all object facts in unspecified order.
+	// WARNING: This is an experimental API and may change in the future.
+	AllObjectFacts func() []ObjectFact
+
 	/* Further fields may be added in future. */
 	// For example, suggested or applied refactorings.
 }
 
+// PackageFact is a package together with an associated fact.
+// WARNING: This is an experimental API and may change in the future.
+type PackageFact struct {
+	Package *types.Package
+	Fact    Fact
+}
+
+// ObjectFact is an object together with an associated fact.
+// WARNING: This is an experimental API and may change in the future.
+type ObjectFact struct {
+	Object types.Object
+	Fact   Fact
+}
+
 // Reportf is a helper function that reports a Diagnostic using the
 // specified position and formatted error message.
 func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
diff --git a/go/analysis/internal/checker/checker.go b/go/analysis/internal/checker/checker.go
index bd8474c..4cade77 100644
--- a/go/analysis/internal/checker/checker.go
+++ b/go/analysis/internal/checker/checker.go
@@ -503,6 +503,8 @@
 		ExportObjectFact:  act.exportObjectFact,
 		ImportPackageFact: act.importPackageFact,
 		ExportPackageFact: act.exportPackageFact,
+		AllObjectFacts:    act.allObjectFacts,
+		AllPackageFacts:   act.allPackageFacts,
 	}
 	act.pass = pass
 
@@ -666,6 +668,15 @@
 	}
 }
 
+// allObjectFacts implements Pass.AllObjectFacts.
+func (act *action) allObjectFacts() []analysis.ObjectFact {
+	facts := make([]analysis.ObjectFact, 0, len(act.objectFacts))
+	for k := range act.objectFacts {
+		facts = append(facts, analysis.ObjectFact{k.obj, act.objectFacts[k]})
+	}
+	return facts
+}
+
 // importPackageFact implements Pass.ImportPackageFact.
 // Given a non-nil pointer ptr of type *T, where *T satisfies Fact,
 // fact copies the fact value to *ptr.
@@ -703,4 +714,13 @@
 	return t
 }
 
+// allObjectFacts implements Pass.AllObjectFacts.
+func (act *action) allPackageFacts() []analysis.PackageFact {
+	facts := make([]analysis.PackageFact, 0, len(act.packageFacts))
+	for k := range act.packageFacts {
+		facts = append(facts, analysis.PackageFact{k.pkg, act.packageFacts[k]})
+	}
+	return facts
+}
+
 func dbg(b byte) bool { return strings.IndexByte(Debug, b) >= 0 }