vulncheck: make API use IDs for entries and proper names for nodes

The change also introduces a small fix to an issue related to entry
points.

Cherry-picked: https://go-review.googlesource.com/c/exp/+/371774

Change-Id: I2d9dc6d0f6a16f1d9546faf362658ad50c9e4f46
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/395050
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/vulncheck/helpers_test.go b/vulncheck/helpers_test.go
index 27ec03b..b275d78 100644
--- a/vulncheck/helpers_test.go
+++ b/vulncheck/helpers_test.go
@@ -114,14 +114,14 @@
 	}
 
 	m := make(map[string][]string)
-	for _, n := range cg.Funcs {
+	for _, n := range cg.Functions {
 		fName := funcName(n)
 		for _, callsite := range n.CallSites {
 			e := edge{src: callsite.Parent, dst: n.ID}
 			if seen[e] {
 				continue
 			}
-			caller := cg.Funcs[e.src]
+			caller := cg.Functions[e.src]
 			callerName := funcName(caller)
 			m[callerName] = append(m[callerName], fName)
 		}
diff --git a/vulncheck/source.go b/vulncheck/source.go
index 72151d4..c195006 100644
--- a/vulncheck/source.go
+++ b/vulncheck/source.go
@@ -30,7 +30,7 @@
 	result := &Result{
 		Imports:  &ImportGraph{Packages: make(map[int]*PkgNode)},
 		Requires: &RequireGraph{Modules: make(map[int]*ModNode)},
-		Calls:    &CallGraph{Funcs: make(map[int]*FuncNode)},
+		Calls:    &CallGraph{Functions: make(map[int]*FuncNode)},
 	}
 
 	vulnPkgModSlice(pkgs, modVulns, result)
@@ -68,7 +68,7 @@
 		// Top level packages that lead to vulnerable imports are
 		// stored as result.Imports graph entry points.
 		if e := vulnImportSlice(pkg, modVulns, result, analyzedPkgs); e != nil {
-			result.Imports.Entries = append(result.Imports.Entries, e)
+			result.Imports.Entries = append(result.Imports.Entries, e.ID)
 		}
 	}
 
@@ -172,6 +172,17 @@
 		modPredRelation[pkgModID] = predSet
 	}
 
+	// Add entry module IDs.
+	seenEntries := make(map[int]bool)
+	for _, epID := range result.Imports.Entries {
+		entryModID := moduleNodeID(result.Imports.Packages[epID], result, modNodeIDs)
+		if seenEntries[entryModID] {
+			continue
+		}
+		seenEntries[entryModID] = true
+		result.Requires.Entries = append(result.Requires.Entries, entryModID)
+	}
+
 	// Store the predecessor requires relation to result.
 	for modID := range modPredRelation {
 		if modID == 0 {
@@ -256,7 +267,7 @@
 		// Top level entries that lead to vulnerable calls
 		// are stored as result.Calls graph entry points.
 		if e := vulnCallSlice(entry, modVulns, cg, result, analyzedFuncs); e != nil {
-			result.Calls.Entries = append(result.Calls.Entries, e)
+			result.Calls.Entries = append(result.Calls.Entries, e.ID)
 		}
 	}
 }
@@ -320,7 +331,7 @@
 		funNode = funcNode(f)
 		analyzed[f] = funNode
 	}
-	result.Calls.Funcs[funNode.ID] = funNode
+	result.Calls.Functions[funNode.ID] = funNode
 
 	// Save node predecessor information.
 	for _, calleeSliceInfo := range onSlice {
diff --git a/vulncheck/source_test.go b/vulncheck/source_test.go
index 24127e0..ed25385 100644
--- a/vulncheck/source_test.go
+++ b/vulncheck/source_test.go
@@ -132,6 +132,14 @@
 		}
 	}
 
+	// Check that module and package entry points are collected.
+	if got := len(result.Imports.Entries); got != 2 {
+		t.Errorf("want 2 package entry points; got %v", got)
+	}
+	if got := len(result.Requires.Entries); got != 1 {
+		t.Errorf("want 1 module entry point; got %v", got)
+	}
+
 	// The imports slice should include import chains:
 	//   x -> avuln -> w -> bvuln
 	//         |
@@ -360,6 +368,11 @@
 		t.Errorf("want 3 Vulns, got %d", len(result.Vulns))
 	}
 
+	// Check that call graph entry points are present.
+	if got := len(result.Calls.Entries); got != 2 {
+		t.Errorf("want 2 call graph entry points; got %v", got)
+	}
+
 	// Check that vulnerabilities are connected to the call graph.
 	// For the test example, all vulns should have a call sink.
 	for _, v := range result.Vulns {
diff --git a/vulncheck/vulncheck.go b/vulncheck/vulncheck.go
index 82d3117..8561a6e 100644
--- a/vulncheck/vulncheck.go
+++ b/vulncheck/vulncheck.go
@@ -162,10 +162,10 @@
 // CallGraph is technically backwards directed, i.e., from a vulnerable function
 // towards the program entry functions (see FuncNode).
 type CallGraph struct {
-	// Funcs contains all call graph nodes as a map: func node id -> func node.
-	Funcs map[int]*FuncNode
-	// Entries are a subset of Funcs representing vulncheck entry points.
-	Entries []*FuncNode
+	// Functions contains all call graph nodes as a map: func node id -> func node.
+	Functions map[int]*FuncNode
+	// Entries are IDs of a subset of Functions representing vulncheck entry points.
+	Entries []int
 }
 
 type FuncNode struct {
@@ -199,8 +199,8 @@
 type RequireGraph struct {
 	// Modules contains all module nodes as a map: module node id -> module node.
 	Modules map[int]*ModNode
-	// Entries are a subset of Modules representing modules of vulncheck entry points.
-	Entries []*ModNode
+	// Entries are IDs of a subset of Modules representing modules of vulncheck entry points.
+	Entries []int
 }
 
 type ModNode struct {
@@ -221,8 +221,8 @@
 type ImportGraph struct {
 	// Packages contains all package nodes as a map: package node id -> package node.
 	Packages map[int]*PkgNode
-	// Entries are a subset of Packages representing packages of vulncheck entry points.
-	Entries []*PkgNode
+	// Entries are IDs of a subset of Packages representing packages of vulncheck entry points.
+	Entries []int
 }
 
 type PkgNode struct {