Beispiel #1
0
func tokenOf(o types.Object) string {
	switch o := o.(type) {
	case *types.Func:
		return "func"
	case *types.Var:
		return "var"
	case *types.TypeName:
		return "type"
	case *types.Const:
		return "const"
	case *types.PkgName:
		return "package"
	case *types.Builtin:
		return "builtin" // e.g. when describing package "unsafe"
	case *types.Nil:
		return "nil"
	case *types.Label:
		return "label"
	case *types.Alias:
		if o.Orig() == nil {
			return "alias"
		}
		return tokenOf(o.Orig())
	}
	panic(o)
}
Beispiel #2
0
func typesObjectString(obj types.Object) string {
	var prefix string

	switch obj.(type) {
	case *types.Builtin:
		prefix = "builtin"
	case *types.Func:
		prefix = "func"
	case *types.Const:
		prefix = "const"
	case *types.PkgName:
		prefix = "package"
	case *types.Var:
		prefix = "var"
	case *types.Label:
		prefix = "label"
	case *types.Nil:
		return "nil"
	case *types.TypeName:
		prefix = "type"
	default:
		panic(fmt.Sprintf("unexpected type: %T", obj))
	}

	return prefix + " " + obj.Name()
}
Beispiel #3
0
func updateGetDefinitionsContext(ctx *getDefinitionsContext, def *Definition, ident *ast.Ident, obj types.Object) {
	switch obj.(type) {
	case *types.Var:
		//Processing vars later to be sure that all info about structs already filled
		ctx.vars = append(ctx.vars, newObjectWithIdent(obj, ident))
	case *types.Func:
		//Processing funcs later to be sure that all info about interfaces already filled
		ctx.funcs = append(ctx.funcs, newObjectWithIdent(obj, ident))
	case *types.TypeName:
		//If the underlying type is struct, then filling
		//positions of struct's fields (key) and struct name(value)
		//to map. Then we can extract struct name for fields when
		//will be analyze them.
		t := obj.(*types.TypeName)
		underlyingType := t.Type().Underlying()
		switch underlyingType.(type) {
		case *types.Struct:
			s := underlyingType.(*types.Struct)
			for i := 0; i < s.NumFields(); i++ {
				field := s.Field(i)
				ctx.structs[posToStr(ctx.fset, field.Pos())] = obj.Name()
			}
		}
	}

	//Check for interfaces
	underlyingType := obj.Type().Underlying()
	switch underlyingType.(type) {
	case *types.Interface:
		d := new(defWithInterface)
		d.def = def
		d.interfac = underlyingType.(*types.Interface)
		ctx.interfaces = append(ctx.interfaces, d)
	}
}
Beispiel #4
0
// checkSelection checks that all uses and selections that resolve to
// the specified object would continue to do so after the renaming.
func (r *renamer) checkSelections(from types.Object) {
	for pkg, info := range r.packages {
		if id := someUse(info, from); id != nil {
			if !r.checkExport(id, pkg, from) {
				return
			}
		}

		for syntax, sel := range info.Selections {
			// There may be extant selections of only the old
			// name or only the new name, so we must check both.
			// (If neither, the renaming is sound.)
			//
			// In both cases, we wish to compare the lengths
			// of the implicit field path (Selection.Index)
			// to see if the renaming would change it.
			//
			// If a selection that resolves to 'from', when renamed,
			// would yield a path of the same or shorter length,
			// this indicates ambiguity or a changed referent,
			// analogous to same- or sub-block lexical conflict.
			//
			// If a selection using the name 'to' would
			// yield a path of the same or shorter length,
			// this indicates ambiguity or shadowing,
			// analogous to same- or super-block lexical conflict.

			// TODO(adonovan): fix: derive from Types[syntax.X].Mode
			// TODO(adonovan): test with pointer, value, addressable value.
			isAddressable := true

			if sel.Obj() == from {
				if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil {
					// Renaming this existing selection of
					// 'from' may block access to an existing
					// type member named 'to'.
					delta := len(indices) - len(sel.Index())
					if delta > 0 {
						continue // no ambiguity
					}
					r.selectionConflict(from, delta, syntax, obj)
					return
				}

			} else if sel.Obj().Name() == r.to {
				if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from {
					// Renaming 'from' may cause this existing
					// selection of the name 'to' to change
					// its meaning.
					delta := len(indices) - len(sel.Index())
					if delta > 0 {
						continue //  no ambiguity
					}
					r.selectionConflict(from, -delta, syntax, sel.Obj())
					return
				}
			}
		}
	}
}
Beispiel #5
0
// lookup returns the address of the named variable identified by obj
// that is local to function f or one of its enclosing functions.
// If escaping, the reference comes from a potentially escaping pointer
// expression and the referent must be heap-allocated.
//
func (f *Function) lookup(obj types.Object, escaping bool) Value {
	if v, ok := f.objects[obj]; ok {
		if alloc, ok := v.(*Alloc); ok && escaping {
			alloc.Heap = true
		}
		return v // function-local var (address)
	}

	// Definition must be in an enclosing function;
	// plumb it through intervening closures.
	if f.parent == nil {
		panic("no ssa.Value for " + obj.String())
	}
	outer := f.parent.lookup(obj, true) // escaping
	v := &FreeVar{
		name:   obj.Name(),
		typ:    outer.Type(),
		pos:    outer.Pos(),
		outer:  outer,
		parent: f,
	}
	f.objects[obj] = v
	f.FreeVars = append(f.FreeVars, v)
	return v
}
Beispiel #6
0
func isStringer(obj types.Object) bool {
	switch obj := obj.(type) {
	case *types.Func:
		if obj.Name() != "String" {
			return false
		}
		sig, ok := obj.Type().(*types.Signature)
		if !ok {
			return false
		}
		if sig.Recv() == nil {
			return false
		}
		if sig.Params().Len() != 0 {
			return false
		}
		res := sig.Results()
		if res.Len() != 1 {
			return false
		}
		ret := res.At(0).Type()
		if ret != types.Universe.Lookup("string").Type() {
			return false
		}
		return true
	default:
		return false
	}

	return false
}
Beispiel #7
0
func (b *candidateCollector) appendObject(obj types.Object) {
	// TODO(mdempsky): Change this to true.
	const proposeBuiltins = false

	if obj.Pkg() != b.localpkg {
		if obj.Parent() == types.Universe {
			if !proposeBuiltins {
				return
			}
		} else if !obj.Exported() {
			return
		}
	}

	// TODO(mdempsky): Reconsider this functionality.
	if b.filter != nil && !b.filter(obj) {
		return
	}

	if b.filter != nil || strings.HasPrefix(obj.Name(), b.partial) {
		b.exact = append(b.exact, obj)
	} else if strings.HasPrefix(strings.ToLower(obj.Name()), strings.ToLower(b.partial)) {
		b.badcase = append(b.badcase, obj)
	}
}
Beispiel #8
0
// lookup returns the address of the named variable identified by obj
// that is local to function f or one of its enclosing functions.
// If escaping, the reference comes from a potentially escaping pointer
// expression and the referent must be heap-allocated.
//
func (f *Function) lookup(obj types.Object, escaping bool) Value {
	if v, ok := f.objects[obj]; ok {
		if escaping {
			// Walk up the chain of Captures.
			x := v
			for {
				if c, ok := x.(*Capture); ok {
					x = c.Outer
				} else {
					break
				}
			}
			// By construction, all captures are ultimately Allocs in the
			// naive SSA form.  Parameters are pre-spilled to the stack.
			x.(*Alloc).Heap = true
		}
		return v // function-local var (address)
	}

	// Definition must be in an enclosing function;
	// plumb it through intervening closures.
	if f.Enclosing == nil {
		panic("no Value for type.Object " + obj.GetName())
	}
	v := &Capture{f.Enclosing.lookup(obj, true)} // escaping
	f.objects[obj] = v
	f.FreeVars = append(f.FreeVars, v)
	return v
}
Beispiel #9
0
// equalObj reports how x and y differ.  They are assumed to belong to
// different universes so cannot be compared directly.
func equalObj(x, y types.Object) error {
	if reflect.TypeOf(x) != reflect.TypeOf(y) {
		return fmt.Errorf("%T vs %T", x, y)
	}
	xt := x.Type()
	yt := y.Type()
	switch x.(type) {
	case *types.Var, *types.Func:
		// ok
	case *types.Const:
		xval := x.(*types.Const).Val()
		yval := y.(*types.Const).Val()
		// Use string comparison for floating-point values since rounding is permitted.
		if constant.Compare(xval, token.NEQ, yval) &&
			!(xval.Kind() == constant.Float && xval.String() == yval.String()) {
			return fmt.Errorf("unequal constants %s vs %s", xval, yval)
		}
	case *types.TypeName:
		xt = xt.Underlying()
		yt = yt.Underlying()
	default:
		return fmt.Errorf("unexpected %T", x)
	}
	return equalType(xt, yt)
}
Beispiel #10
0
func (p *exporter) obj(obj types.Object) {
	switch obj := obj.(type) {
	case *types.Const:
		p.tag(constTag)
		p.pos(obj)
		p.qualifiedName(obj)
		p.typ(obj.Type())
		p.value(obj.Val())

	case *types.TypeName:
		p.tag(typeTag)
		p.typ(obj.Type())

	case *types.Var:
		p.tag(varTag)
		p.pos(obj)
		p.qualifiedName(obj)
		p.typ(obj.Type())

	case *types.Func:
		p.tag(funcTag)
		p.pos(obj)
		p.qualifiedName(obj)
		sig := obj.Type().(*types.Signature)
		p.paramList(sig.Params(), sig.Variadic())
		p.paramList(sig.Results(), false)

	default:
		log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj)
	}
}
Beispiel #11
0
//getFullName is returning unique name of obj.
func getFullName(obj types.Object, ctx *getDefinitionsContext, isType bool) string {
	if obj == nil {
		return ""
	}
	if isType {
		return obj.Type().String()
	}

	result := ""

	switch obj.(type) {
	case *types.Func:
		f := obj.(*types.Func)
		r := strings.NewReplacer("(", "", "*", "", ")", "")
		result = r.Replace(f.FullName())
	default:
		if obj.Pkg() != nil {
			result += obj.Pkg().Path()
			result += "."
		}

		if packageName, ok := ctx.structs[posToStr(ctx.fset, obj.Pos())]; ok {
			result += packageName
			result += "."
		}
		result += obj.Name()
	}

	return result
}
Beispiel #12
0
func (p *exporter) qualifiedName(obj types.Object) {
	if obj == nil {
		p.string("")
		return
	}
	p.string(obj.Name())
	p.pkg(obj.Pkg(), false)
}
Beispiel #13
0
func (p *exporter) fileLine(obj types.Object) (file string, line int) {
	if p.fset != nil {
		pos := p.fset.Position(obj.Pos())
		file = pos.Filename
		line = pos.Line
	}
	return
}
Beispiel #14
0
// isLocal reports whether obj is local to some function.
// Precondition: not a struct field or interface method.
func isLocal(obj types.Object) bool {
	// [... 5=stmt 4=func 3=file 2=pkg 1=universe]
	var depth int
	for scope := obj.Parent(); scope != nil; scope = scope.Parent() {
		depth++
	}
	return depth >= 4
}
Beispiel #15
0
func (v *visitor) decl(obj types.Object) {
	key := getKey(obj)
	if _, ok := v.uses[key]; !ok {
		v.uses[key] = 0
	}
	if _, ok := v.positions[key]; !ok {
		v.positions[key] = v.prog.Fset.Position(obj.Pos())
	}
}
Beispiel #16
0
// VName returns a VName for obj relative to that of its package.
func (pi *PackageInfo) VName(obj types.Object) *spb.VName {
	sig := pi.Signature(obj)
	base := pi.VNames[obj.Pkg()]
	if base == nil {
		return govname.ForBuiltin(sig)
	}
	vname := proto.Clone(base).(*spb.VName)
	vname.Signature = sig
	return vname
}
Beispiel #17
0
func joinQuery(pkg *types.Package, parent types.Object, obj types.Object, suffix string) string {
	var args []string
	args = append(args, pkg.Name())
	if parent != nil {
		args = append(args, parent.Name())
	}

	args = append(args, nameExported(obj.Name()))
	return strings.Join(args, ".") + suffix
}
Beispiel #18
0
// same reports whether x and y are identical, or both are PkgNames
// that import the same Package.
//
func sameObj(x, y types.Object) bool {
	if x == y {
		return true
	}
	if x, ok := x.(*types.PkgName); ok {
		if y, ok := y.(*types.PkgName); ok {
			return x.Imported() == y.Imported()
		}
	}
	return false
}
Beispiel #19
0
func (p *importer) declare(obj types.Object) {
	pkg := obj.Pkg()
	if alt := pkg.Scope().Insert(obj); alt != nil {
		// This could only trigger if we import a (non-type) object a second time.
		// This should never happen because 1) we only import a package once; and
		// b) we ignore compiler-specific export data which may contain functions
		// whose inlined function bodies refer to other functions that were already
		// imported.
		// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
		// switch case importing functions).
		panic(fmt.Sprintf("%s already declared", alt.Name()))
	}
}
Beispiel #20
0
func newObject(pkg *build.Package, obj types.Object, parent types.Object) *identifier {
	if !obj.Exported() {
		panic("Only exported objects")
	}
	if v, ok := obj.(*types.Var); ok && v.IsField() && parent == nil {
		panic("Expected a non nil parent")
	}
	return &identifier{
		buildPkg: pkg,
		parent:   parent,
		this:     obj,
		usedBy:   make([]token.Position, 0),
	}
}
Beispiel #21
0
func (b *candidateCollector) asCandidate(obj types.Object) Candidate {
	objClass := classifyObject(obj)
	var typ types.Type
	switch objClass {
	case "const", "func", "var":
		typ = obj.Type()
	case "type":
		typ = obj.Type().Underlying()
	}

	var typStr string
	switch t := typ.(type) {
	case *types.Interface:
		typStr = "interface"
	case *types.Struct:
		typStr = "struct"
	default:
		if _, isBuiltin := obj.(*types.Builtin); isBuiltin {
			typStr = builtinTypes[obj.Name()]
		} else if t != nil {
			typStr = types.TypeString(t, b.qualify)
		}
	}

	return Candidate{
		Class: objClass,
		Name:  obj.Name(),
		Type:  typStr,
	}
}
Beispiel #22
0
func (r *renamer) checkInLocalScope(from types.Object) {
	info := r.packages[from.Pkg()]

	// Is this object an implicit local var for a type switch?
	// Each case has its own var, whose position is the decl of y,
	// but Ident in that decl does not appear in the Uses map.
	//
	//   switch y := x.(type) {	 // Defs[Ident(y)] is undefined
	//   case int:    print(y)       // Implicits[CaseClause(int)]    = Var(y_int)
	//   case string: print(y)       // Implicits[CaseClause(string)] = Var(y_string)
	//   }
	//
	var isCaseVar bool
	for syntax, obj := range info.Implicits {
		if _, ok := syntax.(*ast.CaseClause); ok && obj.Pos() == from.Pos() {
			isCaseVar = true
			r.check(obj)
		}
	}

	r.checkInLexicalScope(from, info)

	// Finally, if this was a type switch, change the variable y.
	if isCaseVar {
		_, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
		path[0].(*ast.Ident).Name = r.to // path is [Ident AssignStmt TypeSwitchStmt...]
	}
}
Beispiel #23
0
func createDef(obj types.Object, ident *ast.Ident, ctx *getDefinitionsContext, isType bool) *Definition {
	fullName := getFullName(obj, ctx, isType)

	if def, ok := ctx.defs[fullName]; ok {
		return def
	}

	def := new(Definition)
	def.Name = fullName
	def.Pkg = obj.Pkg()
	def.IsExported = obj.Exported()
	def.TypeOf = reflect.TypeOf(obj)
	def.SimpleName = obj.Name()
	def.Usages = make([]*Usage, 0)
	def.InterfacesDefs = make([]*Definition, 0)

	if ident != nil {
		position := ctx.fset.Position(ident.Pos())
		def.File = position.Filename
		def.Line = position.Line
		def.Offset = position.Offset
		def.Col = position.Column
	}

	if !types.IsInterface(obj.Type()) {
		fillInterfaces(def, obj, ctx)
	}

	ctx.defs[def.Name] = def
	logDefinition(def, obj, ident, ctx)

	return def
}
Beispiel #24
0
func addInterface(obj types.Object, ident *ast.Ident, ctx *getDefinitionsContext) {
	interfac := obj.Type().Underlying().(*types.Interface)

	def := createDef(obj, ident, ctx, true)
	updateGetDefinitionsContext(ctx, def, ident, obj)

	util.Debug("adding interface [%s] [%v] [%v] [%v]", def.Name, def.Pkg, obj.Type().Underlying(), obj.Type())
	//Adding all methods of interface
	for i := 0; i < interfac.NumMethods(); i++ {
		f := interfac.Method(i)
		def := createDef(f, nil, ctx, false)
		util.Debug("\tadding method [%v] [%s]", f, def.Name)
		updateGetDefinitionsContext(ctx, def, ident, f)
	}
}
Beispiel #25
0
func getKey(obj types.Object) object {
	if obj == nil {
		return object{}
	}

	pkg := obj.Pkg()
	pkgPath := ""
	if pkg != nil {
		pkgPath = pkg.Path()
	}

	return object{
		pkgPath: pkgPath,
		name:    obj.Name(),
	}
}
Beispiel #26
0
func (p *exporter) obj(obj types.Object) {
	switch obj := obj.(type) {
	case *types.Const:
		p.tag(constTag)
		p.pos(obj)
		p.qualifiedName(obj)
		p.typ(obj.Type())
		p.value(obj.Val())

	case *types.TypeName:
		p.tag(typeTag)
		p.typ(obj.Type())

	case *types.Var:
		p.tag(varTag)
		p.pos(obj)
		p.qualifiedName(obj)
		p.typ(obj.Type())

	case *types.Func:
		p.tag(funcTag)
		p.pos(obj)
		p.qualifiedName(obj)
		sig := obj.Type().(*types.Signature)
		p.paramList(sig.Params(), sig.Variadic())
		p.paramList(sig.Results(), false)

	// Alias-related code. Keep for now.
	// case *types_Alias:
	// 	// make sure the original is exported before the alias
	// 	// (if the alias declaration was invalid, orig will be nil)
	// 	orig := original(obj)
	// 	if orig != nil && !p.reexported[orig] {
	// 		p.obj(orig)
	// 		p.reexported[orig] = true
	// 	}

	// 	p.tag(aliasTag)
	// 	p.pos(obj)
	// 	p.string(obj.Name())
	// 	p.qualifiedName(orig)

	default:
		log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj)
	}
}
Beispiel #27
0
func (p *importer) declare(obj types.Object) {
	pkg := obj.Pkg()
	if alt := pkg.Scope().Insert(obj); alt != nil {
		// This can only trigger if we import a (non-type) object a second time.
		// Excluding aliases, this cannot happen because 1) we only import a package
		// once; and b) we ignore compiler-specific export data which may contain
		// functions whose inlined function bodies refer to other functions that
		// were already imported.
		// However, aliases require reexporting the original object, so we need
		// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
		// method importer.obj, switch case importing functions).
		// Note that the original itself cannot be an alias.
		if !sameObj(obj, alt) {
			errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
		}
	}
}
Beispiel #28
0
func printTargetObj(obj types.Object) {
	if obj != nil && obj.Pos() != token.NoPos {
		fmt.Println(posPrinter{obj})
		return
	}
	if *godef != "" {
		cmd := exec.Command(*godef, os.Args[1:]...)
		cmd.Stdin = bytes.NewReader(fileBody)
		b, err := cmd.Output()
		if err != nil {
			fail()
		}
		os.Stdout.Write(b)
		return
	}
	fail()
}
Beispiel #29
0
func isParam(ctx Ctx, fn *types.Func, obj types.Object) bool {
	params := getParameters(ctx, fn)
	for _, p := range params {
		if p.v.Id() == obj.Id() {
			return true
		}
	}
	return false
}
Beispiel #30
0
func objectKind(obj types.Object) string {
	switch obj := obj.(type) {
	case *types.PkgName:
		return "imported package name"
	case *types.TypeName:
		return "type"
	case *types.Var:
		if obj.IsField() {
			return "field"
		}
	case *types.Func:
		if obj.Type().(*types.Signature).Recv() != nil {
			return "method"
		}
	}
	// label, func, var, const
	return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
}