func (m *mDoc) Call() (interface{}, string) { res := []*Doc{} fset, af, err := parseAstFile(m.Fn, m.Src, parser.ParseComments) if err != nil { return res, err.Error() } sel, id := identAt(fset, af, m.Offset) if id == nil { return res, "" } pkgs, _ := parser.ParseDir(fset, filepath.Dir(m.Fn), fiHasGoExt, parser.ParseComments) if pkgs == nil { pkgs = map[string]*ast.Package{} } pkgName := af.Name.Name files := map[string]*ast.File{} pkg, _ := pkgs[pkgName] if pkg != nil { files = pkg.Files } files[m.Fn] = af pkg, _ = ast.NewPackage(fset, files, nil, nil) if pkg == nil { return res, "" } pkgs[pkg.Name] = pkg obj, pkg, objPkgs := findUnderlyingObj(fset, af, pkg, pkgs, rootDirs(m.Env), sel, id) if obj != nil { res = append(res, objDoc(fset, pkg, m.TabIndent, m.TabWidth, obj)) if objPkgs != nil { xName := "Example" + obj.Name xPrefix := xName + "_" for _, objPkg := range objPkgs { xPkg, _ := ast.NewPackage(fset, objPkg.Files, nil, nil) if xPkg == nil || xPkg.Scope == nil { continue } for _, xObj := range xPkg.Scope.Objects { if xObj.Name == xName || strings.HasPrefix(xObj.Name, xPrefix) { res = append(res, objDoc(fset, xPkg, m.TabIndent, m.TabWidth, xObj)) } } } } } return res, "" }
func check(t *testing.T, testname string, testfiles []string) { // TODO(gri) Eventually all these different phases should be // subsumed into a single function call that takes // a set of files and creates a fully resolved and // type-checked AST. files, err := parseFiles(t, testname, testfiles) // we are expecting the following errors // (collect these after parsing the files so that // they are found in the file set) errors := expectedErrors(t, testname, files) // verify errors returned by the parser eliminate(t, errors, err) // verify errors returned after resolving identifiers pkg, err := ast.NewPackage(fset, files, GcImporter, Universe) eliminate(t, errors, err) // verify errors returned by the typechecker _, err = Check(fset, pkg) eliminate(t, errors, err) // there should be no expected errors left if len(errors) > 0 { t.Errorf("%s: %d errors not reported:", testname, len(errors)) for pos, msg := range errors { t.Errorf("%s: %s\n", fset.Position(pos), msg) } } }
// parseReflect parses the reflect package and type-checks its AST. // This is used to generate runtime type structures. func (c *compiler) parseReflect() (*ast.Package, error) { buildpkg, err := build.Import("reflect", "", 0) if err != nil { return nil, err } filenames := make([]string, len(buildpkg.GoFiles)) for i, f := range buildpkg.GoFiles { filenames[i] = path.Join(buildpkg.Dir, f) } fset := token.NewFileSet() files, err := parseFiles(fset, filenames) if err != nil { return nil, err } pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { return nil, err } _, err = types.Check(buildpkg.Name, c, fset, pkg) if err != nil { return nil, err } return pkg, nil }
func compilePackage(fset *token.FileSet, files map[string]*ast.File) (*llgo.Module, error) { // make a package (resolve all identifiers) pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { report(err) return nil, err } exprTypes, err := types.Check(fset, pkg) if err != nil { report(err) return nil, err } if *dumpast { ast.Fprint(os.Stderr, fset, pkg, nil) os.Exit(0) } compiler := llgo.NewCompiler() compiler.SetTraceEnabled(*trace) compiler.SetTargetArch(*arch) compiler.SetTargetOs(*os_) return compiler.Compile(fset, pkg, exprTypes) }
func TestFilterDuplicates(t *testing.T) { // parse input fset := token.NewFileSet() file, err := parser.ParseFile(fset, "", input, 0) if err != nil { t.Fatal(err) } // create package files := map[string]*ast.File{"": file} pkg, err := ast.NewPackage(fset, files, nil, nil) if err != nil { t.Fatal(err) } // filter merged := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates) // pretty-print var buf bytes.Buffer if err := format.Node(&buf, fset, merged); err != nil { t.Fatal(err) } output := buf.String() if output != golden { t.Errorf("incorrect output:\n%s", output) } }
func doParseReflect() { buildpkg, err := build.Import("reflect", "", 0) if err != nil { parseReflectResult, parseReflectError = nil, err return } filenames := make([]string, len(buildpkg.GoFiles)) for i, f := range buildpkg.GoFiles { filenames[i] = path.Join(buildpkg.Dir, f) } fset := token.NewFileSet() files, err := parseFiles(fset, filenames) if err != nil { parseReflectResult, parseReflectError = nil, err return } pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { parseReflectResult, parseReflectError = nil, err return } _, err = types.Check(fset, pkg) if err != nil { parseReflectResult, parseReflectError = nil, err return } parseReflectResult, parseReflectError = pkg, nil return }
func compilePackage(compiler llgo.Compiler, fset *token.FileSet, files map[string]*ast.File, importpath string) (*llgo.Module, error) { // make a package (resolve all identifiers) pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { report(err) return nil, err } // an empty importpath means the same as the package name if importpath == "" { importpath = pkg.Name } exprTypes, err := types.Check(importpath, compiler, fset, pkg) if err != nil { report(err) return nil, err } if *dumpast { ast.Fprint(os.Stderr, fset, pkg, nil) os.Exit(0) } return compiler.Compile(fset, pkg, importpath, exprTypes) }
func main() { flag.Parse() if len(flag.Args()) != 1 { log.Fatal("Usage: go run goprint.go path") } bpkg, err := build.Default.Import(flag.Args()[0], ".", 0) if err != nil { log.Fatal(err) } fset := token.NewFileSet() files := make(map[string]*ast.File) for _, fname := range bpkg.GoFiles { p, err := ioutil.ReadFile(filepath.Join(bpkg.SrcRoot, bpkg.ImportPath, fname)) if err != nil { log.Fatal(err) } file, err := parser.ParseFile(fset, fname, p, parser.ParseComments) if err != nil { log.Fatal(err) } files[fname] = file } c := spew.NewDefaultConfig() c.DisableMethods = true apkg, _ := ast.NewPackage(fset, files, importer, nil) c.Dump(apkg) ast.Print(fset, apkg) dpkg := doc.New(apkg, bpkg.ImportPath, 0) c.Dump(dpkg) }
func ExtractStructs(inputPath string) (string, []*StructInfo, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, inputPath, nil, parser.ParseComments) if err != nil { return "", nil, err } packageName := f.Name.String() structs := make(map[string]*StructInfo) for k, d := range f.Scope.Objects { if d.Kind == ast.Typ { incl, err := shouldInclude(d) if err != nil { return "", nil, err } if incl { stobj := NewStructInfo(k) structs[k] = stobj } } } files := map[string]*ast.File{ inputPath: f, } pkg, _ := ast.NewPackage(fset, files, nil, nil) d := doc.New(pkg, f.Name.String(), doc.AllDecls) for _, t := range d.Types { if skipre.MatchString(t.Doc) { delete(structs, t.Name) } else { if skipdec.MatchString(t.Doc) { s, ok := structs[t.Name] if ok { s.Options.SkipDecoder = true } } if skipenc.MatchString(t.Doc) { s, ok := structs[t.Name] if ok { s.Options.SkipEncoder = true } } } } rv := make([]*StructInfo, 0) for _, v := range structs { rv = append(rv, v) } return packageName, rv, nil }
// build generates data from source files. func (w *routerWalker) build(srcs []*source) (*Package, error) { // Add source files to walker, I skipped references here. w.srcs = make(map[string]*source) for _, src := range srcs { w.srcs[src.name] = src } w.fset = token.NewFileSet() // Find the package and associated files. ctxt := gobuild.Context{ GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, CgoEnabled: true, JoinPath: path.Join, IsAbsPath: path.IsAbs, SplitPathList: func(list string) []string { return strings.Split(list, ":") }, IsDir: func(path string) bool { panic("unexpected") }, HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") }, ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, Compiler: "gc", } bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0) // Continue if there are no Go source files; we still want the directory info. _, nogo := err.(*gobuild.NoGoError) if err != nil { if nogo { err = nil } else { return nil, errors.New("routerWalker.build -> " + err.Error()) } } // Parse the Go files files := make(map[string]*ast.File) for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) if err != nil { return nil, errors.New("routerWalker.build -> parse go files: " + err.Error()) } files[name] = file } apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) mode := doc.Mode(0) if w.pdoc.ImportPath == "builtin" { mode |= doc.AllDecls } pdoc := doc.New(apkg, w.pdoc.ImportPath, mode) w.pdoc.Types = w.types(pdoc.Types) return w.pdoc, err }
func TestResolveQualifiedIdents(t *testing.T) { // parse package files fset := token.NewFileSet() files := make(map[string]*ast.File) for i, src := range sources { filename := fmt.Sprintf("file%d", i) f, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors) if err != nil { t.Fatal(err) } files[filename] = f } // resolve package AST pkg, err := ast.NewPackage(fset, files, GcImport, Universe) if err != nil { t.Fatal(err) } // check that all packages were imported for _, name := range pkgnames { if pkg.Imports[name] == nil { t.Errorf("package %s not imported", name) } } // check that there are no top-level unresolved identifiers for _, f := range pkg.Files { for _, x := range f.Unresolved { t.Errorf("%s: unresolved global identifier %s", fset.Position(x.Pos()), x.Name) } } // resolve qualified identifiers if err := ResolveQualifiedIdents(fset, pkg); err != nil { t.Error(err) } // check that qualified identifiers are resolved ast.Inspect(pkg, func(n ast.Node) bool { if s, ok := n.(*ast.SelectorExpr); ok { if x, ok := s.X.(*ast.Ident); ok { if x.Obj == nil { t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name) return false } if x.Obj.Kind == ast.Pkg && s.Sel != nil && s.Sel.Obj == nil { t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name) return false } return false } return false } return true }) }
// AnalyzeFile scans the provided file for references to packages with the given // package prefix. The list of unique (package, identifier) pairs is returned func AnalyzeFile(file *ast.File, pkgPrefix string) (*References, error) { visitor := newRefsSaver(pkgPrefix) fset := token.NewFileSet() files := map[string]*ast.File{file.Name.Name: file} // Ignore errors (from unknown packages) pkg, _ := ast.NewPackage(fset, files, visitor.importer(), nil) ast.Walk(visitor, pkg) return &visitor.References, nil }
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value { f, _ := c.functions[name+":"+signature] if !f.IsNil() { return f } if strings.HasPrefix(name, c.module.Name+".") { obj := c.pkg.Scope.Lookup(name[len(c.module.Name)+1:]) value := c.Resolve(obj) f = value.LLVMValue() } else { fset := token.NewFileSet() code := `package runtime;import("unsafe");` + signature + `{panic()}` file, err := parser.ParseFile(fset, "", code, 0) if err != nil { panic(err) } // Parse the runtime package, since we may need to refer to // its types. TODO cache the package. buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0) if err != nil { panic(err) } runtimefiles := make([]string, len(buildpkg.GoFiles)) for i, f := range buildpkg.GoFiles { runtimefiles[i] = path.Join(buildpkg.Dir, f) } files, err := parseFiles(fset, runtimefiles) if err != nil { panic(err) } files["<src>"] = file pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { panic(err) } _, err = types.Check(fset, pkg) if err != nil { panic(err) } fdecl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl) ftype := fdecl.Name.Obj.Type.(*types.Func) llvmfptrtype := c.types.ToLLVM(ftype) f = llvm.AddFunction(c.module.Module, name, llvmfptrtype.ElementType()) if !strings.HasPrefix(name, "llvm.") { f.SetLinkage(llvm.AvailableExternallyLinkage) } } c.functions[name+":"+signature] = f return f }
//ExtractStructs extract struct infos from file func ExtractStructs(inputPath string) (string, []*ActStructInfo, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, inputPath, nil, parser.ParseComments) if err != nil { return "", nil, err } packageName := f.Name.String() structs := make(map[string]*ActStructInfo) for k, d := range f.Scope.Objects { if d.Kind == ast.Typ { ts, ok := d.Decl.(*ast.TypeSpec) if !ok { return "", nil, fmt.Errorf("Unknown type without TypeSec: %v", d) } _, ok = ts.Type.(*ast.StructType) if !ok { _, ok = ts.Type.(*ast.ArrayType) if !ok { _, ok = ts.Type.(*ast.MapType) if !ok { continue } } } stobj := NewStructInfo(k) structs[k] = stobj } } files := map[string]*ast.File{ inputPath: f, } pkg, _ := ast.NewPackage(fset, files, nil, nil) d := doc.New(pkg, f.Name.String(), doc.AllDecls) for _, t := range d.Types { if skipre.MatchString(t.Doc) { delete(structs, t.Name) } } var rv []*ActStructInfo for _, v := range structs { rv = append(rv, v) } return packageName, rv, nil }
func (ctx *Context) loadPackage(importPath string, flags int) (*Package, error) { bpkg, err := build.Import(importPath, ctx.cwd, 0) if _, ok := err.(*build.NoGoError); ok { return &Package{bpkg: bpkg}, nil } if err != nil { return nil, err } pkg := &Package{ fset: token.NewFileSet(), bpkg: bpkg, } files := make(map[string]*ast.File) for _, name := range append(pkg.bpkg.GoFiles, pkg.bpkg.CgoFiles...) { file, err := pkg.parseFile(name) if err != nil { pkg.errors = append(pkg.errors, err) continue } files[name] = file } pkg.apkg, _ = ast.NewPackage(pkg.fset, files, simpleImporter, nil) if flags&loadDoc != 0 { mode := doc.Mode(0) if pkg.bpkg.ImportPath == "builtin" || flags&loadUnexported != 0 { mode |= doc.AllDecls } pkg.dpkg = doc.New(pkg.apkg, pkg.bpkg.ImportPath, mode) if pkg.bpkg.ImportPath == "builtin" { for _, t := range pkg.dpkg.Types { pkg.dpkg.Funcs = append(pkg.dpkg.Funcs, t.Funcs...) t.Funcs = nil } sort.Sort(byFuncName(pkg.dpkg.Funcs)) } } if flags&loadExamples != 0 { for _, name := range append(pkg.bpkg.TestGoFiles, pkg.bpkg.XTestGoFiles...) { file, err := pkg.parseFile(name) if err != nil { pkg.errors = append(pkg.errors, err) continue } pkg.examples = append(pkg.examples, doc.Examples(file)...) } } return pkg, nil }
func processPackage(fset *token.FileSet, files map[string]*ast.File) { // make a package (resolve all identifiers) pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { report(err) return } if err = types.Check(fset, pkg, nil, nil); err != nil { report(err) } }
func LookupType(pkgs map[string]*ast.Package, name string) *ast.Object { for k := range pkgs { fset := token.NewFileSet() pkg, err := ast.NewPackage(fset, pkgs[k].Files, nil, nil) if err != nil { // panic(err) // too much errors due to the abscence of an importer (incomplete types) } return pkg.Scope.Lookup(name) } return nil }
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value { f, _ := c.functions[name+":"+signature] if !f.IsNil() { return f } if strings.HasPrefix(name, c.module.Name+".") { obj := c.pkg.Scope.Lookup(name[len(c.module.Name)+1:]) value := c.Resolve(obj) f = value.LLVMValue() } else { fset := token.NewFileSet() code := `package runtime;import("unsafe");` + signature + `{panic()}` file, err := parser.ParseFile(fset, "", code, 0) if err != nil { panic(err) } // Parse the runtime package, since we may need to refer to // its types. Can't be cached, because type-checking can't // be done twice on the AST. buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0) if err != nil { panic(err) } // All types visible to the compiler are in "types.go". runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")} files, err := parseFiles(fset, runtimefiles) if err != nil { panic(err) } files["<src>"] = file pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe) if err != nil { panic(err) } _, err = types.Check("", c.compiler, fset, pkg) if err != nil { panic(err) } fdecl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl) ftype := fdecl.Name.Obj.Type.(*types.Func) llvmfptrtype := c.types.ToLLVM(ftype) f = llvm.AddFunction(c.module.Module, name, llvmfptrtype.ElementType()) } c.functions[name+":"+signature] = f return f }
func New(p *build.Package, mode parser.Mode) (*token.FileSet, *ast.Package, error) { fset := token.NewFileSet() var names []string names = append(names, p.GoFiles...) names = append(names, p.CgoFiles...) files, err := ParseFiles(fset, p.Dir, names, mode) if err != nil { return nil, nil, err } a, _ := ast.NewPackage(fset, files, Importer, nil) return fset, a, nil }
func (e Environment) _importPackage(p string, shallow bool) (*Package, error) { b, err := e.importBuildPackage(p) if err != nil { if noBuildable(err) && !shallow { dir, sub, err := e.importSubpackages(p) if err != nil { return nil, err } return &Package{name: path.Base(p), dir: dir, Packages: sub, env: e}, nil } } fset := token.NewFileSet() var names []string names = append(names, b.GoFiles...) names = append(names, b.CgoFiles...) files, err := e.parseFiles(fset, b.Dir, names, parser.ParseComments) if err != nil { return nil, err } bodies := make(map[*ast.FuncDecl]*ast.BlockStmt) for _, f := range files { for _, d := range f.Decls { if fn, ok := d.(*ast.FuncDecl); ok { bodies[fn] = fn.Body } } } // NewPackage will always return errors because it won't // resolve builtin types. a, _ := ast.NewPackage(fset, files, astutil.Importer, nil) flags := doc.AllMethods if p == "builtin" { flags |= doc.AllDecls } pkg := &Package{ fset: fset, bpkg: b, apkg: a, dpkg: doc.New(a, b.ImportPath, flags), bodies: bodies, env: e, } if !shallow { sub, err := e.ImportPackages(b.Dir) if err != nil { return nil, err } pkg.Packages = sub } return pkg, nil }
func populateASTWithTokenSet(pkg *Package, fset *token.FileSet) error { gtor := &astPopulator{fset: fset, populated: map[canPopulateAST]struct{}{}} files := map[string]*ast.File{} for _, f := range pkg.Files() { f.populateAST(gtor) files[f.Name()] = f.AST() } apkg, err := ast.NewPackage(gtor.fset, files, nil, nil) pkg.ast = apkg return err }
func parsePkg(fset *token.FileSet, srcDir string, mode parser.Mode) (pkg *ast.Package, pkgs map[string]*ast.Package, err error) { if pkgs, err = parser.ParseDir(fset, srcDir, fiHasGoExt, mode); pkgs != nil { _, pkgName := filepath.Split(srcDir) // we aren't going to support package whose name don't match the directory unless it's main p, ok := pkgs[pkgName] if !ok { p, ok = pkgs["main"] } if ok { pkg, err = ast.NewPackage(fset, p.Files, nil, nil) } } return }
func packageFromInfo(prog *loader.Program, pkgInfo *loader.PackageInfo) *Package { files := map[string]*ast.File{} for _, f := range pkgInfo.Files { files[prog.Fset.File(f.Pos()).Name()] = f } // Ignore (perhaps) "unresolved identifier" errors astPkg, _ := ast.NewPackage(prog.Fset, files, nil, nil) var mode doc.Mode docPkg := doc.New(astPkg, pkgInfo.String(), mode) return NewPackage(prog.Fset, docPkg, pkgInfo.Pkg) }
func (b *builder) merge() ([]byte, error) { var buf bytes.Buffer if err := b.tpl.Execute(&buf, b); err != nil { return nil, err } f, err := parser.ParseFile(b.fset, "", &buf, 0) if err != nil { return nil, err } // b.imports(f) b.deleteImports(f) b.files["main.go"] = f pkg, _ := ast.NewPackage(b.fset, b.files, nil, nil) pkg.Name = "main" ret, err := ast.MergePackageFiles(pkg, 0), nil if err != nil { return nil, err } // @TODO: we reread the file, probably something goes wrong with position buf.Reset() if err = format.Node(&buf, b.fset, ret); err != nil { return nil, err } ret, err = parser.ParseFile(b.fset, "", buf.Bytes(), 0) if err != nil { return nil, err } for _, spec := range b.imports { var name string if spec.Name != nil { name = spec.Name.Name } ipath, _ := strconv.Unquote(spec.Path.Value) addImport(b.fset, ret, name, ipath) } buf.Reset() if err := format.Node(&buf, b.fset, ret); err != nil { return nil, err } return buf.Bytes(), nil }
func astFrom(filePath string) *doc.Package { fset := token.NewFileSet() m := make(map[string]*ast.File) f, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments) if err != nil { fmt.Println(err) return nil } m[filePath] = f apkg, _ := ast.NewPackage(fset, m, nil, nil) return doc.New(apkg, "", 0) }
func NewPackageAST(files []string) (*ast.Package, error) { asts := make(map[string]*ast.File) fset := token.NewFileSet() for _, file := range files { ast, err := parser.ParseFile(fset, file, nil, parser.ParseComments) if err != nil { return nil, err } asts[file] = ast } pkg, _ := ast.NewPackage(fset, asts, nil, nil) return pkg, nil }
func makePkg(t *testing.T, src string) (*ast.Package, error) { file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors) if err != nil { return nil, err } files := map[string]*ast.File{filename: file} pkg, err := ast.NewPackage(fset, files, GcImport, Universe) if err != nil { return nil, err } if err := Check(fset, pkg, nil, nil); err != nil { return nil, err } return pkg, nil }
func main() { fset := token.NewFileSet() files := map[string]*ast.File{} for _, f := range os.Args[1:] { file, err := parser.ParseFile(fset, f, nil, 0) if err != nil { panic("parse file:" + err.Error()) } files[f] = file } pack, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe) if err != nil { panic("new package" + err.Error()) } /*for name, object := range pack.Scope.Objects { if f, ok := object.Decl.(*ast.FuncDecl); ok { if f.Type.Results == nil { continue } for _, returnValue := range f.Type.Results.List { if returnValue.Type.(*ast.Ident).Name == "error" { fmt.Println(name, ": function returns error") } } } }*/ //check that the file is valid /*valid := true ast.Walk(visitor(func(node ast.Node) bool { switch node.(type) { case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt: valid = false return false } return true }), pack) if !valid { panic("invalid file") }*/ ast.Walk(SimpleVisitor{pack, fset}, pack) }
func NewFilePackage(filename string) (*PackageView, error) { p := new(PackageView) p.fset = token.NewFileSet() file, err := parser.ParseFile(p.fset, filename, nil, parser.AllErrors) if file == nil { return nil, err } m := make(map[string]*ast.File) m[filename] = file pkg, err := ast.NewPackage(p.fset, m, nil, nil) if err != nil { return nil, err } p.pkg = pkg p.pdoc = doc.New(pkg, pkg.Name, doc.AllDecls) return p, nil }
// AnalyzePackages scans the provided packages for references to packages with the given // package prefix. The list of unique (package, identifier) pairs is returned func AnalyzePackages(pkgs []*build.Package, pkgPrefix string) (*References, error) { visitor := newRefsSaver(pkgPrefix) imp := visitor.importer() fset := token.NewFileSet() for _, pkg := range pkgs { fileNames := append(append([]string{}, pkg.GoFiles...), pkg.CgoFiles...) files := make(map[string]*ast.File) for _, name := range fileNames { f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, 0) if err != nil { return nil, err } files[name] = f } // Ignore errors (from unknown packages) astpkg, _ := ast.NewPackage(fset, files, imp, nil) ast.Walk(visitor, astpkg) } return &visitor.References, nil }