Exemplo n.º 1
0
// emitFieldSelection emits to f code to select the index'th field of v.
//
// If wantAddr, the input must be a pointer-to-struct and the result
// will be the field's address; otherwise the result will be the
// field's value.
// Ident id is used for position and debug info.
//
func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value {
	fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)
	if isPointer(v.Type()) {
		instr := &FieldAddr{
			X:     v,
			Field: index,
		}
		instr.setPos(id.Pos())
		instr.setType(types.NewPointer(fld.Type()))
		v = f.emit(instr)
		// Load the field's value iff we don't want its address.
		if !wantAddr {
			v = emitLoad(f, v)
		}
	} else {
		instr := &Field{
			X:     v,
			Field: index,
		}
		instr.setPos(id.Pos())
		instr.setType(fld.Type())
		v = f.emit(instr)
	}
	emitDebugRef(f, id, v, wantAddr)
	return v
}
Exemplo n.º 2
0
func (v *visitor) Visit(node ast.Node) bool {
	descend := true

	var ident *ast.Ident
	var kind string
	switch t := node.(type) {
	case *ast.FuncDecl:
		kind = "func"
		ident = t.Name
		descend = false

	case *ast.TypeSpec:
		kind = "type"
		ident = t.Name
		descend = false
	}

	if ident != nil && strings.Contains(strings.ToLower(ident.Name), v.query) {
		f := v.fset.File(ident.Pos())
		v.syms = append(v.syms, symbol{
			Package: v.pkg.Name,
			Path:    f.Name(),
			Name:    ident.Name,
			Kind:    kind,
			Line:    f.Line(ident.Pos()) - 1,
		})
	}

	return descend
}
Exemplo n.º 3
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
}
Exemplo n.º 4
0
func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
	if id == nil {
		return
	}
	name := x.intern(id.Name)

	switch kind {
	case TypeDecl, FuncDecl, ConstDecl, VarDecl:
		x.curPkgExports[name] = kind
	}

	lists, found := x.words[name]
	if !found {
		lists = new(IndexResult)
		x.words[name] = lists
	}

	if kind == Use || x.decl == nil {
		if x.c.IndexGoCode {
			// not a declaration or no snippet required
			info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
			lists.Others = append(lists.Others, Spot{x.file, info})
		}
	} else {
		// a declaration with snippet
		index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
		info := makeSpotInfo(kind, index, true)
		lists.Decls = append(lists.Decls, Spot{x.file, info})
	}

	x.stats.Spots++
}
Exemplo n.º 5
0
// collectMethods collects the method declarations from an AST File and
// returns a mapping from receiver types to their method FuncDecl's.
func (c *checker) collectMethods(file *ast.File) {
	for _, decl := range file.Decls {
		if funcdecl, ok := decl.(*ast.FuncDecl); ok && funcdecl.Recv != nil {
			recvField := funcdecl.Recv.List[0]
			var recv *ast.Ident
			switch typ := recvField.Type.(type) {
			case *ast.StarExpr:
				recv = typ.X.(*ast.Ident)
			case *ast.Ident:
				recv = typ
			case *ast.BadExpr:
				return
			}

			if recv.Obj == nil {
				// error reported elsewhere.
				return
			}

			if recv.Obj.Kind != ast.Typ {
				c.errorf(recv.Pos(), "%s is not a type", recv.Name)
				return
			}

			// The Obj field of the funcdecl wll be nil, so we'll have to
			// create a new one.
			funcdecl.Name.Obj = ast.NewObj(ast.Fun, funcdecl.Name.String())
			funcdecl.Name.Obj.Decl = funcdecl
			c.methods[recv.Obj] = append(c.methods[recv.Obj], funcdecl.Name.Obj)
		}
	}
}
Exemplo n.º 6
0
// findField returns the object with the given name if visible in the type's scope.
// If no such object is found, an error is reported and a bad object is returned instead.
func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
	// TODO(gri) This is simplistic at the moment and ignores anonymous fields.
	obj = typ.Scope.Lookup(name.Name)
	if obj == nil {
		tc.Errorf(name.Pos(), "%s not declared", name.Name)
		obj = ast.NewObj(ast.Bad, name.Name)
	}
	return
}
Exemplo n.º 7
0
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
// It returns the newly allocated object. If an object with the same name already exists in scope, an error
// is reported and the object is not inserted.
// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
	obj := ast.NewObj(kind, name.Name)
	obj.Decl = decl
	obj.N = n
	name.Obj = obj
	if alt := scope.Insert(obj); alt != obj {
		tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
	}
	return obj
}
Exemplo n.º 8
0
// find returns the object with the given name if visible in the current scope hierarchy.
// If no such object is found, an error is reported and a bad object is returned instead.
func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
	for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
		obj = s.Lookup(name.Name)
	}
	if obj == nil {
		tc.Errorf(name.Pos(), "%s not declared", name.Name)
		obj = ast.NewObj(ast.Bad, name.Name)
	}
	name.Obj = obj
	return
}
Exemplo n.º 9
0
func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
	// TODO instead of pretty-printing the node, should use the original source instead
	var buf1 bytes.Buffer
	writeNode(&buf1, fset, decl)
	// wrap text with <pre> tag
	var buf2 bytes.Buffer
	buf2.WriteString("<pre>")
	FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
	buf2.WriteString("</pre>")
	return &Snippet{fset.Position(id.Pos()).Line, buf2.String()}
}
Exemplo n.º 10
0
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
// It returns the newly allocated object. If an object with the same name already exists in scope, an error
// is reported and the object is not inserted.
func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
	obj := ast.NewObj(kind, name.Name)
	obj.Decl = decl
	//obj.N = n
	name.Obj = obj
	if name.Name != "_" {
		if alt := scope.Insert(obj); alt != nil {
			tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
		}
	}
	return obj
}
Exemplo n.º 11
0
func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) {
	decl := scope.Declare(id.Obj)
	if p.checkDecl && decl != id.Obj {
		if decl.Kind == ast.Err {
			// declared object is a forward declaration - update it
			*decl = *id.Obj
			id.Obj = decl
			return
		}
		p.Error(id.Pos(), "'"+id.Name()+"' declared already at "+decl.Pos.String())
	}
}
Exemplo n.º 12
0
func (check *checker) declareIdent(scope *Scope, ident *ast.Ident, obj Object) {
	assert(check.lookup(ident) == nil) // identifier already declared or resolved
	check.register(ident, obj)
	if ident.Name != "_" {
		if alt := scope.Insert(obj); alt != nil {
			prevDecl := ""
			if pos := alt.GetPos(); pos.IsValid() {
				prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos))
			}
			check.errorf(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
		}
	}
}
Exemplo n.º 13
0
// declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
// and updates check.objMap. The object must not be a function or method.
func (check *checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
	assert(ident.Name == obj.Name())

	// spec: "A package-scope or file-scope identifier with name init
	// may only be declared to be a function with this (func()) signature."
	if ident.Name == "init" {
		check.errorf(ident.Pos(), "cannot declare init - must be func")
		return
	}

	check.declare(check.pkg.scope, ident, obj)
	check.objMap[obj] = d
}
Exemplo n.º 14
0
func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool {
	// Reject cross-package references if r.to is unexported.
	// (Such references may be qualified identifiers or field/method
	// selections.)
	if !ast.IsExported(r.to) && pkg != from.Pkg() {
		r.errorf(from.Pos(),
			"renaming this %s %q to %q would make it unexported",
			objectKind(from), from.Name(), r.to)
		r.errorf(id.Pos(), "\tbreaking references from packages such as %q",
			pkg.Path())
		return false
	}
	return true
}
Exemplo n.º 15
0
func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
	_, _, def := a.block.Lookup(x.Name)
	if def == nil {
		a.diagAt(x.Pos(), "%s: undefined", x.Name)
		return nil
	}
	switch def := def.(type) {
	case *Constant:
		a.diagAt(x.Pos(), "constant %v used as type", x.Name)
		return nil
	case *Variable:
		a.diagAt(x.Pos(), "variable %v used as type", x.Name)
		return nil
	case *NamedType:
		if !allowRec && def.incomplete {
			a.diagAt(x.Pos(), "illegal recursive type")
			return nil
		}
		if !def.incomplete && def.Def == nil {
			// Placeholder type from an earlier error
			return nil
		}
		return def
	case Type:
		return def
	}
	log.Panicf("name %s has unknown type %T", x.Name, def)
	return nil
}
Exemplo n.º 16
0
func saveRecent(ident *ast.Ident, obj types.Object) {
	if *cacheFile == "" {
		return
	}
	if obj == nil || obj.Pos() == token.NoPos {
		return
	}

	if fset.Position(ident.Pos()).Filename == fset.Position(obj.Pos()).Filename {
		lg("same file")
		return
	}

	k := posPrinter{ident}.String()

	sha := fileSHA(fset.Position(obj.Pos()).Filename)
	if sha == "" {
		return
	}

	now := time.Now()
	ent := &objectEntry{
		FromSHA1: fileSHA1,
		ToPos:    posPrinter{obj}.String(),
		ToSHA1:   sha,
		Created:  now.UnixNano(),
	}
	lg("new recent entry %s => %+v", k, ent)

	if recents == nil {
		recents = &recentObjects{entries: make(map[string]*objectEntry)}
	}
	recents.entries[k] = ent

	expire := now.Add(-24 * time.Hour).UnixNano()
	for k, ent := range recents.entries {
		if ent.bad || ent.Created < expire {
			delete(recents.entries, k)
		}
	}

	b, err := json.MarshalIndent(recents.entries, "", "  ")
	if err != nil {
		lg("marshal recents err=%v", err)
		return
	}
	if err = ioutil.WriteFile(*cacheFile, b, 0600); err != nil {
		lg("write recents err=%v", err)
	}
}
Exemplo n.º 17
0
// declare declares an object of the given kind and name (ident) in scope;
// decl is the corresponding declaration in the AST. An error is reported
// if the object was declared before.
//
// TODO(gri) This is very similar to the declare function in go/parser; it
// is only used to associate methods with their respective receiver base types.
// In a future version, it might be simpler and cleaner to do all the resolution
// in the type-checking phase. It would simplify the parser, AST, and also
// reduce some amount of code duplication.
//
func (check *checker) declare(scope *ast.Scope, kind ast.ObjKind, ident *ast.Ident, decl ast.Decl) {
	assert(ident.Obj == nil) // identifier already declared or resolved
	obj := ast.NewObj(kind, ident.Name)
	obj.Decl = decl
	ident.Obj = obj
	if ident.Name != "_" {
		if alt := scope.Insert(obj); alt != nil {
			prevDecl := ""
			if pos := alt.Pos(); pos.IsValid() {
				prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos))
			}
			check.errorf(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
		}
	}
}
Exemplo n.º 18
0
func (f *file) checkPkgName(pkg *ast.Ident) {
	//ref "http://golang.org/doc/effective_go.html#package-names"
	pkgName := pkg.Name
	var desc string
	if strings.Contains(pkgName, "_") {
		suggestName := strings.Replace(pkgName, "_", "/", -1)
		desc = "don't use an underscore in package name, " + pkgName + " should be " + suggestName
	} else if strings.ToLower(pkgName) != pkgName {
		desc = "don't use capital letters in package name: " + pkgName
	}
	if desc != "" {
		start := f.fset.Position(pkg.Pos())
		problem := Problem{Description: desc, Position: &start, Type: PackageName}
		f.problems = append(f.problems, problem)
	}
}
Exemplo n.º 19
0
// NewSnippet creates a text snippet from a declaration decl containing an
// identifier id. Parts of the declaration not containing the identifier
// may be removed for a more compact snippet.
//
func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet) {
	switch d := decl.(type) {
	case *ast.GenDecl:
		s = genSnippet(fset, d, id)
	case *ast.FuncDecl:
		s = funcSnippet(fset, d, id)
	}

	// handle failure gracefully
	if s == nil {
		var buf bytes.Buffer
		fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name)
		s = &Snippet{fset.Position(id.Pos()).Line, buf.String()}
	}
	return
}
Exemplo n.º 20
0
// NewSnippet creates a text snippet from a declaration decl containing an
// identifier id. Parts of the declaration not containing the identifier
// may be removed for a more compact snippet.
//
func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) {
	switch d := decl.(type) {
	case *ast.GenDecl:
		s = genSnippet(d, id)
	case *ast.FuncDecl:
		s = funcSnippet(d, id)
	}

	// handle failure gracefully
	if s == nil {
		s = &Snippet{
			id.Pos().Line,
			fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Name()),
		}
	}
	return
}
Exemplo n.º 21
0
// scopeOf returns the tightest scope encompassing id.
func (p *pkg) scopeOf(id *ast.Ident) *types.Scope {
	var scope *types.Scope
	if obj := p.typesInfo.ObjectOf(id); obj != nil {
		scope = obj.Parent()
	}
	if scope == p.typesPkg.Scope() {
		// We were given a top-level identifier.
		// Use the file-level scope instead of the package-level scope.
		pos := id.Pos()
		for _, f := range p.files {
			if f.f.Pos() <= pos && pos < f.f.End() {
				scope = p.typesInfo.Scopes[f.f]
				break
			}
		}
	}
	return scope
}
Exemplo n.º 22
0
func (f *File) checkCanonicalMethod(id *ast.Ident, t *ast.FuncType) {
	if !*vetMethods && !*vetAll {
		return
	}
	// Expected input/output.
	expect, ok := canonicalMethods[id.Name]
	if !ok {
		return
	}

	// Actual input/output
	args := typeFlatten(t.Params.List)
	var results []ast.Expr
	if t.Results != nil {
		results = typeFlatten(t.Results.List)
	}

	// Do the =s (if any) all match?
	if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
		return
	}

	// Everything must match.
	if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
		expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
		if len(expect.results) == 1 {
			expectFmt += " " + argjoin(expect.results)
		} else if len(expect.results) > 1 {
			expectFmt += " (" + argjoin(expect.results) + ")"
		}

		f.b.Reset()
		if err := printer.Fprint(&f.b, f.fset, t); err != nil {
			fmt.Fprintf(&f.b, "<%s>", err)
		}
		actual := f.b.String()
		if strings.HasPrefix(actual, "func(") {
			actual = actual[4:]
		}
		actual = id.Name + actual

		f.Warnf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
	}
}
Exemplo n.º 23
0
// growSpan expands the span for the object to contain the instance represented
// by the identifier.
func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) {
	if *strictShadowing {
		return // No need
	}
	pos := ident.Pos()
	end := ident.End()
	span, ok := pkg.spans[obj]
	if ok {
		if span.min > pos {
			span.min = pos
		}
		if span.max < end {
			span.max = end
		}
	} else {
		span = Span{pos, end}
	}
	pkg.spans[obj] = span
}
Exemplo n.º 24
0
func (r *resolver) define(b *Block, id *ast.Ident) {
	obj := r.info.Defs[id]
	if obj == nil {
		logf("%s: internal error: not a defining ident: %s\n",
			r.fset.Position(id.Pos()), id.Name)
		panic(id)
	}
	r.defineObject(b, id.Name, obj)

	// Objects (other than PkgName) defined at file scope
	// are also defined in the enclosing package scope.
	if _, ok := b.syntax.(*ast.File); ok {
		switch obj.(type) {
		default:
			r.defineObject(b.parent.block, id.Name, obj)
		case nil, *types.PkgName:
		}
	}
}
Exemplo n.º 25
0
func (r *resolver) use(id *ast.Ident, env Environment) {
	if id.Name == "_" {
		return // an error
	}
	obj, _ := env.Lookup(id.Name)
	if obj == nil {
		logf("%s: lookup of %s failed\n", r.fset.Position(id.Pos()), id.Name)
	} else if want := r.info.Uses[id]; obj != want {
		// sanity check against go/types resolver
		logf("%s: internal error: lookup of %s yielded wrong object: got %v (%s), want %v\n",
			r.fset.Position(id.Pos()), id.Name, types.ObjectString(obj, r.qualifier),
			r.fset.Position(obj.Pos()),
			want)
	}
	if trace {
		logf("use %s = %v in %s\n", id.Name, types.ObjectString(obj, r.qualifier), env)
	}

	r.result.Refs[obj] = append(r.result.Refs[obj], Reference{id, env})
}
Exemplo n.º 26
0
func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
	v, prev := a.block.DefineVar(ident.Name(), ident.Pos(), t)
	if prev != nil {
		// TODO(austin) It's silly that we have to capture
		// Pos() in a variable.
		pos := prev.Pos()
		if pos.IsValid() {
			a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name(), &pos)
		} else {
			a.diagAt(ident, "variable %s redeclared in this block", ident.Name())
		}
		return nil
	}

	// Initialize the variable
	index := v.Index
	if v.Index >= 0 {
		a.push(func(v *Thread) { v.f.Vars[index] = t.Zero() })
	}
	return v
}
Exemplo n.º 27
0
func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
	if id != nil {
		lists, found := x.words[id.Value]
		if !found {
			lists = new(IndexResult)
			x.words[id.Value] = lists
		}

		if kind == Use || x.decl == nil {
			// not a declaration or no snippet required
			info := makeSpotInfo(kind, id.Pos().Line, false)
			lists.Others.Push(Spot{x.file, info})
		} else {
			// a declaration with snippet
			index := x.addSnippet(NewSnippet(x.decl, id))
			info := makeSpotInfo(kind, index, true)
			lists.Decls.Push(Spot{x.file, info})
		}

		x.nspots++
	}
}
Exemplo n.º 28
0
func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
	if id != nil {
		lists, found := x.words[id.Name]
		if !found {
			lists = new(IndexResult)
			x.words[id.Name] = lists
		}

		if kind == Use || x.decl == nil {
			// not a declaration or no snippet required
			info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
			lists.Others = append(lists.Others, Spot{x.file, info})
		} else {
			// a declaration with snippet
			index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
			info := makeSpotInfo(kind, index, true)
			lists.Decls = append(lists.Decls, Spot{x.file, info})
		}

		x.stats.Spots++
	}
}
Exemplo n.º 29
0
func (d *mDeclarations) decl(fset *token.FileSet, id *ast.Ident, name, kind string) *mDeclarationsDecl {
	if name == "" {
		name = id.Name
	}

	if name == "_" {
		return nil
	}

	tp := fset.Position(id.Pos())
	if !tp.IsValid() {
		return nil
	}

	return &mDeclarationsDecl{
		Name: name,
		Kind: d.kind(id, kind),
		Fn:   tp.Filename,
		Row:  tp.Line - 1,
		Col:  tp.Column - 1,
	}
}
Exemplo n.º 30
0
func isValidObject(obj types.Object, ident *ast.Ident, ctx *getDefinitionsContext) bool {
	if obj == nil {
		return false
	}
	position := ctx.fset.Position(ident.Pos())
	typeOf := reflect.TypeOf(obj)
	fullName := getFullName(obj, ctx, false)
	if !position.IsValid() {
		util.Warn("position object is invalid for %s", ident.Name)
		return false
	}
	if len(fullName) == 0 {
		util.Warn("warning: cann't get full name for %s: %v", ident.Name, typeOf)
		return false
	}
	if typeOf == nil {
		return false
	}
	if ctx.defs[fullName] != nil {
		return false
	}
	return true
}