Beispiel #1
0
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
}
Beispiel #2
0
// 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
	}
}
Beispiel #3
0
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
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #6
0
// 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
}
Beispiel #7
0
// 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
}