Beispiel #1
0
/*
 * findCalls() parses the node passed in and, if it's a
 * SelectorExpr (which any call to a function/method will be)
 * populates the map passed in as the second argument.
 * This is the function used for finder.find().
 *
 * Functions will have the package as the X node,
 * whereas methods will have the object identifier as the
 * X.  We do not differentiate in this function (there
 * really isn't a good way without access to the list of
 * imports and identifiers, so that has to be done higher up
 * the stack).
 */
func findCalls(n ast.Node, f *finder) bool {
	switch x := n.(type) {
	case *ast.File:
		locfields := strings.Split(fset.Position(n.Pos()).String(), ":")
		f.currentFile = locfields[0]
	case *ast.SelectorExpr:
		switch y := x.X.(type) {
		case *ast.Ident:
			locfields := strings.Split(fset.Position(y.NamePos).String(), ":")
			ln, err := strconv.Atoi(locfields[1])
			if err != nil {
				ln = -1
			}
			f.dset.AddPackageCall(Call{
				Qual: y.Name,
				Sel:  x.Sel.Name,
				// Location: y.NamePos,
				Line: ln,
			}, f.currentFile, true)
		default:
			return true
		} // END switch y :=
	default:
		return true
	} // END switch x :=
	return true
}
Beispiel #2
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 #3
0
func (v *visitor) Visit(node ast.Node) ast.Visitor {
	switch node := node.(type) {
	case *ast.FuncDecl:
		v.funcName = node.Name.Name
		v.m = make(map[*ast.Object][]string)

	case *ast.DeferStmt:
		if sel, ok := node.Call.Fun.(*ast.SelectorExpr); ok {
			if ident, ok := sel.X.(*ast.Ident); ok {
				if selectors, ok := v.m[ident.Obj]; !ok {
					v.m[ident.Obj] = []string{sel.Sel.Name}
				} else {
					found := false
					for _, selname := range selectors {
						if selname == sel.Sel.Name {
							pos := v.fset.Position(node.Pos())
							fmt.Printf("%s: %s:%d:%d: Repeating defer %s.%s() inside function %s\n",
								v.pkgPath, pos.Filename, pos.Line, pos.Column,
								ident.Name, selname, v.funcName)
							found = true
							exitStatus = 1
							break
						}
					}
					if !found {
						v.m[ident.Obj] = append(selectors, sel.Sel.Name)
					}
				}
			}
		}
	}
	return v
}
Beispiel #4
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 #5
0
func (lp *linePrinter) trim(n ast.Node) bool {
	stmt, ok := n.(ast.Stmt)
	if !ok {
		return true
	}
	line := lp.fset.Position(n.Pos()).Line
	if line != lp.line {
		return false
	}
	switch stmt := stmt.(type) {
	case *ast.IfStmt:
		stmt.Body = lp.trimBlock(stmt.Body)
	case *ast.SwitchStmt:
		stmt.Body = lp.trimBlock(stmt.Body)
	case *ast.TypeSwitchStmt:
		stmt.Body = lp.trimBlock(stmt.Body)
	case *ast.CaseClause:
		stmt.Body = lp.trimList(stmt.Body)
	case *ast.CommClause:
		stmt.Body = lp.trimList(stmt.Body)
	case *ast.BlockStmt:
		stmt.List = lp.trimList(stmt.List)
	}
	return true
}
Beispiel #6
0
// The variadic arguments may start with link and category types,
// and must end with a format string and any arguments.
func (f *file) errorf(n ast.Node, confidence float64, args ...interface{}) {
	if confidence < f.config.MinConfidence {
		return
	}

	p := f.fset.Position(n.Pos())
	problem := Problem{
		File:       f.filename,
		Position:   p,
		Confidence: confidence,
		LineText:   srcLine(f.src, p),
	}

argLoop:
	for len(args) > 1 { // always leave at least the format string in args
		switch v := args[0].(type) {
		case link:
			problem.Link = string(v)
		case category:
			problem.Category = string(v)
		default:
			break argLoop
		}
		args = args[1:]
	}

	problem.Text = fmt.Sprintf(args[0].(string), args[1:]...)

	f.problems = append(f.problems, problem)
}
Beispiel #7
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 #8
0
func (f *File) printNode(node, ident ast.Node, url string) {
	if !f.doPrint {
		f.found = true
		return
	}
	fmt.Printf("%s%s%s", url, f.sourcePos(f.fset.Position(ident.Pos())), f.docs(node))
}
Beispiel #9
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 #10
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 #11
0
// The variadic arguments may start with link and category types,
// and must end with a format string and any arguments.
// It returns the new Problem.
func (f *file) errorf(n ast.Node, confidence float64, args ...interface{}) *Problem {
	pos := f.fset.Position(n.Pos())
	if pos.Filename == "" {
		pos.Filename = f.filename
	}
	return f.pkg.errorfAt(pos, confidence, args...)
}
Beispiel #12
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 #13
0
func (a *stmtCompiler) definePkg(ident ast.Node, id, path string) *PkgIdent {
	v, prev := a.block.DefinePackage(id, path, ident.Pos())
	if prev != nil {
		a.diagAt(ident.Pos(), "%s redeclared as imported package name\n\tprevious declaration at %s", id, a.fset.Position(prev.Pos()))
		return nil
	}
	return v
}
Beispiel #14
0
// Used for implicit objects created by some ImportSpecs and CaseClauses.
func (r *resolver) defineImplicit(b *Block, n ast.Node, name string) {
	obj := r.info.Implicits[n]
	if obj == nil {
		logf("%s: internal error: not an implicit definition: %T\n",
			r.fset.Position(n.Pos()), n)
	}
	r.defineObject(b, name, obj)
}
Beispiel #15
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 #16
0
// Visit implements ast.Visistor's Visit method
func (t *prohibitVisitor) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		return t
	}
	if filterChanStmtOrExpr(node) != nil {
		t.AddError(node.Pos(), fmt.Sprintf("Channel operation in non top-level block: %v", node))
	}
	return t
}
Beispiel #17
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 #18
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 #19
0
func (f *file) errorf(n ast.Node, confidence float64, format string, a ...interface{}) {
	p := f.fset.Position(n.Pos())
	f.problems = append(f.problems, Problem{
		Position:   p,
		Text:       fmt.Sprintf(format, a...),
		Confidence: confidence,
		LineText:   srcLine(f.src, p),
	})
}
Beispiel #20
0
// compiles expression or statement
func (w *World) compile(n ast.Node) Expr {
	switch n := n.(type) {
	case ast.Stmt:
		return w.compileStmt(n)
	case ast.Expr:
		return w.compileExpr(n)
	default:
		panic(err(n.Pos(), "not allowed"))
	}
}
Beispiel #21
0
func nodeLabel(fset *token.FileSet, x ast.Node) string {
	pos := fset.Position(x.Pos())
	label := fmt.Sprintf("%T %s:%d", x, pos.Filename, pos.Line)
	switch x := x.(type) {
	case *ast.Ident:
		label = x.Name + " " + label
	case *ast.SelectorExpr:
		label = "." + x.Sel.Name + " " + label
	}
	return label
}
Beispiel #22
0
func (f *file) indentOf(node ast.Node) string {
	line := srcLine(f.src, f.fset.Position(node.Pos()))
	for i, r := range line {
		switch r {
		case ' ', '\t':
		default:
			return line[:i]
		}
	}
	return line // unusual or empty line
}
Beispiel #23
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
}
func (es *extractStrings) processBasicLit(basicLit *ast.BasicLit, n ast.Node, fset *token.FileSet) {
	s, _ := strconv.Unquote(basicLit.Value)
	if len(s) > 0 && basicLit.Kind == token.STRING && s != "\t" && s != "\n" && s != " " && !es.filter(s) { //TODO: fix to remove these: s != "\\t" && s != "\\n" && s != " "
		position := fset.Position(n.Pos())
		stringInfo := common.StringInfo{Value: s,
			Filename: position.Filename,
			Offset:   position.Offset,
			Line:     position.Line,
			Column:   position.Column}
		es.ExtractedStrings[s] = stringInfo
	}
}
Beispiel #25
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 #26
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 #27
0
func (file *WasmGoSourceFile) ErrorNode(node ast.Node, format string, a ...interface{}) error {
	pos := node.Pos()
	position := file.fset.File(pos).PositionFor(pos, false)
	s := fmt.Sprintf(format, a...)
	src := file.getSingleLineGoSource(node)
	if src != "" {
		s = fmt.Sprintf("%s (src: %s)", s, src)
	}
	e := &GoWasmError{
		msg: fmt.Sprintf("%s @ %v", s, position),
	}
	return e
}
Beispiel #28
0
func (g *Grapher) NewRef(node ast.Node, obj types.Object) (*Ref, error) {
	key, err := g.defKey(obj)
	if err != nil {
		return nil, err
	}

	pos := g.program.Fset.Position(node.Pos())
	return &Ref{
		File: pos.Filename,
		Span: makeSpan(g.program.Fset, node),
		Def:  key,
	}, nil
}
Beispiel #29
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 #30
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
}