func (g *Go) complete_pkg(pkg string, cmp *content.CompletionResult) error { if g.imports == nil { g.imports = make(map[string]*types.Package) } if p, err := types.GcImport(g.imports, pkg); err != nil { return err } else { nn := p.Scope() for i := 0; i < nn.NumEntries(); i++ { t := nn.At(i) var flags content.Flags if n := t.Name(); n[0] != strings.ToUpper(n)[0] { flags = content.FLAG_ACC_PROTECTED } else { flags = content.FLAG_ACC_PUBLIC } switch t.(type) { case *types.Func: var m content.Method m.Flags |= flags m.Name.Relative = t.Name() sig := t.Type().Underlying().(*types.Signature) if sig.Recv() != nil { continue } par := sig.Params() for j := 0; j < par.Len(); j++ { m.Parameters = append(m.Parameters, g.pkg_var(par.At(j))) } ret := sig.Results() for j := 0; j < ret.Len(); j++ { m.Returns = append(m.Returns, g.pkg_var(ret.At(j))) } cmp.Methods = append(cmp.Methods, m) case *types.TypeName: var t2 content.Type t2.Flags |= flags t2.Name.Relative = t.Name() switch t.Type().Underlying().(type) { case *types.Interface: t2.Flags |= content.FLAG_TYPE_INTERFACE case *types.Struct: t2.Flags |= content.FLAG_TYPE_STRUCT } cmp.Types = append(cmp.Types, t2) case *types.Const, *types.Var: var f content.Field f.Name.Relative = t.Name() f.Type = g.pkg_type(t.Type()) cmp.Fields = append(cmp.Fields, f) default: log4go.Warn("Unimplemented type in package completion: at: %+v, %v, %v", t, reflect.TypeOf(t), reflect.TypeOf(t.Type().Underlying())) } } } return nil }
// importBinary implements package loading from object files from the // gc compiler. // func (imp *Importer) importBinary(imports map[string]*types.Package, ii *importInfo) { pkg, err := types.GcImport(imports, ii.path) if pkg != nil { ii.info = &PackageInfo{Pkg: pkg} imp.addPackage(ii.info) } else { ii.err = err } }
func (c *importer) Import(imports map[string]*types.Package, path string) (pkg *types.Package, err error) { if c.myimports == nil { // myimports is different from imports. Imports can contain // dummy packages not loaded by us, while myimports will // be "pure". c.myimports = make(map[string]*types.Package) } if pkg, ok := c.myimports[path]; ok { if pkg == nil { return nil, fmt.Errorf("Previous attempt at loading package failed") } return pkg, nil } var data []byte pkgfile := c.compiler.packageExportsFile(path) if path == "unsafe" { // Importing these packages have issues // // unsafe: // If this is actually imported, go.types will panic due to invalid type conversions. // This because it is a built in package (http://tip.golang.org/doc/spec#Package_unsafe) // and thus shouldn't be treated as a normal package anyway. } else { data, _ = ioutil.ReadFile(pkgfile) } if data != nil { // Need to load dependencies first for _, match := range importsRe.FindAllStringSubmatch(string(data), -1) { if _, ok := c.myimports[match[1]]; !ok { _, err := c.Import(imports, match[1]) if err != nil { return nil, err } } } pkg, err = types.GcImportData(imports, pkgfile, path, bufio.NewReader(bytes.NewBuffer(data))) } if pkg == nil || err != nil { if data != nil { return nil, fmt.Errorf("Failed to load package %s: %v", path, err) } // Package has not been compiled yet, so fall back to // the standard GcImport. pkg, err = types.GcImport(imports, path) } c.myimports[path] = pkg imports[path] = pkg return pkg, err }
func (p *Parser) importSourceFirst(imports map[string]*types.Package, fs *token.FileSet, importPath string, unsaved map[string]UnsavedDocument, options Options, info *types.Info) (*types.Package, error) { if pkg := imports[importPath]; pkg != nil && pkg.Complete() { return pkg, nil } pkg, err := p.tryImportSource(fs, imports, importPath, unsaved, options, info) if pkg == nil { pkg, err = types.GcImport(imports, importPath) } return pkg, err }
func (ctx *Context) getObjects(paths []string) ([]types.Object, []error) { var errors []error var objects []types.Object pathLoop: for _, path := range paths { buildPkg, err := build.Import(path, ".", 0) if err != nil { errors = append(errors, fmt.Errorf("Couldn't import %s: %s", path, err)) continue } fset := token.NewFileSet() var astFiles []*ast.File var pkg *types.Package if buildPkg.Goroot { // TODO what if the compiled package in GoRoot is // outdated? pkg, err = types.GcImport(ctx.allImports, path) if err != nil { errors = append(errors, fmt.Errorf("Couldn't import %s: %s", path, err)) continue } } else { if len(buildPkg.GoFiles) == 0 { errors = append(errors, fmt.Errorf("Couldn't parse %s: No (non cgo) Go files", path)) continue pathLoop } for _, file := range buildPkg.GoFiles { astFile, err := parseFile(fset, filepath.Join(buildPkg.Dir, file)) if err != nil { errors = append(errors, fmt.Errorf("Couldn't parse %s: %s", err)) continue pathLoop } astFiles = append(astFiles, astFile) } pkg, err = check(ctx, path, fset, astFiles) if err != nil { errors = append(errors, fmt.Errorf("Couldn't parse %s: %s\n", path, err)) continue pathLoop } } scope := pkg.Scope() for i := 0; i < scope.NumEntries(); i++ { obj := scope.At(i) objects = append(objects, obj) } } return objects, errors }
// doImport loads the typechecker package identified by path // Implements the types.Importer prototype. // func (b *Builder) doImport(imports map[string]*types.Package, path string) (typkg *types.Package, err error) { // Package unsafe is handled specially, and has no ssa.Package. if path == "unsafe" { return types.Unsafe, nil } if pkg := b.Prog.Packages[path]; pkg != nil { typkg = pkg.Types imports[path] = typkg return // positive cache hit } if err = b.importErrs[path]; err != nil { return // negative cache hit } var files []*ast.File var info *TypeInfo if b.Context.Mode&UseGCImporter != 0 { typkg, err = types.GcImport(imports, path) } else { files, err = b.Context.Loader(b.Prog.Files, path) if err == nil { typkg, info, err = b.typecheck(path, files) } } if err != nil { // Cache failure b.importErrs[path] = err return nil, err } // Cache success imports[path] = typkg // cache for just this package. b.Prog.Packages[path] = b.createPackageImpl(typkg, path, files, info) // cache across all packages return typkg, nil }
// Import implements the Importer type from go/types. func (imp Importer) Import(imports map[string]*types.Package, path string) (pkg *types.Package, err error) { // types.Importer does not seem to be designed for recursive // parsing like we're doing here. Specifically, each nested import // will maintain its own imports map. This will lead to duplicate // imports and in turn packages, which will lead to funny errors // such as "cannot pass argument ip (variable of type net.IP) to // variable of type net.IP" // // To work around this, we keep a global imports map, allImports, // to which we add all nested imports, and which we use as the // cache, instead of imports. // // Since all nested imports will also use this importer, there // should be no way to end up with duplicate imports. // We first try to use GcImport directly. This has the downside of // using possibly out-of-date packages, but it has the upside of // not having to parse most of the Go standard library. buildPkg, buildErr := build.Import(path, ".", 0) // If we found no build dir, assume we're dealing with installed // but no source. If we found a build dir, only use GcImport if // it's in GOROOT. This way we always use up-to-date code for // normal packages but avoid parsing the standard library. if (buildErr == nil && buildPkg.Goroot) || buildErr != nil { pkg, err = types.GcImport(imp.Imports, path) if err == nil { // We don't use imports, but per API we have to add the package. imports[pkg.Path()] = pkg imp.Imports[pkg.Path()] = pkg return pkg, nil } } // See if we already imported this package if pkg = imp.Imports[path]; pkg != nil && pkg.Complete() { return pkg, nil } // allImports failed, try to use go/build if buildErr != nil { return nil, fmt.Errorf("build.Import failed: %s", buildErr) } // TODO check if the .a file is up to date and use it instead fileSet := token.NewFileSet() isGoFile := func(d os.FileInfo) bool { allFiles := make([]string, 0, len(buildPkg.GoFiles)+len(buildPkg.CgoFiles)) allFiles = append(allFiles, buildPkg.GoFiles...) allFiles = append(allFiles, buildPkg.CgoFiles...) for _, file := range allFiles { if file == d.Name() { return true } } return false } pkgs, err := parser.ParseDir(fileSet, buildPkg.Dir, isGoFile, 0) if err != nil { return nil, err } delete(pkgs, "documentation") var astPkg *ast.Package var name string for name, astPkg = range pkgs { // Use the first non-main package, or the only package we // found. // // NOTE(dh) I can't think of a reason why there should be // multiple packages in a single directory, but ParseDir // accommodates for that possibility. if len(pkgs) == 1 || name != "main" { break } } if astPkg == nil { return nil, fmt.Errorf("can't find import: %s", name) } var ff []*ast.File for _, f := range astPkg.Files { ff = append(ff, f) } context := types.Config{ Import: imp.Import, } pkg, err = context.Check(name, fileSet, ff, nil) if err != nil { return pkg, err } if !pkg.Complete() { pkg = types.NewPackage(pkg.Pos(), pkg.Path(), pkg.Name(), pkg.Scope(), pkg.Imports(), true) } imports[path] = pkg imp.Imports[path] = pkg return pkg, nil }