예제 #1
0
파일: describe.go 프로젝트: 4honor/obdi
func describePackage(o *Oracle, qpos *QueryPos, path []ast.Node) (*describePackageResult, error) {
	var description string
	var pkg *types.Package
	switch n := path[0].(type) {
	case *ast.ImportSpec:
		var pkgname *types.PkgName
		if n.Name != nil {
			pkgname = qpos.info.Defs[n.Name].(*types.PkgName)
		} else if p := qpos.info.Implicits[n]; p != nil {
			pkgname = p.(*types.PkgName)
		}
		description = fmt.Sprintf("import of package %q", pkgname.Pkg().Path())
		pkg = pkgname.Pkg()

	case *ast.Ident:
		if _, isDef := path[1].(*ast.File); isDef {
			// e.g. package id
			pkg = qpos.info.Pkg
			description = fmt.Sprintf("definition of package %q", pkg.Path())
		} else {
			// e.g. import id "..."
			//  or  id.F()
			pkg = qpos.info.ObjectOf(n).Pkg()
			description = fmt.Sprintf("reference to package %q", pkg.Path())
		}

	default:
		// Unreachable?
		return nil, fmt.Errorf("unexpected AST for package: %T", n)
	}

	var members []*describeMember
	// NB: "unsafe" has no types.Package
	if pkg != nil {
		// Enumerate the accessible package members
		// in lexicographic order.
		for _, name := range pkg.Scope().Names() {
			if pkg == qpos.info.Pkg || ast.IsExported(name) {
				mem := pkg.Scope().Lookup(name)
				var methods []*types.Selection
				if mem, ok := mem.(*types.TypeName); ok {
					methods = accessibleMethods(mem.Type(), qpos.info.Pkg)
				}
				members = append(members, &describeMember{
					mem,
					methods,
				})

			}
		}
	}

	return &describePackageResult{o.fset, path[0], description, pkg, members}, nil
}
예제 #2
0
// checkInFileBlock performs safety checks for renames of objects in the file block,
// i.e. imported package names.
func (r *renamer) checkInFileBlock(from *types.PkgName) {
	// Check import name is not "init".
	if r.to == "init" {
		r.errorf(from.Pos(), "%q is not a valid imported package name", r.to)
	}

	// Check for conflicts between file and package block.
	if prev := from.Pkg().Scope().Lookup(r.to); prev != nil {
		r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
			objectKind(from), from.Name(), r.to)
		r.errorf(prev.Pos(), "\twith this package member %s",
			objectKind(prev))
		return // since checkInPackageBlock would report redundant errors
	}

	// Check for conflicts in lexical scope.
	r.checkInLexicalScope(from, r.packages[from.Pkg()])

	// Finally, modify ImportSpec syntax to add or remove the Name as needed.
	info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
	if from.Imported().Name() == r.to {
		// ImportSpec.Name not needed
		path[1].(*ast.ImportSpec).Name = nil
	} else {
		// ImportSpec.Name needed
		if spec := path[1].(*ast.ImportSpec); spec.Name == nil {
			spec.Name = &ast.Ident{NamePos: spec.Path.Pos(), Name: r.to}
			info.Defs[spec.Name] = from
		}
	}
}