Beispiel #1
0
// 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
	})
}
Beispiel #2
0
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,
	}
}
Beispiel #3
0
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])
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #6
0
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,
	}
}
Beispiel #7
0
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()
}
Beispiel #8
0
func (f *gofile) newIssueRangeFromNode(n ast.Node) *issueRange {
	s := f.Fset().Position(n.Pos())
	e := f.Fset().Position(n.End())
	return &issueRange{
		s,
		e,
	}
}
Beispiel #9
0
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})
}
Beispiel #10
0
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
}
Beispiel #11
0
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
}
Beispiel #12
0
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
}
Beispiel #13
0
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
}
Beispiel #14
0
// 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
}
Beispiel #15
0
// 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
}
Beispiel #16
0
// 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()
}
Beispiel #17
0
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})
}
Beispiel #18
0
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
}
Beispiel #19
0
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
	})
}
Beispiel #20
0
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
}
Beispiel #21
0
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
}
Beispiel #22
0
// 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
}
Beispiel #23
0
// 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
}
Beispiel #24
0
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,
	}
}
Beispiel #25
0
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
}
Beispiel #26
0
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)
}
Beispiel #27
0
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
}
Beispiel #28
0
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)
}
Beispiel #29
0
func (p *printer) isMultiLine(n ast.Node) bool {
	return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1
}
Beispiel #30
0
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)))}
}