// normalizeNodePos resets all position information of node and its descendants. func normalizeNodePos(node ast.Node) { ast.Inspect(node, func(node ast.Node) bool { if node == nil { return true } if node.Pos() == token.NoPos && node.End() == token.NoPos { return true } pv := reflect.ValueOf(node) if pv.Kind() != reflect.Ptr { return true } v := pv.Elem() if v.Kind() != reflect.Struct { return true } for i := 0; i < v.NumField(); i++ { f := v.Field(i) ft := f.Type() if f.CanSet() && ft.PkgPath() == "go/token" && ft.Name() == "Pos" && f.Int() != 0 { f.SetInt(1) } } return true }) }
func NewIssue(ctx *Context, node ast.Node, desc string, severity Score, confidence Score) *Issue { var code string fobj := ctx.FileSet.File(node.Pos()) name := fobj.Name() line := fobj.Line(node.Pos()) if file, err := os.Open(fobj.Name()); err == nil { defer file.Close() s := (int64)(fobj.Position(node.Pos()).Offset) // Go bug, should be int64 e := (int64)(fobj.Position(node.End()).Offset) // Go bug, should be int64 code, err = codeSnippet(file, s, e, node) if err != nil { code = err.Error() } } return &Issue{ File: name, Line: line, What: desc, Confidence: confidence, Severity: severity, Code: code, } }
func getSourceString(node ast.Node, fset *token.FileSet) string { p1 := fset.Position(node.Pos()) p2 := fset.Position(node.End()) b := getFileBytes(p1.Filename) return string(b[p1.Offset:p2.Offset]) }
func (v *funcVisitor) Visit(n ast.Node) ast.Visitor { switch n := n.(type) { case *ast.FuncDecl: // Function name is prepended with "T." if there is a receiver, where // T is the type of the receiver, dereferenced if it is a pointer. name := n.Name.Name if n.Recv != nil { field := n.Recv.List[0] switch recv := field.Type.(type) { case *ast.StarExpr: name = recv.X.(*ast.Ident).Name + "." + name case *ast.Ident: name = recv.Name + "." + name } } start, end := v.fset.Position(n.Pos()), v.fset.Position(n.End()) f := v.pkg.RegisterFunction(name, start.Filename, start.Offset, end.Offset) v.state.functions = append(v.state.functions, f) sv := &stmtVisitor{v.state} if n.Body != nil { sv.VisitStmt(n.Body) } // TODO function coverage (insert "function.Enter", "function.Leave"). // TODO come up with naming scheme for function literals. // case *ast.FuncLit: } return v }
func (this DepthWalker) Visit(node ast.Node) ast.Visitor { if node == nil { return this + 1 } buffer := "" for i := 0; i < int(this); i++ { buffer += " " } fmt.Printf("%sPos: %d %s\n", buffer, node.Pos(), AllSources.Position(node.Pos())) fmt.Printf("%sEnd: %d %s\n", buffer, node.End(), AllSources.Position(node.End())) fmt.Printf("%s%T\n", buffer, node) fmt.Printf("%s%v\n", buffer, node) if e, ok := node.(ast.Expr); ok { obj, typ := types.ExprType(e, LocalImporter) fmt.Printf("%s%v\n", buffer, obj) fmt.Printf("%s%v\n", buffer, typ) } fmt.Println() switch n := node.(type) { } return this + 1 }
func (visitor *astNodeVisitorForMultipleStatements) Visit(node ast.Node) (w ast.Visitor) { if node != nil { if visitor.context.fset.Position(node.Pos()).Line == visitor.context.selection.Begin.Line && visitor.context.fset.Position(node.Pos()).Column == visitor.context.selection.Begin.Column && !visitor.context.shouldRecord { // fmt.Println("Starting with node at pos", visitor.context.fset.Position(node.Pos()), "and end", visitor.context.fset.Position(node.End())) // ast.Print(visitor.context.fset, node) // fmt.Println(node.Pos(), node) // fmt.Println("Parent") // ast.Print(visitor.context.fset, visitor.parentNode) visitor.context.posParent = visitor.parentNode visitor.context.shouldRecord = true } if visitor.context.shouldRecord && visitor.context.posParent == visitor.parentNode { visitor.context.nodesToExtract = append(visitor.context.nodesToExtract, node) } if visitor.context.fset.Position(node.End()).Line == visitor.context.selection.End.Line && visitor.context.fset.Position(node.End()).Column == visitor.context.selection.End.Column { // fmt.Println("Ending with node at pos", visitor.context.fset.Position(node.Pos()), "and end", visitor.context.fset.Position(node.End())) // ast.Print(visitor.context.fset, node) // fmt.Println("Parent") // ast.Print(visitor.context.fset, visitor.parentNode) visitor.context.endParent = visitor.parentNode visitor.context.shouldRecord = false return nil } } return &astNodeVisitorForMultipleStatements{ parentNode: node, context: visitor.context, } }
func posLink_urlFunc(node ast.Node, fset *token.FileSet) string { var relpath string var line int var low, high int // selection if p := node.Pos(); p.IsValid() { pos := fset.Position(p) relpath = pos.Filename line = pos.Line low = pos.Offset } if p := node.End(); p.IsValid() { high = fset.Position(p).Offset } var buf bytes.Buffer template.HTMLEscape(&buf, []byte(relpath)) // selection ranges are of form "s=low:high" if low < high { fmt.Fprintf(&buf, "?s=%d:%d", low, high) // no need for URL escaping // if we have a selection, position the page // such that the selection is a bit below the top line -= 10 if line < 1 { line = 1 } } // line id's in html-printed source are of the // form "L%d" where %d stands for the line number if line > 0 { fmt.Fprintf(&buf, "#L%d", line) // no need for URL escaping } return buf.String() }
func (f *gofile) newIssueRangeFromNode(n ast.Node) *issueRange { s := f.Fset().Position(n.Pos()) e := f.Fset().Position(n.End()) return &issueRange{ s, e, } }
func (v *annotationVisitor) addAnnoation(n ast.Node, packageName string, name string) { pos := v.fset.Position(n.Pos()) end := v.fset.Position(n.End()) v.annotations = append(v.annotations, TypeAnnotation{ pos.Offset - len(packageWrapper), end.Offset - len(packageWrapper), packageName, name}) }
func (v *funcVisitor) Visit(n ast.Node) ast.Visitor { var body *ast.BlockStmt switch n := n.(type) { case *ast.FuncDecl: // Function name is prepended with "T." if there is a receiver, where // T is the type of the receiver, dereferenced if it is a pointer. name := n.Name.Name if n.Recv != nil { field := n.Recv.List[0] switch recv := field.Type.(type) { case *ast.StarExpr: name = recv.X.(*ast.Ident).Name + "." + name case *ast.Ident: name = recv.Name + "." + name } } start, end := v.fset.Position(n.Pos()), v.fset.Position(n.End()) f := v.pkg.RegisterFunction(name, start.Filename, start.Offset, end.Offset) v.state.functions = append(v.state.functions, f) body = n.Body case *ast.FuncLit: // Function literals defined within a function do not get a separate // *gocov.Function, rather their statements are counted in the // enclosing function. // // Function literals at the package scope are named "@<Position>", // where "<Position>" is the position of the beginning of the function // literal. start, end := v.fset.Position(n.Pos()), v.fset.Position(n.End()) var enclosing *gocov.Function if len(v.functions) > 0 { lastfunc := v.functions[len(v.functions)-1] if start.Offset < lastfunc.End { enclosing = lastfunc } } if enclosing == nil { name := fmt.Sprintf("@%d:%d", start.Line, start.Column) f := v.pkg.RegisterFunction(name, start.Filename, start.Offset, end.Offset) v.state.functions = append(v.state.functions, f) } body = n.Body } if body != nil { // TODO function coverage (insert "function.Enter", "function.Leave"). // // FIXME instrumentation no longer records statements in line order, // as function literals are processed after the body of a function. sv := &stmtVisitor{v.state} sv.VisitStmt(body) } return v }
func (vis *findNodeVisitor) Visit(node ast.Node) (w ast.Visitor) { if node == nil || vis.result != nil { return nil } if utils.ComparePosWithinFile(vis.stPos, vis.fset.Position(node.Pos())) == 0 && utils.ComparePosWithinFile(vis.endPos, vis.fset.Position(node.End())) == 0 { vis.result = node return nil } return vis }
func (v *calltipVisitor) Visit(node ast.Node) (w ast.Visitor) { if node != nil { if x, ok := node.(*ast.CallExpr); ok { a := v.fset.Position(node.Pos()) b := v.fset.Position(node.End()) if (a.IsValid() && v.offset >= a.Offset) && (!b.IsValid() || v.offset <= b.Offset) { v.x = x } } } return v }
func (v *Visitor) Visit(node ast.Node) (w ast.Visitor) { if node != nil { fmt.Println(fset.Position(node.Pos())) fmt.Println(fset.Position(node.End())) fmt.Println(reflect.TypeOf(node)) if f := m[reflect.TypeOf(node)]; f != nil { f(node) } } return v }
// Span returns the 0-based offset range of the given AST node. // The range is half-open, including the start position but excluding the end. // If node == nil or lacks a valid start position, Span returns -1, -1. // If the end position of node is invalid, start == end. func (pi *PackageInfo) Span(node ast.Node) (start, end int) { if node == nil { return -1, -1 } else if pos := node.Pos(); pos == token.NoPos { return -1, -1 } else { start = pi.FileSet.Position(pos).Offset end = start } if pos := node.End(); pos != token.NoPos { end = pi.FileSet.Position(pos).Offset } return }
// Visit finds f.node performing a search down the ast tree. // It keeps the last block statement and statement seen for later use. func (f *blockStmtFinder) Visit(node ast.Node) ast.Visitor { if node == nil || f.node.Pos() < node.Pos() || f.node.End() > node.End() { return nil // not here } switch n := node.(type) { case *ast.BlockStmt: f.block = n case ast.Stmt: f.stmt = n } if f.node.Pos() == node.Pos() && f.node.End() == node.End() { return nil // found } return f // keep looking }
// End returns x.End() except that it works around buggy results from // the implementation of *ast.LabeledStmt and *ast.EmptyStmt. // The node x must be located within b's source file. // See golang.org/issue/9979. func (b *EditBuffer) End(x ast.Node) token.Pos { switch x := x.(type) { case *ast.LabeledStmt: if _, ok := x.Stmt.(*ast.EmptyStmt); ok { return x.Colon + 1 } return b.End(x.Stmt) case *ast.EmptyStmt: i := b.tx(x.Semicolon) if strings.HasPrefix(b.text[i:], ";") { return x.Semicolon + 1 } return x.Semicolon } return x.End() }
func (v *annotationVisitor) addAnnotation(n ast.Node, packageName string, name string) { pos := v.fset.Position(n.Pos()) end := v.fset.Position(n.End()) importPath := "" if packageName != "" { importPath = v.importPaths[packageName] if importPath == "" { return } } v.annotations = append(v.annotations, TypeAnnotation{ pos.Offset - len(packageWrapper), end.Offset - len(packageWrapper), importPath, name}) }
func (b *builder) position(n ast.Node) Pos { var position Pos pos := b.fset.Position(n.Pos()) src := b.srcs[pos.Filename] if src != nil { position.File = int16(src.index) position.Line = int32(pos.Line) end := b.fset.Position(n.End()) if src == b.srcs[end.Filename] { n := end.Line - pos.Line if n >= 0 && n <= math.MaxUint16 { position.N = uint16(n) } } } return position }
func shiftPosesAfterPos(node ast.Node, newNode ast.Node, pos token.Pos, by token.Pos) { // TODO: this must also move comments var offset token.Pos ast.Inspect(node, func(node ast.Node) bool { if node == nil { return true } if node == newNode { return false } if node.End() > pos && offset == 0 { offset = by } shiftPosesNonRecursively(node, offset, pos) return true }) }
func (v *offsetVisitor) Visit(node ast.Node) (w ast.Visitor) { if node == nil || v.node != nil { return nil } if node.End() < v.pos { return v } var start token.Pos switch n := node.(type) { case *ast.Ident: start = n.NamePos case *ast.SelectorExpr: start = n.Sel.NamePos case *ast.ImportSpec: start = n.Pos() case *ast.StructType: // TODO: Remove if unnecessary if n.Fields == nil { break } // Look for anonymous bare field. for _, field := range n.Fields.List { if field.Names != nil { continue } t := field.Type if pt, ok := field.Type.(*ast.StarExpr); ok { t = pt.X } if id, ok := t.(*ast.Ident); ok { if v.found(id.NamePos, id.End()) { v.node = id return nil } } } return v default: return v } if v.found(start, node.End()) { v.node = node return nil } return v }
func nodeInDiff(f BaseFile, node ast.Node) bool { start := f.(*gofile).fset.Position(node.Pos()) end := f.(*gofile).fset.Position(node.End()) diff := f.diff() if len(diff) == 0 { // skip diff check return true } for i := start.Line; i <= end.Line; i++ { if lineInDiff(diff, int64(i)) { return true } } return false }
// Visit implements the ast.Visitor interface. func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor { var body *ast.BlockStmt var name string switch n := node.(type) { case *ast.FuncLit: body = n.Body case *ast.FuncDecl: body = n.Body name = n.Name.Name // Function name is prepended with "T." if there is a receiver, where // T is the type of the receiver, dereferenced if it is a pointer. if n.Recv != nil { field := n.Recv.List[0] switch recv := field.Type.(type) { case *ast.StarExpr: name = recv.X.(*ast.Ident).Name + "." + name case *ast.Ident: name = recv.Name + "." + name } } } if body != nil { start := v.fset.Position(node.Pos()) end := v.fset.Position(node.End()) if name == "" { name = fmt.Sprintf("@%d:%d", start.Line, start.Column) } fe := &FuncExtent{ name: name, extent: extent{ startOffset: start.Offset, startLine: start.Line, startCol: start.Column, endOffset: end.Offset, endLine: end.Line, endCol: end.Column, }, } v.funcs = append(v.funcs, fe) sv := StmtVisitor{fset: v.fset, function: fe} sv.VisitStmt(body) } return v }
// Write the file with patches applied in that order. // Note: If patches contradicts each other, behaviour is undefined. func (p *PatchableFile) FprintPatched(w io.Writer, nd ast.Node, patches []Patch) (total int, err error) { defer func() { if r := recover(); r != nil && err == nil { panic(r) } }() sorted := sorted(patches) start, end := p.Fset.Position(nd.Pos()), p.Fset.Position(nd.End()) // for some reason, the start of an *ast.File is not the initial comment if _, ok := nd.(*ast.File); ok { start = p.Fset.Position(0) end = p.Fset.Position(token.Pos(len(p.Orig) + 1)) } prev := start.Offset for _, patch := range sorted { if nd.Pos() <= patch.StartPos() && nd.End() >= patch.StartPos() { pos := p.Fset.Position(patch.StartPos()) write(&total, &err, w, p.Orig[prev:pos.Offset]) switch patch := patch.(type) { case *InsertPatch: write(&total, &err, w, patch.Insert) case *InsertNodePatch: // TODO(elazar): check performance implications noremove := Patches{} for _, p := range patches { // If the patch removes a certain node if p.StartPos() == patch.Insert.Pos() && p.EndPos() == patch.Insert.End() { continue } noremove = append(noremove, p) } p.FprintPatched(w, patch.Insert, noremove) } prev = p.Fset.Position(patch.EndPos()).Offset } } if prev < end.Offset { write(&total, &err, w, p.Orig[prev:end.Offset]) } return }
func (visitor *astNodeVisitorForExpressions) Visit(node ast.Node) (w ast.Visitor) { if node != nil { _, isExpr := node.(ast.Expr) if visitor.context.fset.Position(node.Pos()).Line == visitor.context.selection.Begin.Line && visitor.context.fset.Position(node.Pos()).Column == visitor.context.selection.Begin.Column && visitor.context.fset.Position(node.End()).Line == visitor.context.selection.End.Line && visitor.context.fset.Position(node.End()).Column == visitor.context.selection.End.Column && isExpr { // fmt.Println("Starting with node at pos", visitor.context.fset.Position(node.Pos()), "and end", visitor.context.fset.Position(node.End())) // ast.Print(visitor.context.fset, node) // fmt.Println(node.Pos(), node) visitor.context.parent = visitor.parentNode visitor.context.exprToExtract = node.(ast.Expr) return nil } } return &astNodeVisitorForExpressions{ parentNode: node, context: visitor.context, } }
func (lp *linePrinter) Visit(n ast.Node) (w ast.Visitor) { if n == nil { if lp.output.Len() == 0 { lp.emit() } return nil } first := lp.fset.Position(n.Pos()).Line last := lp.fset.Position(n.End()).Line if first <= lp.line && last >= lp.line { // Print the innermost statement containing the line. if stmt, ok := n.(ast.Stmt); ok { if _, ok := n.(*ast.BlockStmt); !ok { lp.stmt = stmt } } if first == lp.line && lp.emit() { return nil } return lp } return nil }
func (v *prevFinder) Visit(node ast.Node) ast.Visitor { if _, ok := node.(*ast.File); ok { return ast.Visitor(v) } if node != nil && node.Pos() != token.NoPos { fmt.Println(node.Pos(), v.Off) fmt.Println(node) if int(node.Pos()) < v.Off && int(node.End()) < v.Off { ok := false if v.Ptr == nil { ok = true } else { if v.Off-int(node.End()) < v.Off-int(v.Ptr.End()) { ok = true } } if ok { v.Ptr = node return nil } } } return ast.Visitor(v) }
func AddDeclExplicit(fset *token.FileSet, filename string, file *ast.File, withFileSet *token.FileSet, withFileName string, withFile *ast.File, withNode ast.Node, identMap st.IdentifierMap) (bool, *token.FileSet, *ast.File, *errors.GoRefactorError) { if _, ok := withNode.(ast.Decl); !ok { return false, nil, nil, errors.PrinterError("node is not a declaration") } withTokFile := GetFileFromFileSet(withFileSet, withFileName) withOldSize := withTokFile.Size() l := int(withNode.End() - withNode.Pos()) fset, file = ReparseFile(file, filename, l, identMap) if filename == withFileName { FixPositions(0, 1-withTokFile.Base(), withNode, true) withFileSet, withFile = fset, file } tokFile := GetFileFromFileSet(fset, filename) withTokFile = GetFileFromFileSet(withFileSet, withFileName) if tokFile == nil || withTokFile == nil { return false, nil, nil, errors.PrinterError("couldn't find file " + filename + " in fileset") } lines := GetLines(tokFile) fmt.Printf("linesCount = %d\n", len(lines)) tokFile.SetLines(lines[:len(lines)-(l)]) lines = GetLines(tokFile) for i, offset := range lines { fmt.Printf("%d -> %s(%d)\n", i+1, fset.Position(tokFile.Pos(offset)), offset) } fmt.Printf("node -------- %d %d\n", withNode.Pos(), withNode.End()) withNodeLines, _ := GetRangeLines(withTokFile, withNode.Pos(), withNode.End(), withOldSize) withMod := int(tokFile.Offset(file.Decls[len(file.Decls)-1].End()) + 1 - withTokFile.Offset(withNode.Pos())) fmt.Printf("withMod: %v\n", withMod) for i, _ := range withNodeLines { withNodeLines[i] += withMod } tokFile.SetLines(addLinesOfRange(withTokFile.Offset(withNode.Pos()), withTokFile.Offset(withNode.End()), lines, withNodeLines, -1)) //to the end file.Decls = append(file.Decls, withNode.(ast.Decl)) return true, fset, file, nil }
func (lp *linePrinter) printWithComments(n ast.Node) { nfirst := lp.fset.Position(n.Pos()).Line nlast := lp.fset.Position(n.End()).Line for _, g := range lp.fnode.Comments { cfirst := lp.fset.Position(g.Pos()).Line clast := lp.fset.Position(g.End()).Line if clast == nfirst-1 && lp.fset.Position(n.Pos()).Column == lp.fset.Position(g.Pos()).Column { for _, c := range g.List { lp.output.WriteString(c.Text) lp.output.WriteByte('\n') } } if cfirst >= nfirst && cfirst <= nlast && n.End() <= g.List[0].Slash { // The printer will not include the comment if it starts past // the node itself. Trick it into printing by overlapping the // slash with the end of the statement. g.List[0].Slash = n.End() - 1 } } node := &printer.CommentedNode{n, lp.fnode.Comments} lp.config.Fprint(&lp.output, lp.fset, node) }
func (p *printer) isMultiLine(n ast.Node) bool { return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1 }
func makeSpan(fset *token.FileSet, node ast.Node) [2]uint32 { pos := node.Pos() start := fset.Position(pos) return [2]uint32{uint32(start.Offset), uint32(start.Offset + int((node.End() - pos)))} }