Esempio n. 1
0
func initParserMode() {
	parserMode = parser.Mode(0)
	parserMode |= parser.ParseComments
	if *allErrors {
		parserMode |= parser.AllErrors
	}
}
Esempio n. 2
0
func GrokDir(dir string) {
	pkgs, err := parser.ParseDir(fset, dir, FilterDotGo, parser.Mode(0))
	if err != nil {
		panic(Sprintf("ERROR <%q> IN DIR <%s>", err, dir))
	}

	// Find the subdir that follows /pkg/
	subdir := AfterFirstDelim(dir, "/pkg/", "")
	if len(subdir) == 0 {
		panic("dir does not contain /pkg/ plus a tail: " + dir)
	}

	// Trim trailing /, if any.
	if subdir[len(subdir)-1] == '/' {
		subdir = subdir[:len(subdir)-1]
	}

	for pk, pv := range pkgs {
		// For dirpkg, remove final piece of subdir
		// and replace with stated package name.
		// Often these are the same, but not always.
		updir := BeforeFinalDelim(subdir, "/", "")
		dirpkg := Cond(updir == "", pk, updir+"/"+pk)

		Printf("#dirpkg %#v\n", dirpkg)
		Printf("#pv %#v\n", pv)

		for _, fv := range pv.Files {
			for i, dcl := range fv.Decls {
				doDecl(dcl, i, dirpkg)
			}
		}
	}
}
Esempio n. 3
0
func goInitParserMode() {
	goParserMode = parser.Mode(0)
	if *comments {
		goParserMode |= parser.ParseComments
	}
	goParserMode |= parser.AllErrors
}
Esempio n. 4
0
func TestBump(t *testing.T) {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, "testdata/test1", nil, parser.Mode(0))
	if err != nil {
		t.Fatal(err)
	}

	conf := Config{
		MinorDelta: 1,
	}

	for _, pkg := range pkgs {
		for _, f := range pkg.Files {
			vers, err := conf.ProcessNode(fset, f)
			if err != nil {
				t.Errorf("got error: %s", err)
			}
			if _, ok := vers["version"]; !ok {
				t.Errorf("should detect `version`")
			}
			if _, ok := vers["VERSION"]; !ok {
				t.Errorf("should detect `VERSION`")
			}
			if vers["version"] != "1.1.0" {
				t.Errorf("expected %v: got %v", "1.1.0", vers["version"])
			}
			if vers["VERSION"] != "2.1.0" {
				t.Errorf("expected %v: got %v", "2.1.0", vers["VERSION"])
			}
		}
	}
}
Esempio n. 5
0
// fastQueryPos parses the position string and returns a queryPos.
// It parses only a single file and does not run the type checker.
func fastQueryPos(ctxt *build.Context, pos string) (*queryPos, error) {
	filename, startOffset, endOffset, err := parsePos(pos)
	if err != nil {
		return nil, err
	}

	// Parse the file, opening it the file via the build.Context
	// so that we observe the effects of the -modified flag.
	fset := token.NewFileSet()
	cwd, _ := os.Getwd()
	f, err := buildutil.ParseFile(fset, ctxt, nil, cwd, filename, parser.Mode(0))
	// ParseFile usually returns a partial file along with an error.
	// Only fail if there is no file.
	if f == nil {
		return nil, err
	}
	if !f.Pos().IsValid() {
		return nil, fmt.Errorf("%s is not a Go source file", filename)
	}

	start, end, err := fileOffsetToPos(fset.File(f.Pos()), startOffset, endOffset)
	if err != nil {
		return nil, err
	}

	path, exact := astutil.PathEnclosingInterval(f, start, end)
	if path == nil {
		return nil, fmt.Errorf("no syntax here")
	}

	return &queryPos{fset, start, end, path, exact, nil}, nil
}
Esempio n. 6
0
func initParserMode() {
	parserMode = parser.Mode(0)
	if *comments {
		parserMode |= parser.ParseComments
	}
	if *allErrors {
		parserMode |= parser.SpuriousErrors
	}
}
Esempio n. 7
0
File: main.go Progetto: jonfk/gore
// importPackages includes packages defined on external file into main file
func (s *Session) importPackages(src []byte) error {
	astf, err := parser.ParseFile(s.Fset, "", src, parser.Mode(0))
	if err != nil {
		return err
	}

	for _, imt := range astf.Imports {
		debugf("import package: %s", imt.Path.Value)
		actionImport(s, imt.Path.Value)
	}

	return nil
}
Esempio n. 8
0
// applyAroundAdvice uses code from gofmt to wrap any after advice
// essentially this is the same stuff you could do w/the cmdline tool,
// gofmt
//
// FIXME - mv to CallExpr
//
// looks for call joinpoints && provides around advice capability
//
// this is currently a hack to support deferpanic's http lib
func (w *Weave) applyAroundAdvice(fname string) string {

	stuff := fileAsStr(fname)

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {
		aspect := w.aspects[i]
		if aspect.advize.around != "" {
			pk := aspect.pointkut
			around_advice := aspect.advize.around

			fset := token.NewFileSet()
			file, err := parser.ParseFile(fset, fname, stuff, parser.Mode(0))
			if err != nil {
				w.flog.Println("Failed to parse source: %s", err.Error())
			}

			// needs match groups
			// wildcards of d,s...etc.
			p := parseExpr(pk.def)
			val := parseExpr(around_advice)

			file = rewriteFile2(p, val, file)

			buf := new(bytes.Buffer)
			err = format.Node(buf, fset, file)
			if err != nil {
				w.flog.Println("Failed to format post-replace source: %v", err)
			}

			actual := buf.String()

			w.writeOut(fname, actual)

			stuff = actual

			for t := 0; t < len(aspect.importz); t++ {
				importsNeeded = append(importsNeeded, aspect.importz[t])
			}

		}
	}

	if len(importsNeeded) > 0 {
		// add any imports for this piece of advice
		stuff = w.writeMissingImports(fname, stuff, importsNeeded)
	}

	return stuff
}
Esempio n. 9
0
// findPackageMember returns the type and position of the declaration of
// pkg.member by loading and parsing the files of that package.
// srcdir is the directory in which the import appears.
func findPackageMember(ctxt *build.Context, fset *token.FileSet, srcdir, pkg, member string) (token.Token, token.Pos, error) {
	bp, err := ctxt.Import(pkg, srcdir, 0)
	if err != nil {
		return 0, token.NoPos, err // no files for package
	}

	// TODO(adonovan): opt: parallelize.
	for _, fname := range bp.GoFiles {
		filename := filepath.Join(bp.Dir, fname)

		// Parse the file, opening it the file via the build.Context
		// so that we observe the effects of the -modified flag.
		f, _ := buildutil.ParseFile(fset, ctxt, nil, ".", filename, parser.Mode(0))
		if f == nil {
			continue
		}

		// Find a package-level decl called 'member'.
		for _, decl := range f.Decls {
			switch decl := decl.(type) {
			case *ast.GenDecl:
				for _, spec := range decl.Specs {
					switch spec := spec.(type) {
					case *ast.ValueSpec:
						// const or var
						for _, id := range spec.Names {
							if id.Name == member {
								return decl.Tok, id.Pos(), nil
							}
						}
					case *ast.TypeSpec:
						if spec.Name.Name == member {
							return token.TYPE, spec.Name.Pos(), nil
						}
					case *ast.AliasSpec:
						if spec.Name.Name == member {
							return decl.Tok, spec.Name.Pos(), nil
						}
					}
				}
			case *ast.FuncDecl:
				if decl.Recv == nil && decl.Name.Name == member {
					return token.FUNC, decl.Name.Pos(), nil
				}
			}
		}
	}

	return 0, token.NoPos, fmt.Errorf("couldn't find declaration of %s in %q", member, pkg)
}
Esempio n. 10
0
// applyGlobalAdvice applies any global scoped advice
// if advice has already been placed in this pkg than we skip
// no support for sub-pkgs yet
// FIXME
func (w *Weave) applyGlobalAdvice(fname string, stuff string) string {
	if w.appliedGlobal {
		return stuff
	}

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {
		aspect := w.aspects[i]
		if aspect.pointkut.def != "*" {
			continue
		}

		before_advice := aspect.advize.before
		after_advice := aspect.advize.after

		w.appliedGlobal = true

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		// endOfImport returns the line after the import statement
		// used to add global advice
		// just a guess here - doubt this is ordered
		ilen := len(file.Imports)
		s := file.Imports[ilen-1].End()
		ei := fset.Position(s).Line + 1

		if before_advice != "" {
			rout = w.writeAtLine(fname, ei, before_advice)
		}

		if after_advice != "" {
			rout = w.writeAtLine(fname, ei, after_advice)
		}

	}

	if len(importsNeeded) > 0 {
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout
}
Esempio n. 11
0
File: main.go Progetto: jonfk/gore
func (s *Session) reset() error {
	source, err := s.source(false)
	if err != nil {
		return err
	}

	file, err := parser.ParseFile(s.Fset, "gore_session.go", source, parser.Mode(0))
	if err != nil {
		return err
	}

	s.File = file
	s.mainBody = s.mainFunc().Body

	return nil
}
Esempio n. 12
0
func TestDeadCode(t *testing.T) {
	// We'll use dead code detection to verify the CFG.

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
	if err != nil {
		t.Fatal(err)
	}
	for _, decl := range f.Decls {
		if decl, ok := decl.(*ast.FuncDecl); ok {
			g := New(decl.Body, mayReturn)

			// Mark blocks reachable from entry.
			live := make(map[*Block]bool)
			var visit func(*Block)
			visit = func(b *Block) {
				if !live[b] {
					live[b] = true
					for _, succ := range b.Succs {
						visit(succ)
					}
				}
			}
			visit(g.Blocks[0])

			// Print statements in unreachable blocks
			// (in order determined by builder).
			var buf bytes.Buffer
			for _, b := range g.Blocks {
				if !live[b] {
					for _, n := range b.Nodes {
						fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
					}
				}
			}

			// Check that the result contains "dead" at least once but not "live".
			if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
				bytes.Contains(buf.Bytes(), []byte("live")) {
				t.Errorf("unexpected dead statements in function %s:\n%s",
					decl.Name.Name,
					&buf)
				t.Logf("control flow graph:\n%s", g.Format(fset))
			}
		}
	}
}
Esempio n. 13
0
File: main.go Progetto: jonfk/gore
// importFile adds external golang file to goRun target to use its function
func (s *Session) importFile(src []byte) error {
	// Don't need to same directory
	tmp, err := ioutil.TempFile(filepath.Dir(s.FilePath), "gore_extarnal_")
	if err != nil {
		return err
	}

	ext := tmp.Name() + ".go"

	f, err := parser.ParseFile(s.Fset, ext, src, parser.Mode(0))
	if err != nil {
		return err
	}

	// rewrite to package main
	f.Name.Name = "main"

	// remove func main()
	for i, decl := range f.Decls {
		if funcDecl, ok := decl.(*ast.FuncDecl); ok {
			if isNamedIdent(funcDecl.Name, "main") {
				f.Decls = append(f.Decls[0:i], f.Decls[i+1:]...)
				// main() removed from this file, we may have to
				// remove some unsed import's
				quickfix.QuickFix(s.Fset, []*ast.File{f})
				break
			}
		}
	}

	out, err := os.Create(ext)
	if err != nil {
		return err
	}
	defer out.Close()

	err = printer.Fprint(out, s.Fset, f)
	if err != nil {
		return err
	}

	debugf("import file: %s", ext)
	s.ExtraFilePaths = append(s.ExtraFilePaths, ext)
	s.ExtraFiles = append(s.ExtraFiles, f)

	return nil
}
Esempio n. 14
0
func doDir(name string) {
	notests := func(info os.FileInfo) bool {
		if !info.IsDir() && strings.HasSuffix(info.Name(), ".go") &&
			(!strings.HasSuffix(info.Name(), "_test.go") || *includeTests) {
			return true
		}
		return false
	}
	fs := token.NewFileSet()
	pkgs, err := parser.ParseDir(fs, name, notests, parser.Mode(0))
	if err != nil {
		errorf("%s", err)
		return
	}
	for _, pkg := range pkgs {
		doPackage(fs, pkg)
	}
}
Esempio n. 15
0
File: main.go Progetto: jonfk/gore
// fixImports formats and adjusts imports for the current AST.
func (s *Session) fixImports() error {

	var buf bytes.Buffer
	err := printer.Fprint(&buf, s.Fset, s.File)
	if err != nil {
		return err
	}

	formatted, err := imports.Process("", buf.Bytes(), nil)
	if err != nil {
		return err
	}

	s.File, err = parser.ParseFile(s.Fset, "", formatted, parser.Mode(0))
	if err != nil {
		return err
	}
	s.mainBody = s.mainFunc().Body

	return nil
}
Esempio n. 16
0
File: main.go Progetto: jonfk/gore
func NewSession() (*Session, error) {
	var err error

	s := &Session{
		Fset: token.NewFileSet(),
		Types: &types.Config{
			Packages: make(map[string]*types.Package),
		},
	}

	s.FilePath, err = tempFile()
	if err != nil {
		return nil, err
	}

	var initialSource string
	for _, pp := range printerPkgs {
		_, err := types.DefaultImport(s.Types.Packages, pp.path)
		if err == nil {
			initialSource = fmt.Sprintf(initialSourceTemplate, pp.path, pp.code)
			break
		}
		debugf("could not import %q: %s", pp.path, err)
	}

	if initialSource == "" {
		return nil, fmt.Errorf(`Could not load pretty printing package (even "fmt"; something is wrong)`)
	}

	s.File, err = parser.ParseFile(s.Fset, "gore_session.go", initialSource, parser.Mode(0))
	if err != nil {
		return nil, err
	}

	s.mainBody = s.mainFunc().Body

	return s, nil
}
Esempio n. 17
0
// NewSession initiates a new REPL
func NewSession() (*Session, error) {

	s := &Session{
		Fset: token.NewFileSet(),
		Types: &types.Config{
			Importer: importer.Default(),
		},
	}

	var err error
	s.FilePath, err = tempFile()
	if err != nil {
		return nil, err
	}

	var initialSource string
	for _, pp := range printerPkgs {
		_, err := importer.Default().Import(pp.path)
		if err == nil {
			initialSource = fmt.Sprintf(initialSourceTemplate, pp.path, pp.code)
			break
		}
		debugf("could not import %q: %s", pp.path, err)
	}
	if initialSource == "" {
		return nil, fmt.Errorf("Could not load pretty printing package")
	}

	s.File, err = parser.ParseFile(s.Fset, "gophernotes_session.go", initialSource, parser.Mode(0))
	if err != nil {
		return nil, err
	}

	s.mainBody = s.mainFunc().Body

	return s, nil
}
Esempio n. 18
0
File: main.go Progetto: billf/gore
func (s *Session) evalStmt(in string) error {
	src := fmt.Sprintf("package P; func F() { %s }", in)
	f, err := parser.ParseFile(s.Fset, "stmt.go", src, parser.Mode(0))
	if err != nil {
		return err
	}

	enclosingFunc := f.Scope.Lookup("F").Decl.(*ast.FuncDecl)
	stmts := enclosingFunc.Body.List

	if len(stmts) > 0 {
		debugf("evalStmt :: %s", showNode(s.Fset, stmts))
		lastStmt := stmts[len(stmts)-1]
		// print last assigned/defined values
		if assign, ok := lastStmt.(*ast.AssignStmt); ok {
			vs := []ast.Expr{}
			for _, v := range assign.Lhs {
				if !isNamedIdent(v, "_") {
					vs = append(vs, v)
				}
			}
			if len(vs) > 0 {
				printLastValues := &ast.ExprStmt{
					X: &ast.CallExpr{
						Fun:  ast.NewIdent(printerName),
						Args: vs,
					},
				}
				stmts = append(stmts, printLastValues)
			}
		}
	}

	s.appendStatements(stmts...)

	return nil
}
Esempio n. 19
0
// applySetJP applies any advice for set joinpoints
func (w *Weave) applySetJP(fname string, stuff string) string {

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {

		aspect := w.aspects[i]
		if !aspect.pointkut.isSet() {
			continue
		}

		pk := aspect.pointkut.def

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		linecnt := 0

		for _, decl := range file.Decls {
			fn, ok := decl.(*ast.FuncDecl)
			if !ok {
				continue
			}

			for x := 0; x < len(fn.Body.List); x++ {
				begin := 0
				after := 0

				as, ok2 := fn.Body.List[x].(*ast.SendStmt)
				if !ok2 {

					// look for assignment
					//*ast.AssignStmt
					as, ok3 := fn.Body.List[x].(*ast.AssignStmt)
					if !ok3 {
						continue
					}

					// no multiple-return support yet
					blah := as.Lhs[0].(*ast.Ident).Name

					if pk != blah {
						continue
					}

					begin = fset.Position(as.Pos()).Line - 1
					after = fset.Position(as.End()).Line + 1

				} else {
					// look for channel
					as3, ok3 := as.Chan.(*ast.Ident)
					if !ok3 {
						continue
					}

					if as3.Name != pk {
						continue
					}

					begin = fset.Position(as.Pos()).Line - 1
					after = fset.Position(as.End()).Line + 1

				}

				// figure out type

				//				begin := fset.Position(as.Pos()).Line - 1
				//				after := fset.Position(as.End()).Line + 1

				before_advice := aspect.advize.before
				after_advice := aspect.advize.after

				if before_advice != "" {
					rout = w.writeAtLine(fname, begin+linecnt, before_advice)
					linecnt += strings.Count(before_advice, "\n") + 1
				}

				if after_advice != "" {
					rout = w.writeAtLine(fname, after+linecnt-1, after_advice)

					linecnt += strings.Count(after_advice, "\n") + 1
				}

			}
		}

	}

	if len(importsNeeded) > 0 {
		// add any imports for this piece of advice
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout
}
Esempio n. 20
0
// parse parses src, which was read from filename,
// as a Go source file or statement list.
func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) {
	parserMode := parser.Mode(0)
	if opt.Comments {
		parserMode |= parser.ParseComments
	}
	if opt.AllErrors {
		parserMode |= parser.AllErrors
	}

	// Try as whole source file.
	file, err := parser.ParseFile(fset, filename, src, parserMode)
	if err == nil {
		return file, nil, nil
	}
	// If the error is that the source file didn't begin with a
	// package line and we accept fragmented input, fall through to
	// try as a source fragment.  Stop and return on any other error.
	if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") {
		return nil, nil, err
	}

	// If this is a declaration list, make it a source file
	// by inserting a package clause.
	// Insert using a ;, not a newline, so that the line numbers
	// in psrc match the ones in src.
	psrc := append([]byte("package main;"), src...)
	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
	if err == nil {
		// If a main function exists, we will assume this is a main
		// package and leave the file.
		if containsMainFunc(file) {
			return file, nil, nil
		}

		adjust := func(orig, src []byte) []byte {
			// Remove the package clause.
			// Gofmt has turned the ; into a \n.
			src = src[len("package main\n"):]
			return matchSpace(orig, src)
		}
		return file, adjust, nil
	}
	// If the error is that the source file didn't begin with a
	// declaration, fall through to try as a statement list.
	// Stop and return on any other error.
	if !strings.Contains(err.Error(), "expected declaration") {
		return nil, nil, err
	}

	// If this is a statement list, make it a source file
	// by inserting a package clause and turning the list
	// into a function body.  This handles expressions too.
	// Insert using a ;, not a newline, so that the line numbers
	// in fsrc match the ones in src.
	fsrc := append(append([]byte("package p; func _() {"), src...), '}')
	file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
	if err == nil {
		adjust := func(orig, src []byte) []byte {
			// Remove the wrapping.
			// Gofmt has turned the ; into a \n\n.
			src = src[len("package p\n\nfunc _() {"):]
			src = src[:len(src)-len("}\n")]
			// Gofmt has also indented the function body one level.
			// Remove that indent.
			src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
			return matchSpace(orig, src)
		}
		return file, adjust, nil
	}

	// Failed, and out of options.
	return nil, nil, err
}
Esempio n. 21
0
// applyCallAdvice applies call advice before/after a call
// around advice is currently hacked in via applyAroundAdvice
func (w *Weave) applyCallAdvice(fname string, stuff string) string {

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {
		aspect := w.aspects[i]
		if aspect.pointkut.kind != 1 {
			continue
		}

		linecnt := 0

		pk := aspect.pointkut.def
		before_advice := aspect.advize.before
		after_advice := aspect.advize.after

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		// look for call expressions - call joinpoints

		// bend keeps track of tailing binaryExprs
		// if a call-expression's end is not > then we use this
		lastbinstart := 0
		lastbinend := 0

		ast.Inspect(file, func(n ast.Node) bool {

			switch stmt := n.(type) {

			case *ast.CompositeLit:
				// log.Printf("found a composite lit\n")
				lbs := fset.Position(stmt.Lbrace).Line
				lbe := fset.Position(stmt.Rbrace).Line

				if lbs > lastbinstart {
					lastbinstart = lbs
				}

				if lbe > lastbinend {
					lastbinend = lbe
				}

			case *ast.BinaryExpr:
				// child nodes traversed in DFS - so we want the max
				// it's ok when newer nodes re-write this out of scope
				lbs := fset.Position(stmt.X.Pos()).Line
				lbe := fset.Position(stmt.Y.Pos()).Line

				if lbs > lastbinstart {
					lastbinstart = lbs
				}

				if lbe > lastbinend {
					lastbinend = lbe
				}

				// log.Printf("last bin start %d, last bin end %d", lastbinstart, lastbinend)

			case *ast.CallExpr:
				var name string
				switch x := stmt.Fun.(type) {
				case *ast.Ident:
					name = x.Name
				case *ast.SelectorExpr:
					name = x.Sel.Name
				default:
					name = "WRONG"
				}

				pk = strings.Split(pk, "(")[0]

				// fixme - hack - we need support for identifying call
				// expressions w/pkgs
				if strings.Contains(pk, ".") {
					pk = strings.Split(pk, ".")[1]
				}

				// are we part of a bigger expression?
				// if so grab our lines so we don't erroneously set them
				if (string(name) != pk) && (len(stmt.Args) > 1) {
					// log.Printf("found comma..")
					// child nodes traversed in DFS - so we want the max
					// it's ok when newer nodes re-write this out of scope
					lbs := fset.Position(stmt.Lparen).Line
					lbe := fset.Position(stmt.Rparen).Line
					// log.Printf("lbs: %d, lbe: %d\n", lbs, lbe)
					if lbs > 0 {
						//lastbinstart {
						lastbinstart = lbs
					}

					if lbe > lastbinend {
						lastbinend = lbe
					}

				}

				if string(name) == pk {

					begin := fset.Position(stmt.Lparen).Line
					end := fset.Position(stmt.Rparen).Line
					// log.Printf("found expression on line %d\n", begin)
					//log.Printf("lbs: %d, lbe: %d\n", lbs, lbe)

					// adjust begin
					if begin > lastbinend {
						// log.Printf("using this funcs start %d", begin)
					} else {
						if lastbinstart < begin {
							begin = lastbinstart
						}
						// log.Printf("using binexps' start %d", begin)
					}

					if end > lastbinend {
						// log.Printf("using this funcs begin %d", begin)
					} else {
						if lastbinstart < begin {
							begin = lastbinstart
						}
						// log.Printf("using binexps' start %d", begin)
					}

					// adjust end
					if lastbinend > end {
						end = lastbinend
					}

					if before_advice != "" {
						rout = w.writeAtLine(fname, begin+linecnt-1, before_advice)
						// log.Println(rout)
						// log.Printf("writing at line %d", begin+linecnt-1)
						linecnt += strings.Count(before_advice, "\n") + 1
					}

					if after_advice != "" {
						rout = w.writeAtLine(fname, end+linecnt, after_advice)
						// log.Println(rout)
						// log.Printf("writing at line %d", end+linecnt)

						linecnt += strings.Count(after_advice, "\n") + 1
					}

					for t := 0; t < len(aspect.importz); t++ {
						importsNeeded = append(importsNeeded, aspect.importz[t])
					}

				}
			}

			return true
		})

	}

	if len(importsNeeded) > 0 {
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout

}
Esempio n. 22
0
func (s *Session) evalStmt(in string, noPrint bool) error {
	src := fmt.Sprintf("package P; func F() { %s }", in)
	f, err := parser.ParseFile(s.Fset, "stmt.go", src, parser.Mode(0))
	if err != nil {
		debugf("stmt :: err = %s", err)

		// try to import this as a proxy function and correct for any imports
		appendForImport := `package main


			`

		f, err := os.Create(string(filepath.Dir(s.FilePath)) + "/func_proxy.go")
		if err != nil {
			return err
		}

		_, err = f.Write([]byte(appendForImport + in))
		if err != nil {
			return err
		}
		f.Close()

		b := new(bytes.Buffer)
		cmd := exec.Command("goimports", "-w", string(filepath.Dir(s.FilePath))+"/func_proxy.go")
		cmd.Stdout = b
		cmd.Stderr = b
		err = cmd.Run()
		if err != nil {
			err = errors.New(b.String())
			return err
		}

		functproxy, err := ioutil.ReadFile(string(filepath.Dir(s.FilePath)) + "/func_proxy.go")
		if err != nil {
			return err
		}

		if err = s.importFile(functproxy); err != nil {
			errorf("%s", err.Error())
			if _, ok := err.(scanner.ErrorList); ok {
				return ErrContinue
			}
		}

	}

	enclosingFunc := f.Scope.Lookup("F").Decl.(*ast.FuncDecl)
	stmts := enclosingFunc.Body.List

	if len(stmts) > 0 {

		debugf("evalStmt :: %s", showNode(s.Fset, stmts))
		lastStmt := stmts[len(stmts)-1]

		// print last assigned/defined values
		if !noPrint {
			if assign, ok := lastStmt.(*ast.AssignStmt); ok {
				vs := []ast.Expr{}
				for _, v := range assign.Lhs {
					if !isNamedIdent(v, "_") {
						vs = append(vs, v)
					}
				}
				if len(vs) > 0 {
					printLastValues := &ast.ExprStmt{
						X: &ast.CallExpr{
							Fun:  ast.NewIdent(printerName),
							Args: vs,
						},
					}
					stmts = append(stmts, printLastValues)
				}
			}
		}
	}

	s.appendStatements(stmts...)

	return nil
}
Esempio n. 23
0
// applyGetJP applies any advice for get joinpoints
func (w *Weave) applyGetJP(fname string, stuff string) string {

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {

		aspect := w.aspects[i]
		if !aspect.pointkut.isGet() {
			continue
		}

		pk := aspect.pointkut.def

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		linecnt := 0

		for _, decl := range file.Decls {
			fn, ok := decl.(*ast.FuncDecl)
			if !ok {
				continue
			}

			for x := 0; x < len(fn.Body.List); x++ {
				as, ok2 := fn.Body.List[x].(*ast.ExprStmt)
				if !ok2 {
					continue
				}

				blah, ok3 := as.X.(*ast.CallExpr)
				if !ok3 {
					continue
				}

				// can either be a unary || a ident (so far)
				fn2, ok4 := blah.Args[0].(*ast.UnaryExpr)
				if !ok4 {
					// look for ident

					fn3, ok5 := blah.Args[0].(*ast.Ident)
					if !ok5 {
						continue
					}

					if pk != fn3.Name {
						continue
					}

				} else {
					// look for channel

					blah2, ok4 := fn2.X.(*ast.Ident)
					if !ok4 {
						continue
					}

					if pk != blah2.Name {
						continue
					}
				}

				begin := fset.Position(as.Pos()).Line - 1
				after := fset.Position(as.End()).Line + 1

				before_advice := aspect.advize.before
				after_advice := aspect.advize.after

				if before_advice != "" {
					rout = w.writeAtLine(fname, begin+linecnt, before_advice)
					linecnt += strings.Count(before_advice, "\n") + 1
				}

				if after_advice != "" {
					rout = w.writeAtLine(fname, after+linecnt-1, after_advice)

					linecnt += strings.Count(after_advice, "\n") + 1
				}

			}

		}
	}

	if len(importsNeeded) > 0 {
		// add any imports for this piece of advice
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout
}
Esempio n. 24
0
// applyWithinJP applies any advice for within joinpoints
// right now this expects both 'before && after'
func (w *Weave) applyWithinJP(fname string, stuff string) string {

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {
		aspect := w.aspects[i]
		if !aspect.pointkut.isWithin() {
			continue
		}

		pk := aspect.pointkut.def

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		linecnt := 0

		// look for function declarations - ala look for execution
		// joinpoints
		for _, decl := range file.Decls {
			fn, ok := decl.(*ast.FuncDecl)
			if !ok {
				continue
			}

			fpk := strings.Split(pk, "(")[0]

			// if function name missing --> wildcard
			if fpk == "" {
				fpk = fn.Name.Name
			}

			if fn.Name.Name == fpk && containArgs(pk, fn.Type.Params.List) {

				wb := WithinBlock{
					name:          fn.Name.Name,
					fname:         fname,
					stmts:         fn.Body.List,
					linecnt:       linecnt,
					importsNeeded: importsNeeded,
					aspect:        aspect,
					fset:          fset,
				}

				rout, linecnt, importsNeeded = wb.iterateBodyStatements(w)

			}
		}

	}

	if len(importsNeeded) > 0 {
		// add any imports for this piece of advice
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout
}
Esempio n. 25
0
// CreateTestMainPackage creates and returns a synthetic "testmain"
// package for the specified package if it defines tests, benchmarks or
// executable examples, or nil otherwise.  The new package is named
// "main" and provides a function named "main" that runs the tests,
// similar to the one that would be created by the 'go test' tool.
//
// Subsequent calls to prog.AllPackages include the new package.
// The package pkg must belong to the program prog.
func (prog *Program) CreateTestMainPackage(pkg *Package) *Package {
	if pkg.Prog != prog {
		log.Fatal("Package does not belong to Program")
	}

	// Template data
	var data struct {
		Pkg                         *Package
		Tests, Benchmarks, Examples []*Function
		Main                        *Function
		Go18                        bool
	}
	data.Pkg = pkg

	// Enumerate tests.
	data.Tests, data.Benchmarks, data.Examples, data.Main = FindTests(pkg)
	if data.Main == nil &&
		data.Tests == nil && data.Benchmarks == nil && data.Examples == nil {
		return nil
	}

	// Synthesize source for testmain package.
	path := pkg.Pkg.Path() + "$testmain"
	tmpl := testmainTmpl
	if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil {
		// In Go 1.8, testing.MainStart's first argument is an interface, not a func.
		data.Go18 = types.IsInterface(testingPkg.Func("MainStart").Signature.Params().At(0).Type())
	} else {
		// The program does not import "testing", but FindTests
		// returned non-nil, which must mean there were Examples
		// but no Test, Benchmark, or TestMain functions.

		// We'll simply call them from testmain.main; this will
		// ensure they don't panic, but will not check any
		// "Output:" comments.
		// (We should not execute an Example that has no
		// "Output:" comment, but it's impossible to tell here.)
		tmpl = examplesOnlyTmpl
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, data); err != nil {
		log.Fatalf("internal error expanding template for %s: %v", path, err)
	}
	if false { // debugging
		fmt.Fprintln(os.Stderr, buf.String())
	}

	// Parse and type-check the testmain package.
	f, err := parser.ParseFile(prog.Fset, path+".go", &buf, parser.Mode(0))
	if err != nil {
		log.Fatalf("internal error parsing %s: %v", path, err)
	}
	conf := types.Config{
		DisableUnusedImportCheck: true,
		Importer:                 importer{pkg},
	}
	files := []*ast.File{f}
	info := &types.Info{
		Types:      make(map[ast.Expr]types.TypeAndValue),
		Defs:       make(map[*ast.Ident]types.Object),
		Uses:       make(map[*ast.Ident]types.Object),
		Implicits:  make(map[ast.Node]types.Object),
		Scopes:     make(map[ast.Node]*types.Scope),
		Selections: make(map[*ast.SelectorExpr]*types.Selection),
	}
	testmainPkg, err := conf.Check(path, prog.Fset, files, info)
	if err != nil {
		log.Fatalf("internal error type-checking %s: %v", path, err)
	}

	// Create and build SSA code.
	testmain := prog.CreatePackage(testmainPkg, files, info, false)
	testmain.SetDebugMode(false)
	testmain.Build()
	testmain.Func("main").Synthetic = "test main function"
	testmain.Func("init").Synthetic = "package initializer"
	return testmain
}
Esempio n. 26
0
// applyExecutionJP applies any advice for execution joinpoints
func (w *Weave) applyExecutionJP(fname string, stuff string) string {

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {
		aspect := w.aspects[i]
		if aspect.pointkut.kind != 2 {
			continue
		}

		pk := aspect.pointkut.def

		before_advice := aspect.advize.before
		after_advice := aspect.advize.after

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		linecnt := 0

		// look for function declarations - ala look for execution
		// joinpoints
		for _, decl := range file.Decls {
			fn, ok := decl.(*ast.FuncDecl)
			if !ok {
				continue
			}

			fpk := strings.Split(pk, "(")[0]

			// if function name missing --> wildcard
			if fpk == "" {
				fpk = fn.Name.Name
			}

			if fn.Name.Name == fpk && containArgs(pk, fn.Type.Params.List) {

				// begin line
				begin := fset.Position(fn.Body.Lbrace).Line
				after := fset.Position(fn.Body.Rbrace).Line

				// until this is refactored - any lines we add in our
				// advice need to be accounted for w/begin

				if before_advice != "" {
					rout = w.writeAtLine(fname, begin+linecnt, before_advice)
					linecnt += strings.Count(before_advice, "\n") + 1
				}

				if after_advice != "" {
					if fn.Type.Results != nil {
						lcnt := strings.Count(after_advice, "\n") + 1
						rout = w.writeAtLine(fname, after+linecnt-1-lcnt, after_advice)
					} else {
						rout = w.writeAtLine(fname, after+linecnt-1, after_advice)
					}

					linecnt += strings.Count(after_advice, "\n") + 1
				}

				for t := 0; t < len(aspect.importz); t++ {
					importsNeeded = append(importsNeeded, aspect.importz[t])
				}

			}
		}

	}

	if len(importsNeeded) > 0 {
		// add any imports for this piece of advice applyExecutionJP
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout
}
Esempio n. 27
0
// applyDeclarationJP applies any advice for set joinpoints
// currently expects a channel type
// need some extra help here to be agnostic
// maybe some helper functions that determine what type it is and
// associated meta-data about it
//
// this is currently a TEST - it only works for specific channels at the
// moment
func (w *Weave) applyDeclarationJP(fname string, stuff string) string {

	rout := stuff

	importsNeeded := []string{}

	for i := 0; i < len(w.aspects); i++ {

		aspect := w.aspects[i]
		if !aspect.pointkut.isDeclaration() {
			continue
		}

		pk := aspect.pointkut.def

		fset := token.NewFileSet()
		file, err := parser.ParseFile(fset, fname, rout, parser.Mode(0))
		if err != nil {
			w.flog.Println("Failed to parse source: %s", err.Error())
		}

		linecnt := 0

		for _, decl := range file.Decls {
			fn, ok := decl.(*ast.FuncDecl)
			if !ok {
				continue
			}

			for x := 0; x < len(fn.Body.List); x++ {
				as, ok2 := fn.Body.List[x].(*ast.AssignStmt)
				if !ok2 {
					continue
				}

				// ll-cool-j
				blah := as.Lhs[0].(*ast.Ident).Name

				if pk != blah {
					continue
				}

				// figure out type

				// ll-cool-j once again
				if len(as.Rhs[0].(*ast.CallExpr).Args) == 2 {
					_, k := (as.Rhs[0].(*ast.CallExpr).Args[0]).(*ast.ChanType)
					if !k {
						continue
					}

					r2, k2 := (as.Rhs[0].(*ast.CallExpr).Args[1]).(*ast.BasicLit)
					if !k2 {
						continue
					}

					avar := AbstractVar{
						Kind: "channel",
						Val:  r2.Value,
					}

					begin := fset.Position(as.Pos()).Line - 1
					after := fset.Position(as.End()).Line + 1

					// this needs to do var subsitution like we do for
					// within advice
					//
					// before_advice := formatAdvice(aspect.advize.before, mName)
					// after_advice := formatAdvice(aspect.advize.after, mName)

					before_advice := aspect.advize.before
					after_advice := aspect.advize.after

					if before_advice != "" {
						rout = w.writeAtLine(fname, begin+linecnt, before_advice)
						linecnt += strings.Count(before_advice, "\n") + 1
					}

					if after_advice != "" {
						rout = w.writeAtLine(fname, after+linecnt-1, after_advice)

						linecnt += strings.Count(after_advice, "\n") + 1
					}

					mAvars = append(mAvars, avar)

				}

			}
		}

	}

	if len(importsNeeded) > 0 {
		// add any imports for this piece of advice
		rout = w.writeMissingImports(fname, rout, importsNeeded)
	}

	return rout
}