func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type { _, _, def := a.block.Lookup(x.Name()) if def == nil { a.diagAt(x, "%s: undefined", x.Name()) return nil } switch def := def.(type) { case *Constant: a.diagAt(x, "constant %v used as type", x.Name()) return nil case *Variable: a.diagAt(x, "variable %v used as type", x.Name()) return nil case *NamedType: if !allowRec && def.incomplete { a.diagAt(x, "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.Crashf("name %s has unknown type %T", x.Name(), def) return nil }
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 }
func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label { bc := a.blockCompiler for ; bc != nil; bc = bc.parent { if bc.label == nil { continue } l := bc.label if name == nil && pred(l) { return l } if name != nil && l.name == name.Name() { if !pred(l) { a.diag("cannot %s to %s %s", errOp, l.desc, l.name) return nil } return l } } if name == nil { a.diag("%s outside %s", errOp, errCtx) } else { a.diag("%s label %s not defined", errOp, name.Name()) } return nil }
// 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 }
// DeclLhsPos returns the position of the ident's variable on the left hand // side of the assignment operator with which it was declared. func DeclLhsPos(ident *ast.Ident) (int, error) { var identPos int switch n := ident.Obj.Decl.(type) { case *ast.AssignStmt: // find position of ident on lhs of assignment for i, exp := range n.Lhs { if a, ok := exp.(*ast.Ident); ok && SameIdent(a, ident) { identPos = i break } } case *ast.ValueSpec: // find position of ident on lhs of assignment for i, name := range n.Names { if name.String() == ident.String() { identPos = i break } } default: return 0, errors.New("could not get lhs position of ident: unknown decl type") } return identPos, nil }
func (s *Styler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) { text = strings.Bytes(id.Name()) if s.highlight == id.Name() { tag = printer.HTMLTag{"<span class=highlight>", "</span>"} } return }
func (s *snippetStyler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) { text = []byte(id.Name()) if s.highlight == id { tag = printer.HTMLTag{"<span class=highlight>", "</span>"} } return }
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++ }
// 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) } } }
// SameIdent returns true if a and b are the same. func SameIdent(a, b *ast.Ident) bool { // TODO(waigani) Don't rely on name, it could change and still be the same // ident. if a.String() != b.String() { return false } // TODO(waigani) this happens if ident decl is outside of current // file. We need to use the FileSet to find it. if a.Obj == nil && b.Obj == nil { return true } pa, err := DeclPos(a) if err != nil { // TODO(waigani) log error return false } pb, err := DeclPos(b) if err != nil { // TODO(waigani) log error return false } if pa != pb { return false } return true }
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 }
// 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 }
// 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 }
func (c *compiler) makeFunc(ident *ast.Ident, ftyp *types.Signature) *LLVMValue { fname := ident.String() if ftyp.Recv() == nil && fname == "init" { // Make "init" functions anonymous. fname = "" } else { var pkgname string if recv := ftyp.Recv(); recv != nil { var recvname string switch recvtyp := recv.Type().(type) { case *types.Pointer: if named, ok := recvtyp.Elem().(*types.Named); ok { obj := named.Obj() recvname = "*" + obj.Name() pkgname = obj.Pkg().Path() } case *types.Named: named := recvtyp obj := named.Obj() recvname = obj.Name() pkgname = obj.Pkg().Path() } if recvname != "" { fname = fmt.Sprintf("%s.%s", recvname, fname) } else { // If the receiver is an unnamed struct, we're // synthesising a method for an unnamed struct // type. There's no meaningful name to give the // function, so leave it up to LLVM. fname = "" } } else { obj := c.typeinfo.Objects[ident] pkgname = obj.Pkg().Path() } if fname != "" { fname = pkgname + "." + fname } } // gcimporter may produce multiple AST objects for the same function. llvmftyp := c.types.ToLLVM(ftyp) var fn llvm.Value if fname != "" { fn = c.module.Module.NamedFunction(fname) } if fn.IsNil() { llvmfptrtyp := llvmftyp.StructElementTypes()[0].ElementType() fn = llvm.AddFunction(c.module.Module, fname, llvmfptrtyp) } fn = llvm.ConstInsertValue(llvm.ConstNull(llvmftyp), fn, []uint32{0}) return c.NewValue(fn, ftyp) }
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()} }
// 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 }
// 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 }
func findImportedTypes(name *ast.Ident, withImports []*ast.ImportSpec, dir GoDir) []*ast.TypeSpec { importName := name.String() for _, imp := range withImports { path := strings.Trim(imp.Path.Value, `"`) if pkg, err := dir.Import(path, importName); err == nil { typs, _ := loadPkgTypeSpecs(pkg, dir) addSelector(typs, importName) return typs } } return nil }
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()) } }
func handleUnresolved(unresolved *ast.Ident) gxui.CodeSyntaxLayers { layers := make(gxui.CodeSyntaxLayers, 0, 1) switch unresolved.String() { case "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", "panic", "print", "println", "real", "recover": layers = append(layers, nodeLayer(unresolved, builtinColor)) case "nil": layers = append(layers, nodeLayer(unresolved, nilColor)) } return layers }
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)) } } }
// 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 }
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) } }
func (r *Resolver) resolveIdent(context *resolution.LocatorContext, ident *ast.Ident) (ast.Expr, error) { if r.isBuiltIn(ident.String()) { return ident, nil } discovery, err := r.locator.FindIdentType(context, ident) if err != nil { return nil, err } al := r.model.AddImport("", discovery.Location) return &ast.SelectorExpr{ X: ast.NewIdent(al), Sel: ast.NewIdent(ident.String()), }, nil }
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 }
// Writes a TAGS line to a buffer buffer func (t *buffer) tagLine(leaf *ast.Ident, pkgname, rcvname string) { P := t.fset.Position(leaf.NamePos) n, l := leaf.String(), P.Line s, o := t.lineANDpos(P.Line, n) beforedot := pkgname if rcvname != "" { beforedot = rcvname } if rcvname != "" && *fullTag { fmt.Fprintf(t, "%s\177%s.%s.%s\001%d,%d\n", s, pkgname, rcvname, n, l, o) } else { fmt.Fprintf(t, "%s\177%s.%s\001%d,%d\n", s, beforedot, n, l, o) } }
// 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)) } } }
func (vis *pointerTransformVisitor) makeNewNode(i *ast.Ident, depth int) ast.Expr { d := depth i.NamePos += token.Pos(d) switch { case depth > 0: res := &ast.UnaryExpr{i.NamePos - token.Pos(depth), token.AND, nil} e := res for depth > 1 { e.X = &ast.UnaryExpr{i.NamePos - token.Pos(depth), token.AND, nil} e = e.X.(*ast.UnaryExpr) depth-- } e.X = i return res case depth < 0: res := &ast.StarExpr{i.NamePos - token.Pos(depth), nil} e := res for depth < -1 { e.X = &ast.StarExpr{i.NamePos - token.Pos(depth), nil} e = e.X.(*ast.StarExpr) depth++ } e.X = i return res } return i }
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) } }
// 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 }