Example #1
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)
	}
}
Example #2
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
}
Example #3
0
// classify classifies objects by how far
// we have to look to find references to them.
func classify(obj types.Object) (global, pkglevel bool) {
	if obj.Exported() {
		if obj.Parent() == nil {
			// selectable object (field or method)
			return true, false
		}
		if obj.Parent() == obj.Pkg().Scope() {
			// lexical object (package-level var/const/func/type)
			return true, true
		}
	}
	// object with unexported named or defined in local scope
	return false, false
}
Example #4
0
// newSignature constructs and returns a tag and base signature for obj.  The
// tag represents the "kind" of signature, to disambiguate built-in types from
// user-defined names, fields from methods, and so on.  The base is a unique
// name for obj within its package, modulo the tag.
func (pi *PackageInfo) newSignature(obj types.Object) (tag, base string) {
	if obj.Name() == "" {
		return tagVar, "_"
	}
	topLevelTag := tagVar
	switch t := obj.(type) {
	case *types.Builtin:
		return isBuiltin + tagFunc, t.Name()

	case *types.Nil:
		return isBuiltin + tagConst, "nil"

	case *types.PkgName:
		return "", ":pkg:" // the vname corpus and path carry the package name

	case *types.Const:
		topLevelTag = tagConst
		if t.Pkg() == nil {
			return isBuiltin + tagConst, t.Name()
		}

	case *types.Var:
		if t.IsField() {
			if owner, ok := pi.owner[t]; ok {
				_, base := pi.newSignature(owner)
				return tagField, base + "." + t.Name()
			}
			return tagField, fmt.Sprintf("[%p].%s", t, t.Name())
		} else if owner, ok := pi.owner[t]; ok {
			_, base := pi.newSignature(owner)
			return tagParam, base + ":" + t.Name()
		}

	case *types.Func:
		topLevelTag = tagFunc
		if recv := t.Type().(*types.Signature).Recv(); recv != nil { // method
			if owner, ok := pi.owner[t]; ok {
				_, base := pi.newSignature(owner)
				return tagMethod, base + "." + t.Name()
			}
			return tagMethod, fmt.Sprintf("(%s).%s", recv.Type(), t.Name())
		}

	case *types.TypeName:
		topLevelTag = tagType
		if t.Pkg() == nil {
			return isBuiltin + tagType, t.Name()
		}

	case *types.Label:
		return tagLabel, fmt.Sprintf("[%p].%s", t, t.Name())

	default:
		log.Panicf("Unexpected object kind: %T", obj)
	}

	// At this point, we have eliminated built-in objects; everything else must
	// be defined in a package.
	if obj.Pkg() == nil {
		log.Panic("Object without a package: ", obj)
	}

	// Objects at package scope (i.e., parent scope is package scope).
	if obj.Parent() == obj.Pkg().Scope() {
		return topLevelTag, obj.Name()
	}

	// Objects in interior (local) scopes, i.e., everything else.
	return topLevelTag, fmt.Sprintf("[%p].%s", obj, obj.Name())
}
Example #5
0
func isPkgLevel(o types.Object) bool {
	return o.Parent() != nil && o.Parent().Parent() == types.Universe
}
Example #6
0
// checkInLexicalScope performs safety checks that a renaming does not
// change the lexical reference structure of the specified package.
//
// For objects in lexical scope, there are three kinds of conflicts:
// same-, sub-, and super-block conflicts.  We will illustrate all three
// using this example:
//
//	var x int
//	var z int
//
//	func f(y int) {
//		print(x)
//		print(y)
//	}
//
// Renaming x to z encounters a SAME-BLOCK CONFLICT, because an object
// with the new name already exists, defined in the same lexical block
// as the old object.
//
// Renaming x to y encounters a SUB-BLOCK CONFLICT, because there exists
// a reference to x from within (what would become) a hole in its scope.
// The definition of y in an (inner) sub-block would cast a shadow in
// the scope of the renamed variable.
//
// Renaming y to x encounters a SUPER-BLOCK CONFLICT.  This is the
// converse situation: there is an existing definition of the new name
// (x) in an (enclosing) super-block, and the renaming would create a
// hole in its scope, within which there exist references to it.  The
// new name casts a shadow in scope of the existing definition of x in
// the super-block.
//
// Removing the old name (and all references to it) is always safe, and
// requires no checks.
//
func (r *renamer) checkInLexicalScope(from types.Object, info *loader.PackageInfo) {
	b := from.Parent() // the block defining the 'from' object
	if b != nil {
		toBlock, to := b.LookupParent(r.to, from.Parent().End())
		if toBlock == b {
			// same-block conflict
			r.errorf(from.Pos(), "renaming this %s %q to %q",
				objectKind(from), from.Name(), r.to)
			r.errorf(to.Pos(), "\tconflicts with %s in same block",
				objectKind(to))
			return
		} else if toBlock != nil {
			// Check for super-block conflict.
			// The name r.to is defined in a superblock.
			// Is that name referenced from within this block?
			forEachLexicalRef(info, to, func(id *ast.Ident, block *types.Scope) bool {
				_, obj := lexicalLookup(block, from.Name(), id.Pos())
				if obj == from {
					// super-block conflict
					r.errorf(from.Pos(), "renaming this %s %q to %q",
						objectKind(from), from.Name(), r.to)
					r.errorf(id.Pos(), "\twould shadow this reference")
					r.errorf(to.Pos(), "\tto the %s declared here",
						objectKind(to))
					return false // stop
				}
				return true
			})
		}
	}

	// Check for sub-block conflict.
	// Is there an intervening definition of r.to between
	// the block defining 'from' and some reference to it?
	forEachLexicalRef(info, from, func(id *ast.Ident, block *types.Scope) bool {
		// Find the block that defines the found reference.
		// It may be an ancestor.
		fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos())

		// See what r.to would resolve to in the same scope.
		toBlock, to := lexicalLookup(block, r.to, id.Pos())
		if to != nil {
			// sub-block conflict
			if deeper(toBlock, fromBlock) {
				r.errorf(from.Pos(), "renaming this %s %q to %q",
					objectKind(from), from.Name(), r.to)
				r.errorf(id.Pos(), "\twould cause this reference to become shadowed")
				r.errorf(to.Pos(), "\tby this intervening %s definition",
					objectKind(to))
				return false // stop
			}
		}
		return true
	})

	// Renaming a type that is used as an embedded field
	// requires renaming the field too. e.g.
	// 	type T int // if we rename this to U..
	// 	var s struct {T}
	// 	print(s.T) // ...this must change too
	if _, ok := from.(*types.TypeName); ok {
		for id, obj := range info.Uses {
			if obj == from {
				if field := info.Defs[id]; field != nil {
					r.check(field)
				}
			}
		}
	}
}
Example #7
0
// getDoc returns the doc string associated with types.Object
// parent is the name of the containing scope ("" for global scope)
func (p *Package) getDoc(parent string, o types.Object) string {
	n := o.Name()
	switch o.(type) {
	case *types.Const:
		for _, c := range p.doc.Consts {
			for _, cn := range c.Names {
				if n == cn {
					return c.Doc
				}
			}
		}

	case *types.Var:
		for _, v := range p.doc.Vars {
			for _, vn := range v.Names {
				if n == vn {
					return v.Doc
				}
			}
		}

	case *types.Func:
		doc := func() string {
			if o.Parent() == nil || (o.Parent() != nil && parent != "") {
				for _, typ := range p.doc.Types {
					if typ.Name != parent {
						continue
					}
					if o.Parent() == nil {
						for _, m := range typ.Methods {
							if m.Name == n {
								return m.Doc
							}
						}
					} else {
						for _, m := range typ.Funcs {
							if m.Name == n {
								return m.Doc
							}
						}
					}
				}
			} else {
				for _, f := range p.doc.Funcs {
					if n == f.Name {
						return f.Doc
					}
				}
			}
			return ""
		}()

		sig := o.Type().(*types.Signature)

		parseFn := func(tup *types.Tuple) []string {
			params := []string{}
			if tup == nil {
				return params
			}
			for i := 0; i < tup.Len(); i++ {
				paramVar := tup.At(i)
				paramType := p.syms.symtype(paramVar.Type()).pysig
				if paramVar.Name() != "" {
					paramType = fmt.Sprintf("%s %s", paramType, paramVar.Name())
				}
				params = append(params, paramType)
			}
			return params
		}

		params := parseFn(sig.Params())
		results := parseFn(sig.Results())

		paramString := strings.Join(params, ", ")
		resultString := strings.Join(results, ", ")

		//FIXME(sbinet): add receiver for methods?
		docSig := fmt.Sprintf("%s(%s) %s", o.Name(), paramString, resultString)

		if doc != "" {
			doc = fmt.Sprintf("%s\n\n%s", docSig, doc)
		} else {
			doc = docSig
		}
		return doc

	case *types.TypeName:
		for _, t := range p.doc.Types {
			if n == t.Name {
				return t.Doc
			}
		}

	default:
		// TODO(sbinet)
		panic(fmt.Errorf("not yet supported: %v (%T)", o, o))
	}

	return ""
}