Используйте ast.NewPackage для разрешения идентификаторов в AST. Для функции NewPackage требуется средство импорта, которое ищет информацию о пакете для пути импорта. Вот простой импортер, который отвечает потребностям этого вопроса. Импортер возвращает объект пакета с правильным именем для стандартных пакетов и сгенерированным именем для нестандартных пакетов.
var genNameCounter int
func simpleImporter(imports map[string]*ast.Object, p string) (*ast.Object, error) {
pkg := imports[p]
if pkg != nil {
return pkg, nil
}
// This is correct for standard packages
name := path.Base(p)
if !isStandardLibraryPath(p) {
// Generate fake name that will not match name of a standard package.
genNameCounter++
name = fmt.Sprintf("genName%d", genNameCounter)
}
pkg = ast.NewObj(ast.Pkg, name)
pkg.Data = ast.NewScope(nil)
imports[p] = pkg
return pkg, nil
}
Импортер использует функцию, которая возвращает true для путей импорта в стандартной библиотеке. Приближение этой функции следует. См. Могу ли я перечислить все стандартные Go пакеты? для получения информации о том, как реализовать реальную функцию.
func isStandardLibraryPath(path string) bool {
return !strings.Contains(path, ".")
}
Если вы хотите разрешить все идентификаторы пакетов, используйте go / build package, чтобы найти имя пакета для пути импорта. Преимущество использования simpleImporter
, представленного здесь, заключается в том, что функция не читает исходные файлы на диске.
Разрешите идентификаторы и создайте карту из областей пакета для пути импорта:
pkg, err := ast.NewPackage(fset, files, simpleImporter, nil)
// Create map from scope to path
paths := make(map[interface{}]string)
for path, obj := range pkg.Imports {
paths[obj.Data] = path
}
Используйте эту карту, чтобы определить, разрешен ли *ast.Ident
в стандартный пакет.
func isStandardLibraryIdent(paths map[interface{}]string, ident *ast.Ident) bool {
if ident.Obj == nil || ident.Obj.Kind != ast.Pkg {
return false
}
path, ok := paths[ident.Obj.Data]
if !ok {
return false
}
return isStandardLibraryPath(path)
}
Запустите его на игровой площадке Go .