func (v *fileVisitor) method(n *ast.FuncDecl) *Method {
	method := &Method{Name: n.Name.Name}
	method.Lines = []*Line{}

	start := v.fset.Position(n.Pos())
	end := v.fset.Position(n.End())
	startLine := start.Line
	startCol := start.Column
	endLine := end.Line
	endCol := end.Column
	// The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block.
	for _, b := range v.profile.Blocks {
		if b.StartLine > endLine || (b.StartLine == endLine && b.StartCol >= endCol) {
			// Past the end of the function.
			break
		}
		if b.EndLine < startLine || (b.EndLine == startLine && b.EndCol <= startCol) {
			// Before the beginning of the function
			continue
		}
		for i := b.StartLine; i <= b.EndLine; i++ {
			method.Lines = append(method.Lines, &Line{Number: i, Hits: int64(b.Count)})
		}
	}
	return method
}
Beispiel #2
0
func (p *Parser) checkFuncLength(x *ast.FuncDecl) {
	numStatements := statementCount(x)
	if numStatements <= *statementThreshold {
		return
	}

	p.summary.addStatement(p.offender(x.Name.String(), numStatements, x.Pos()))
}
Beispiel #3
0
func (f *file) checkFunctionBody(funcDecl *ast.FuncDecl) {
	if funcDecl.Body != nil {
		return
	}
	start := f.fset.Position(funcDecl.Pos())
	problem := genFuncBodyProblem(funcDecl.Name.Name, start)
	f.problems = append(f.problems, problem)
}
Beispiel #4
0
func (p *Parser) checkResultCount(x *ast.FuncDecl) {
	numResults := x.Type.Results.NumFields()
	if numResults <= *resultThreshold {
		return
	}

	p.summary.addResult(p.offender(x.Name.String(), numResults, x.Pos()))
}
Beispiel #5
0
func checkTestFunc(fn *ast.FuncDecl, arg string) error {
	if !isTestFunc(fn, arg) {
		name := fn.Name.String()
		pos := testFileSet.Position(fn.Pos())
		return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
	}
	return nil
}
Beispiel #6
0
func (p *Parser) checkParamCount(x *ast.FuncDecl) {
	numFields := x.Type.Params.NumFields()
	if numFields <= *paramThreshold {
		return
	}

	p.summary.addParam(p.offender(x.Name.String(), numFields, x.Pos()))
}
func parseFunction(funcDecl *ast.FuncDecl, fileInBytes []byte) (string, bool) {
	if ast.IsExported(funcDecl.Name.Name) {
		fmt.Printf("Function exported: %s\n", funcDecl.Name.Name)
		return string(fileInBytes[funcDecl.Pos()-1 : funcDecl.Body.Lbrace-1]), true
	} else {
		fmt.Printf("Function not exported: %s\n", funcDecl.Name.Name)
	}
	return "", false
}
Beispiel #8
0
func processFunction(funcDecl *ast.FuncDecl) {
	m := function{}

	m.bodyStart = fset.Position(funcDecl.Pos()).Line
	m.bodyEnd = fset.Position(funcDecl.End()).Line
	m.variables = getFunctionVariables(funcDecl)

	addFoundFunctions(m)
}
Beispiel #9
0
// Functions
//
// http://golang.org/doc/go_spec.html#Function_declarations
// https://developer.mozilla.org/en/JavaScript/Reference/Statements/function
func (tr *transform) getFunc(decl *ast.FuncDecl) {
	// godoc go/ast FuncDecl
	//  Doc  *CommentGroup // associated documentation; or nil
	//  Recv *FieldList    // receiver (methods); or nil (functions)
	//  Name *Ident        // function/method name
	//  Type *FuncType     // position of Func keyword, parameters and results
	//  Body *BlockStmt    // function body; or nil (forward declaration)

	// Check empty functions
	if len(decl.Body.List) == 0 {
		return
	}

	isFuncInit := false // function init()

	// == Initialization to save variables created on this function
	if decl.Name != nil { // discard literal functions
		tr.funcTotal++
		tr.funcId = tr.funcTotal
		tr.blockId = 0

		tr.vars[tr.funcId] = make(map[int]map[string]bool)
		tr.addr[tr.funcId] = make(map[int]map[string]bool)
		tr.maps[tr.funcId] = make(map[int]map[string]struct{})
		tr.slices[tr.funcId] = make(map[int]map[string]struct{})
		tr.zeroType[tr.funcId] = make(map[int]map[string]string)
	}
	// ==

	tr.addLine(decl.Pos())
	tr.addIfExported(decl.Name)

	if decl.Name.Name != "init" {
		tr.writeFunc(decl.Recv, decl.Name, decl.Type)
	} else {
		isFuncInit = true
		tr.WriteString("(function()" + SP)
	}

	tr.getStatement(decl.Body)

	if isFuncInit {
		tr.WriteString("());")
	}

	// At exiting of the function, it returns at the global scope.
	if decl.Name != nil {
		tr.funcId = 0
		tr.blockId = 0
	}
	if decl.Recv != nil {
		tr.recvVar = ""
	}
}
Beispiel #10
0
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
	p.setComment(d.Doc)
	p.print(d.Pos(), token.FUNC, blank)
	if d.Recv != nil {
		p.parameters(d.Recv, multiLine) // method: print receiver
		p.print(blank)
	}
	p.expr(d.Name, multiLine)
	p.signature(d.Type.Params, d.Type.Results, multiLine)
	p.funcBody(d.Body, distance(d.Pos(), p.pos), false, multiLine)
}
Beispiel #11
0
// Handle a function declaration.
func funcDecl(fset *token.FileSet, decl *ast.FuncDecl) {
	var recvType string
	if decl.Recv != nil {
		// Method definition.  There's always only one receiver.
		recvType = "class:" + typeName(decl.Recv.List[0].Type)
	} else {
		// Normal function
		recvType = ""
	}
	emitTag(decl.Name.Name, decl.Pos(), fset, FUNC, recvType)
}
Beispiel #12
0
func (p *printer) funcDecl(d *ast.FuncDecl) {
	p.setComment(d.Doc)
	p.print(d.Pos(), token.FUNC, blank)
	if d.Recv != nil {
		p.parameters(d.Recv) // method: print receiver
		p.print(blank)
	}
	p.expr(d.Name)
	p.signature(d.Type.Params, d.Type.Results)
	p.adjBlock(p.distanceFrom(d.Pos()), vtab, d.Body)
}
Beispiel #13
0
func (p *Parser) checkBoolParams(x *ast.FuncDecl) {
	if *skipBoolParamCheck {
		return
	}
	for _, f := range x.Type.Params.List {
		// this is ugly, but:
		if fmt.Sprintf("%s", f.Type) != "bool" {
			continue
		}
		p.summary.addBoolParam(p.offender(x.Name.String(), 0, x.Pos()))
	}
}
Beispiel #14
0
func (c *compiler) createFunctionMetadata(f *ast.FuncDecl, fn *LLVMValue) llvm.DebugDescriptor {
	if len(c.debug_context) == 0 {
		return nil
	}

	file := c.fileset.File(f.Pos())
	fnptr := fn.value
	fun := fnptr.IsAFunction()
	if fun.IsNil() {
		fnptr = llvm.ConstExtractValue(fn.value, []uint32{0})
	}
	meta := &llvm.SubprogramDescriptor{
		Name:        fnptr.Name(),
		DisplayName: f.Name.Name,
		Path:        llvm.FileDescriptor(file.Name()),
		Line:        uint32(file.Line(f.Pos())),
		ScopeLine:   uint32(file.Line(f.Body.Pos())),
		Context:     &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())},
		Function:    fnptr}

	var result types.Type
	var metaparams []llvm.DebugDescriptor
	if ftyp, ok := fn.Type().(*types.Signature); ok {
		if recv := ftyp.Recv(); recv != nil {
			metaparams = append(metaparams, c.tollvmDebugDescriptor(recv.Type()))
		}
		if ftyp.Params() != nil {
			for i := 0; i < ftyp.Params().Len(); i++ {
				p := ftyp.Params().At(i)
				metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type()))
			}
		}
		if ftyp.Results() != nil {
			result = ftyp.Results().At(0).Type()
			// TODO: what to do with multiple returns?
			for i := 1; i < ftyp.Results().Len(); i++ {
				p := ftyp.Results().At(i)
				metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type()))
			}
		}
	}

	meta.Type = llvm.NewSubroutineCompositeType(
		c.tollvmDebugDescriptor(result),
		metaparams,
	)

	// compile unit is the first context object pushed
	compileUnit := c.debug_context[0].(*llvm.CompileUnitDescriptor)
	compileUnit.Subprograms = append(compileUnit.Subprograms, meta)
	return meta
}
Beispiel #15
0
func (p *parser) parseFuncDecl(n *parse.Node) ast.Decl {
	scope := ast.NewScope(p.topScope)
	funcDecl := ast.FuncDecl{
		Name: p.parseIdent(n.Child(1)),
	}
	funcOrSig := n.Child(2).Child(0)
	if funcOrSig.Rule() == signature {
		funcDecl.Type = p.parseSignature(funcOrSig, scope)
	} else {
		funcDecl.Type, funcDecl.Body = p.parseFunc(funcOrSig, scope)
	}
	funcDecl.Type.Func = token.Pos(n.Child(0).Pos())
	return &funcDecl
}
Beispiel #16
0
// topLevelNodeToDecl converts an AST node to Go ast.Decl
func topLevelNodeToDecl(node *parser.CallNode) ast.Decl {
	if node.Callee.(*parser.IdentNode).Ident != "defn" {
		panic("Top level node has to be defn")
	}

	switch node.Callee.(*parser.IdentNode).Ident {
	case "defn":
		decl := ast.FuncDecl{
			Name: &ast.Ident{
				NamePos: 2,
				Name:    node.Args[0].(*parser.IdentNode).Ident,
			},
		}
		fmt.Printf("SHOW ARGS: %+v\n", node.Args[1:])

		// @TODO Fix this to support signature properly
		params := &ast.FieldList{
			Opening: 1,
			Closing: 3,
		}
		params.List = make([]*ast.Field, 1)
		params.List[0] = &ast.Field{
			Names: []*ast.Ident{
				&ast.Ident{
					Name: "lol",
				},
			},
			Type: &ast.Ident{
				Name: "interface{}",
			},
		}

		decl.Type = &ast.FuncType{
			Func:    1,
			Params:  params,
			Results: nil,
		}

		//decl.Body = nodeFnBody(node.Args[1:])
		// TODO: Check argument lengths
		decl.Body = nodeFnBody(node.Args[1])

		return &decl
	default:
		// The rest is normal function call probably
		//return nodeFnCall(node)
		fmt.Println("got nil %+v", node)
		return nil
	}
}
Beispiel #17
0
func (check *checker) funcDecl(obj *Func, fdecl *ast.FuncDecl) {
	// func declarations cannot use iota
	assert(check.iota == nil)

	obj.typ = Typ[Invalid] // guard against cycles
	sig := check.funcType(fdecl.Recv, fdecl.Type, nil)
	if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
		check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
		// ok to continue
	}
	obj.typ = sig

	check.later(obj, sig, fdecl.Body)
}
Beispiel #18
0
func (f *file) checkFunctionLine(funcDecl *ast.FuncDecl) {
	lineLimit := f.config.FunctionLine
	if lineLimit <= 0 {
		return
	}
	start := f.fset.Position(funcDecl.Pos())

	startLine := start.Line
	endLine := f.fset.Position(funcDecl.End()).Line
	lineCount := endLine - startLine
	if lineCount > lineLimit {
		problem := genFuncLineProblem(funcDecl.Name.Name, lineCount, lineLimit, start)
		f.problems = append(f.problems, problem)
	}
}
Beispiel #19
0
// set creates the corresponding Func for f and adds it to mset.
// If there are multiple f's with the same name, set keeps the first
// one with documentation; conflicts are ignored.
//
func (mset methodSet) set(f *ast.FuncDecl) {
	name := f.Name.Name
	if g := mset[name]; g != nil && g.Doc != "" {
		// A function with the same name has already been registered;
		// since it has documentation, assume f is simply another
		// implementation and ignore it. This does not happen if the
		// caller is using go/build.ScanDir to determine the list of
		// files implementing a package.
		return
	}
	// function doesn't exist or has no documentation; use f
	recv := ""
	if f.Recv != nil {
		var typ ast.Expr
		// be careful in case of incorrect ASTs
		if list := f.Recv.List; len(list) == 1 {
			typ = list[0].Type
		}
		recv = recvString(typ)
	}
	mset[name] = &Func{
		Doc:  f.Doc.Text(),
		Name: name,
		Decl: f,
		Recv: recv,
		Orig: recv,
	}
	f.Doc = nil // doc consumed - remove from AST
}
Beispiel #20
0
// writeFunc writes a syscall wrapper for f to w.
// It modifies f's data, so be warned!
func (m *module) writeFunc(w io.Writer, f *ast.FuncDecl) error {
	f.Recv = nil // Remove the bogus receiver (really the DLL name).
	err := m.printConfig.Fprint(w, m.fileSet, f)
	if err != nil {
		return err
	}
	fmt.Fprintln(w, " {")

	params, setupCode, resultCode, err := m.analyzeParameterList(f.Type)
	if err != nil {
		return err
	}

	prefix := ""
	if m.packageName != "com" {
		prefix = "com."
	}

	if setupCode != "" {
		fmt.Fprintln(w, setupCode)
	}
	fmt.Fprintf(w, "\t_res, _, _ := %sSyscall(proc%s.Addr(),\n\t\t%s)\n", prefix, f.Name.Name, strings.Join(params, ",\n\t\t"))

	fmt.Fprint(w, resultCode)
	fmt.Fprintln(w, "\treturn")

	fmt.Fprintln(w, "}")
	fmt.Fprintln(w)
	return nil
}
Beispiel #21
0
// readFunc processes a func or method declaration.
//
func (r *reader) readFunc(fun *ast.FuncDecl) {
	// strip function body
	fun.Body = nil

	// determine if it should be associated with a type
	if fun.Recv != nil {
		// method
		recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
		if imp {
			// should not happen (incorrect AST);
			// don't show this method
			return
		}
		var typ *baseType
		if r.isVisible(recvTypeName) {
			// visible recv type: if not found, add it to r.types
			typ = r.lookupType(recvTypeName)
		} else {
			// invisible recv type: if not found, do not add it
			// (invisible embedded types are added before this
			// phase, so if the type doesn't exist yet, we don't
			// care about this method)
			typ = r.types[recvTypeName]
		}
		if typ != nil {
			// associate method with the type
			// (if the type is not exported, it may be embedded
			// somewhere so we need to collect the method anyway)
			typ.methods.set(fun)
		}
		// otherwise don't show the method
		// TODO(gri): There may be exported methods of non-exported types
		// that can be called because of exported values (consts, vars, or
		// function results) of that type. Could determine if that is the
		// case and then show those methods in an appropriate section.
		return
	}

	// perhaps a factory function
	// determine result type, if any
	if fun.Type.Results.NumFields() >= 1 {
		res := fun.Type.Results.List[0]
		if len(res.Names) <= 1 {
			// exactly one (named or anonymous) result associated
			// with the first type in result signature (there may
			// be more than one result)
			if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) {
				if typ := r.lookupType(n); typ != nil {
					// associate Func with typ
					typ.funcs.set(fun)
					return
				}
			}
		}
	}

	// just an ordinary function
	r.funcs.set(fun)
}
Beispiel #22
0
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
	p.leadComment(d.Doc)
	p.print(d.Pos(), token.FUNC, blank)
	if recv := d.Recv; recv != nil {
		// method: print receiver
		p.print(token.LPAREN)
		if len(recv.Names) > 0 {
			p.expr(recv.Names[0], multiLine)
			p.print(blank)
		}
		p.expr(recv.Type, multiLine)
		p.print(token.RPAREN, blank)
	}
	p.expr(d.Name, multiLine)
	p.signature(d.Type.Params, d.Type.Results, multiLine)
	p.funcBody(d.Body, false, multiLine)
}
Beispiel #23
0
func funcDeclToString(decl *ast.FuncDecl) string {
	var buffer bytes.Buffer
	var body *ast.BlockStmt
	body, decl.Body = decl.Body, nil
	printer.Fprint(&buffer, token.NewFileSet(), decl)
	decl.Body = body
	return buffer.String()
}
Beispiel #24
0
func newFunc(decl *ast.FuncDecl) *Func {
	if !ast.IsExported(decl.Name.Name) {
		return nil
	}

	f := new(Func)
	f.Doc = doc.CommentText(decl.Doc)
	decl.Doc = nil

	f.Name = decl.Name.Name
	if decl.Recv != nil {
		f.Recv = recvAsString(decl.Recv.List[0].Type)
	}
	f.Decl = decl
	decl.Body = nil // remove body
	return f
}
Beispiel #25
0
func (p *printer) funcDecl(d *ast.FuncDecl) {
	p.setComment(d.Doc)
	if d.Recv != nil {
		p.parameters(d.Recv) // method: print receiver
		p.print(blank)
	}
	if d.Name.Name == "main" {
		p.print("int ")
	} else {
		p.funcreturn(d.Type.Results)
	}
	p.expr(d.Name)
	p.signature(d.Type.Params)
	if d.Name.Name == "main" {
		zero := &ast.BasicLit{Kind: token.INT, Value: "0"}
		d.Body.List = append(d.Body.List, &ast.ReturnStmt{Results: []ast.Expr{zero}})
	}
	p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false)
}
Beispiel #26
0
// parseFunction creates a tag for function declaration f.
func (p *tagParser) parseFunction(f *ast.FuncDecl) {
	tag := p.createTag(f.Name.Name, f.Pos(), Function)

	tag.Fields[Access] = getAccess(tag.Name)
	tag.Fields[Signature] = fmt.Sprintf("(%s)", getTypes(f.Type.Params, true))
	tag.Fields[TypeField] = getTypes(f.Type.Results, false)

	if f.Recv != nil && len(f.Recv.List) > 0 {
		// this function has a receiver, set the type to Method
		tag.Fields[ReceiverType] = getType(f.Recv.List[0].Type, false)
		tag.Type = Method
	} else if name, ok := p.belongsToReceiver(f.Type.Results); ok {
		// this function does not have a receiver, but it belongs to one based
		// on its return values; its type will be Function instead of Method.
		tag.Fields[ReceiverType] = name
		tag.Type = Function
	}

	p.tags = append(p.tags, tag)
}
func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string {
	// find the last comment in the function
	var last *ast.CommentGroup
	for _, cg := range comments {
		if cg.Pos() < fun.Pos() {
			continue
		}
		if cg.End() > fun.End() {
			break
		}
		last = cg
	}
	if last != nil {
		// test that it begins with the correct prefix
		text := last.Text()
		if loc := outputPrefix.FindStringIndex(text); loc != nil {
			return strings.TrimSpace(text[loc[1]:])
		}
	}
	return "" // no suitable comment found
}
Beispiel #28
0
func (p *printer) funcDecl(d *ast.FuncDecl) {
	p.setComment(d.Doc)
	p.print(d.Pos(), token.FUNC, blank)
	if d.Recv != nil {
		p.expr(d.Recv.List[0].Type) // method: print receiver
		p.print(d.Pos(), ".")
		if names := d.Recv.List[0].Names; len(names) > 0 {
			if name := names[0]; name != nil && name.Name != "_" {
				p.rcvName = name
				defer func() {
					p.rcvName = nil
				}()
			}
		}
	}
	p.expr(d.Name)
	p.signature(d.Type.Params, d.Type.Results)
	p.inFunc = true
	p.adjBlock(d.Body)
	p.inFunc = false
	p.print(unindent)
}
Beispiel #29
0
// readFunc processes a func or method declaration.
//
func (r *reader) readFunc(fun *ast.FuncDecl) {
	// strip function body
	fun.Body = nil

	// associate methods with the receiver type, if any
	if fun.Recv != nil {
		// method
		if len(fun.Recv.List) == 0 {
			// should not happen (incorrect AST); (See issue 17788)
			// don't show this method
			return
		}
		recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
		if imp {
			// should not happen (incorrect AST);
			// don't show this method
			return
		}
		if typ := r.lookupType(recvTypeName); typ != nil {
			typ.methods.set(fun)
		}
		// otherwise ignore the method
		// TODO(gri): There may be exported methods of non-exported types
		// that can be called because of exported values (consts, vars, or
		// function results) of that type. Could determine if that is the
		// case and then show those methods in an appropriate section.
		return
	}

	// associate factory functions with the first visible result type, if any
	if fun.Type.Results.NumFields() >= 1 {
		res := fun.Type.Results.List[0]
		if len(res.Names) <= 1 {
			// exactly one (named or anonymous) result associated
			// with the first type in result signature (there may
			// be more than one result)
			if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) {
				if typ := r.lookupType(n); typ != nil {
					// associate function with typ
					typ.funcs.set(fun)
					return
				}
			}
		}
	}

	// just an ordinary function
	r.funcs.set(fun)
}
Beispiel #30
0
func (c *compiler) VisitFuncDecl(f *ast.FuncDecl) Value {
	fn := c.Resolve(f.Name).(*LLVMValue)
	attributes := parseAttributes(f.Doc)
	for _, attr := range attributes {
		attr.Apply(fn)
	}
	if f.Body == nil {
		return fn
	}

	var paramVars []*types.Var
	ftyp := fn.Type().(*types.Signature)
	if recv := ftyp.Recv(); recv != nil {
		paramVars = append(paramVars, recv)
	}
	if ftyp.Params() != nil {
		for i := 0; i < ftyp.Params().Len(); i++ {
			p := ftyp.Params().At(i)
			paramVars = append(paramVars, p)
		}
	}

	c.pushDebugContext(c.createFunctionMetadata(f, fn))
	defer c.popDebugContext()
	c.setDebugLine(f.Pos())

	paramVarsTuple := types.NewTuple(paramVars...)
	c.buildFunction(fn, nil, paramVarsTuple, ftyp.Results(), f.Body)

	if f.Recv == nil && f.Name.Name == "init" {
		// Is it an 'init' function? Then record it.
		fnptr := llvm.ConstExtractValue(fn.value, []uint32{0})
		c.initfuncs = append(c.initfuncs, fnptr)
	}
	return fn
}