@@ -22,22 +22,20 @@ type Graph struct {
22
22
// Packages maps package IDs to their associated Packages.
23
23
Packages map [PackageID ]* Package
24
24
25
+ // Each of the three maps below is an index of the pointer values held
26
+ // by the Packages map. However, Package pointers are not generally canonical.
27
+
25
28
// ImportedBy maps package IDs to the list of packages that import them.
26
- ImportedBy map [PackageID ][]PackageID
29
+ ImportedBy map [PackageID ][]* Package
27
30
28
- // ByPackagePath maps package by their package path to their package ID.
31
+ // ForPackagePath maps package by their package path to their package ID.
29
32
// Non-test packages appear before test packages, and within each of those
30
33
// categories, packages with fewer CompiledGoFiles appear first.
31
- //
32
- // TODO(rfindley): there's no reason for ImportedBy and IDs to not also hold
33
- // pointers, rather than IDs, and pointers are more convenient.
34
- ByPackagePath map [PackagePath ][]* Package
34
+ ForPackagePath map [PackagePath ][]* Package
35
35
36
- // IDs maps file URIs to package IDs , sorted by (!valid, cli, packageID).
36
+ // ForFile maps file URIs to packages , sorted by (!valid, cli, packageID).
37
37
// A single file may belong to multiple packages due to tests packages.
38
- //
39
- // Invariant: all IDs present in the IDs map exist in the metadata map.
40
- IDs map [protocol.DocumentURI ][]PackageID
38
+ ForFile map [protocol.DocumentURI ][]* Package
41
39
}
42
40
43
41
// Metadata implements the [Source] interface
@@ -93,18 +91,18 @@ func (g *Graph) Update(updates map[PackageID]*Package) *Graph {
93
91
// deriving relations from the specified metadata.
94
92
func newGraph (pkgs map [PackageID ]* Package ) * Graph {
95
93
// Build the import graph.
96
- importedBy := make (map [PackageID ][]PackageID )
94
+ importedBy := make (map [PackageID ][]* Package )
97
95
byPackagePath := make (map [PackagePath ][]* Package )
98
- for id , mp := range pkgs {
96
+ for _ , mp := range pkgs {
99
97
for _ , depID := range mp .DepsByPkgPath {
100
- importedBy [depID ] = append (importedBy [depID ], id )
98
+ importedBy [depID ] = append (importedBy [depID ], mp )
101
99
}
102
100
byPackagePath [mp .PkgPath ] = append (byPackagePath [mp .PkgPath ], mp )
103
101
}
104
102
105
103
// Collect file associations.
106
- uriIDs := make (map [protocol.DocumentURI ][]PackageID )
107
- for id , mp := range pkgs {
104
+ uriPkgs := make (map [protocol.DocumentURI ][]* Package )
105
+ for _ , mp := range pkgs {
108
106
uris := map [protocol.DocumentURI ]struct {}{}
109
107
for _ , uri := range mp .CompiledGoFiles {
110
108
uris [uri ] = struct {}{}
@@ -118,34 +116,34 @@ func newGraph(pkgs map[PackageID]*Package) *Graph {
118
116
}
119
117
}
120
118
for uri := range uris {
121
- uriIDs [uri ] = append (uriIDs [uri ], id )
119
+ uriPkgs [uri ] = append (uriPkgs [uri ], mp )
122
120
}
123
121
}
124
122
125
123
// Sort and filter file associations.
126
- for uri , ids := range uriIDs {
127
- sort .Slice (ids , func (i , j int ) bool {
128
- cli := IsCommandLineArguments (ids [i ])
129
- clj := IsCommandLineArguments (ids [j ])
124
+ for uri , pkgs := range uriPkgs {
125
+ sort .Slice (pkgs , func (i , j int ) bool {
126
+ cli := IsCommandLineArguments (pkgs [i ]. ID )
127
+ clj := IsCommandLineArguments (pkgs [j ]. ID )
130
128
if cli != clj {
131
129
return clj
132
130
}
133
131
134
132
// 2. packages appear in name order.
135
- return ids [i ] < ids [j ]
133
+ return pkgs [i ]. ID < pkgs [j ]. ID
136
134
})
137
135
138
- // Choose the best IDs for each URI, according to the following rules:
136
+ // Choose the best packages for each URI, according to the following rules:
139
137
// - If there are any valid real packages, choose them.
140
138
// - Else, choose the first valid command-line-argument package, if it exists.
141
139
//
142
- // TODO(rfindley): it might be better to track all IDs here, and exclude
140
+ // TODO(rfindley): it might be better to track all packages here, and exclude
143
141
// them later when type checking, but this is the existing behavior.
144
- for i , id := range ids {
142
+ for i , pkg := range pkgs {
145
143
// If we've seen *anything* prior to command-line arguments package, take
146
- // it. Note that ids [0] may itself be command-line-arguments.
147
- if i > 0 && IsCommandLineArguments (id ) {
148
- uriIDs [uri ] = ids [:i ]
144
+ // it. Note that pkgs [0] may itself be command-line-arguments.
145
+ if i > 0 && IsCommandLineArguments (pkg . ID ) {
146
+ uriPkgs [uri ] = pkgs [:i ]
149
147
break
150
148
}
151
149
}
@@ -167,10 +165,10 @@ func newGraph(pkgs map[PackageID]*Package) *Graph {
167
165
}
168
166
169
167
return & Graph {
170
- Packages : pkgs ,
171
- ImportedBy : importedBy ,
172
- ByPackagePath : byPackagePath ,
173
- IDs : uriIDs ,
168
+ Packages : pkgs ,
169
+ ImportedBy : importedBy ,
170
+ ForPackagePath : byPackagePath ,
171
+ ForFile : uriPkgs ,
174
172
}
175
173
}
176
174
@@ -179,18 +177,22 @@ func newGraph(pkgs map[PackageID]*Package) *Graph {
179
177
// transitively imports one of them, keyed by ID, including all the initial packages.
180
178
func (g * Graph ) ReverseReflexiveTransitiveClosure (ids ... PackageID ) map [PackageID ]* Package {
181
179
seen := make (map [PackageID ]* Package )
182
- var visitAll func ([]PackageID )
183
- visitAll = func (ids []PackageID ) {
184
- for _ , id := range ids {
185
- if seen [id ] == nil {
186
- if mp := g .Packages [id ]; mp != nil {
187
- seen [id ] = mp
188
- visitAll (g .ImportedBy [id ])
189
- }
180
+ var visitAll func ([]* Package )
181
+ visitAll = func (pkgs []* Package ) {
182
+ for _ , pkg := range pkgs {
183
+ if seen [pkg .ID ] == nil {
184
+ seen [pkg .ID ] = pkg
185
+ visitAll (g .ImportedBy [pkg .ID ])
190
186
}
191
187
}
192
188
}
193
- visitAll (ids )
189
+ var initial []* Package
190
+ for _ , id := range ids {
191
+ if pkg := g .Packages [id ]; pkg != nil {
192
+ initial = append (initial , pkg )
193
+ }
194
+ }
195
+ visitAll (initial )
194
196
return seen
195
197
}
196
198
0 commit comments