89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package facts
|
||
|
|
||
|
import "go/types"
|
||
|
|
||
|
// importMap computes the import map for a package by traversing the
|
||
|
// entire exported API each of its imports.
|
||
|
//
|
||
|
// This is a workaround for the fact that we cannot access the map used
|
||
|
// internally by the types.Importer returned by go/importer. The entries
|
||
|
// in this map are the packages and objects that may be relevant to the
|
||
|
// current analysis unit.
|
||
|
//
|
||
|
// Packages in the map that are only indirectly imported may be
|
||
|
// incomplete (!pkg.Complete()).
|
||
|
//
|
||
|
func importMap(imports []*types.Package) map[string]*types.Package {
|
||
|
objects := make(map[types.Object]bool)
|
||
|
packages := make(map[string]*types.Package)
|
||
|
|
||
|
var addObj func(obj types.Object) bool
|
||
|
var addType func(T types.Type)
|
||
|
|
||
|
addObj = func(obj types.Object) bool {
|
||
|
if !objects[obj] {
|
||
|
objects[obj] = true
|
||
|
addType(obj.Type())
|
||
|
if pkg := obj.Pkg(); pkg != nil {
|
||
|
packages[pkg.Path()] = pkg
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
addType = func(T types.Type) {
|
||
|
switch T := T.(type) {
|
||
|
case *types.Basic:
|
||
|
// nop
|
||
|
case *types.Named:
|
||
|
if addObj(T.Obj()) {
|
||
|
for i := 0; i < T.NumMethods(); i++ {
|
||
|
addObj(T.Method(i))
|
||
|
}
|
||
|
}
|
||
|
case *types.Pointer:
|
||
|
addType(T.Elem())
|
||
|
case *types.Slice:
|
||
|
addType(T.Elem())
|
||
|
case *types.Array:
|
||
|
addType(T.Elem())
|
||
|
case *types.Chan:
|
||
|
addType(T.Elem())
|
||
|
case *types.Map:
|
||
|
addType(T.Key())
|
||
|
addType(T.Elem())
|
||
|
case *types.Signature:
|
||
|
addType(T.Params())
|
||
|
addType(T.Results())
|
||
|
case *types.Struct:
|
||
|
for i := 0; i < T.NumFields(); i++ {
|
||
|
addObj(T.Field(i))
|
||
|
}
|
||
|
case *types.Tuple:
|
||
|
for i := 0; i < T.Len(); i++ {
|
||
|
addObj(T.At(i))
|
||
|
}
|
||
|
case *types.Interface:
|
||
|
for i := 0; i < T.NumMethods(); i++ {
|
||
|
addObj(T.Method(i))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, imp := range imports {
|
||
|
packages[imp.Path()] = imp
|
||
|
|
||
|
scope := imp.Scope()
|
||
|
for _, name := range scope.Names() {
|
||
|
addObj(scope.Lookup(name))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return packages
|
||
|
}
|