コード例 #1
0
ファイル: godef.go プロジェクト: hualet/golang-workspace
// findIdentifier looks for an identifier at byte-offset searchpos
// inside the parsed source represented by node.
// If it is part of a selector expression, it returns
// that expression rather than the identifier itself.
//
// As a special case, if it finds an import
// spec, it returns ImportSpec.
//
func findIdentifier(f *ast.File, searchpos int) ast.Node {
	ec := make(chan ast.Node)
	go func() {
		visit := func(n ast.Node) bool {
			var startPos token.Pos
			switch n := n.(type) {
			case *ast.Ident:
				startPos = n.NamePos
			case *ast.SelectorExpr:
				startPos = n.Sel.NamePos
			case *ast.ImportSpec:
				startPos = n.Pos()
			default:
				return true
			}
			start := types.FileSet.Position(startPos).Offset
			end := start + int(n.End()-startPos)
			if start <= searchpos && searchpos <= end {
				ec <- n
				runtime.Goexit()
			}
			return true
		}
		ast.Walk(FVisitor(visit), f)
		ec <- nil
	}()
	ev := <-ec
	if ev == nil {
		fail("no identifier found")
	}
	return ev
}
コード例 #2
0
ファイル: godef.go プロジェクト: zxpbenson/rog-go
// findIdentifier looks for an identifier at byte-offset searchpos
// inside the parsed source represented by node.
// If it is part of a selector expression, it returns
// that expression rather than the identifier itself.
//
// As a special case, if it finds an import
// spec, it returns ImportSpec.
//
func findIdentifier(f *ast.File, searchpos int) ast.Node {
	ec := make(chan ast.Node)
	found := func(startPos, endPos token.Pos) bool {
		start := types.FileSet.Position(startPos).Offset
		end := start + int(endPos-startPos)
		return start <= searchpos && searchpos <= end
	}
	go func() {
		var visit func(ast.Node) bool
		visit = func(n ast.Node) bool {
			var startPos token.Pos
			switch n := n.(type) {
			default:
				return true
			case *ast.Ident:
				startPos = n.NamePos
			case *ast.SelectorExpr:
				startPos = n.Sel.NamePos
			case *ast.ImportSpec:
				startPos = n.Pos()
			case *ast.StructType:
				// If we find an anonymous bare field in a
				// struct type, its definition points to itself,
				// but we actually want to go elsewhere,
				// so assume (dubiously) that the expression
				// works globally and return a new node for it.
				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 found(id.NamePos, id.End()) {
							ec <- parseExpr(f.Scope, id.Name)
							runtime.Goexit()
						}
					}
				}
				return true
			}
			if found(startPos, n.End()) {
				ec <- n
				runtime.Goexit()
			}
			return true
		}
		ast.Walk(FVisitor(visit), f)
		ec <- nil
	}()
	ev := <-ec
	if ev == nil {
		fail("no identifier found")
	}
	return ev
}
コード例 #3
0
ファイル: dscan.go プロジェクト: rwl/gorf
func ScanCmd(args []string) (err error) {
	ScanAllForImports(LocalRoot)
	for _, path := range args {
		pkg := LocalImporter(path)

		ast.Walk(DepthWalker(0), pkg)
	}
	return
}
コード例 #4
0
ファイル: types.go プロジェクト: zxpbenson/rog-go
// constainsNode returns true if x is found somewhere
// inside node.
func containsNode(node, x ast.Node) (found bool) {
	ast.Walk(funcVisitor(func(n ast.Node) bool {
		if !found {
			found = n == x
		}
		return !found
	}),
		node)
	return
}
コード例 #5
0
ファイル: util.go プロジェクト: rwl/gorf
func GetUniqueIdent(files []*ast.File, candidate string) (id string) {
	ic := make(IdentCollector)
	for _, file := range files {
		ast.Walk(ic, file)
	}

	id = candidate
	for i := 0; ic[id]; i++ {
		id = fmt.Sprintf("%s_%d", candidate, i)
	}

	return
}
コード例 #6
0
ファイル: singlemover.go プロジェクト: rwl/gorf
func (this *SingleMover) CollectNameObjs(name string) (found bool) {
	for _, file := range this.pkg.Files {
		fdl := DeclFinder{oldname: name}
		ast.Walk(&fdl, file)
		if fdl.Obj != nil {
			found = true

			this.moveNodes[fdl.Node] = fdl.Obj

			mf := MethodFinder{
				Receiver: fdl.Obj,
				NodeObjs: make(map[ast.Node]*ast.Object),
			}

			ast.Walk(&mf, this.pkg)

			for node, obj := range mf.NodeObjs {
				this.moveNodes[node] = obj
			}
		}
	}
	return
}
コード例 #7
0
ファイル: move.go プロジェクト: rwl/gorf
func (this ListImportWalker) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.SelectorExpr:
		ast.Walk(this, n.X)
		//skip n.Sel, we don't need to import for it
		return nil
	case *ast.Ident:
		obj, typ := types.ExprType(n, LocalImporter)
		if is, ok := typ.Node.(*ast.ImportSpec); ok {
			this[obj] = is
		}
	}

	return this
}
コード例 #8
0
ファイル: types_test.go プロジェクト: zxpbenson/rog-go
func TestOneFile(t *testing.T) {
	code, offsetMap := translateSymbols(testCode)
	//fmt.Printf("------------------- {%s}\n", code)
	f, err := parser.ParseFile(FileSet, "xx.go", code, 0, ast.NewScope(parser.Universe))
	if err != nil {
		t.Fatalf("parse failed: %v", err)
	}
	v := make(identVisitor)
	go func() {
		ast.Walk(v, f)
		close(v)
	}()
	for e := range v {
		testExpr(t, FileSet, e, offsetMap)
	}
}
コード例 #9
0
ファイル: types_test.go プロジェクト: zxpbenson/rog-go
func (v identVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.Ident:
		if strings.HasPrefix(n.Name, prefix) {
			v <- n
		}
		return nil
	case *ast.SelectorExpr:
		ast.Walk(v, n.X)
		if strings.HasPrefix(n.Sel.Name, prefix) {
			v <- n
		}
		return nil
	}
	return v
}
コード例 #10
0
ファイル: scan.go プロジェクト: rwl/gorf
//Look at the imports, and build up ImportedBy
func ScanForImports(path string) (err error) {
	sourcefiles, _ := filepath.Glob(filepath.Join(path, "*.go"))
	dirpkgs, err := parser.ParseFiles(AllSourceTops, sourcefiles, parser.ImportsOnly)

	if err != nil {
		fmt.Println(err)
	}

	//take the first non-main. otherwise, main is ok.
	var prime *ast.Package
	for name, pkg := range dirpkgs {
		prime = pkg
		if name != "main" {
			break
		}
	}

	if prime == nil {
		return
	}

	PackageTops[path] = prime

	is := make(ImportScanner)

	ast.Walk(is, prime)

	if v, ok := is["."]; !v && ok {
		return MakeErr("gorf can not deal with unnamed import in '%s'", path)
	}

	for path, _ := range is {
		if strings.HasPrefix(path, ".") {
			return MakeErr("gorf can not deal with relative import in '%s'", path)
		}
	}

	for imp := range is {
		ImportedBy[imp] = append(ImportedBy[imp], path)
	}

	return
}
コード例 #11
0
ファイル: move.go プロジェクト: rwl/gorf
func MoveCmd(args []string) (err error) {
	if len(args) < 2 {
		return MakeErr("Usage: gorf [flags] move <old path> <new path> [<name>+]")
	}

	oldpath, newpath := filepath.Clean(args[0]), filepath.Clean(args[1])

	if oldpath == newpath {
		return MakeErr("Old path and new path are the same")
	}

	err = ScanAllForImports(LocalRoot)
	if err != nil {
		return
	}

	PreloadImportedBy(oldpath)

	defer func() {
		if err != nil {
			UndoCmd([]string{})
		}
	}()

	if PackageTops[oldpath] == nil {
		return MakeErr("Old path %s has no local package", oldpath)
	}

	if PackageTops[newpath] != nil {
		return MakeErr("New path %s already has a package (did you mean to merge?)", newpath)
	}

	pkg := LocalImporter(oldpath)

	if len(args) >= 3 {
		err = MoveSingle(oldpath, newpath, args[2:])
		return
	}

	os.MkdirAll(filepath.Join(LocalRoot, newpath), 0755)
	for fpath := range pkg.Files {
		_, base := filepath.Split(fpath)
		npath := filepath.Join(LocalRoot, newpath, base)
		_ = npath
		err = MoveSource(fpath, npath)
		if err != nil {
			return
		}
	}

	for _, ip := range ImportedBy[QuotePath(oldpath)] {
		ipkg := LocalImporter(ip)
		for fpath, file := range ipkg.Files {
			pcw := PathChangeWalker{OldPath: oldpath, NewPath: newpath}
			ast.Walk(&pcw, file)
			if pcw.Updated {

				err = RewriteSource(fpath, file)
				if err != nil {
					return
				}
			}
		}
	}

	return
}
コード例 #12
0
ファイル: types_test.go プロジェクト: zxpbenson/rog-go
func checkExprs(t *testing.T, pkg *ast.File, importer Importer) {
	var visit astVisitor
	stopped := false
	visit = func(n ast.Node) bool {
		if stopped {
			return false
		}
		mustResolve := false
		var e ast.Expr
		switch n := n.(type) {
		case *ast.ImportSpec:
			// If the file imports a package to ".", abort
			// because we don't support that (yet).
			if n.Name != nil && n.Name.Name == "." {
				stopped = true
				return false
			}
			return true

		case *ast.FuncDecl:
			// add object for init functions
			if n.Recv == nil && n.Name.Name == "init" {
				n.Name.Obj = ast.NewObj(ast.Fun, "init")
			}
			return true

		case *ast.Ident:
			if n.Name == "_" {
				return false
			}
			e = n
			mustResolve = true

		case *ast.KeyValueExpr:
			// don't try to resolve the key part of a key-value
			// because it might be a map key which doesn't
			// need resolving, and we can't tell without being
			// complicated with types.
			ast.Walk(visit, n.Value)
			return false

		case *ast.SelectorExpr:
			ast.Walk(visit, n.X)
			e = n
			mustResolve = true

		case *ast.File:
			for _, d := range n.Decls {
				ast.Walk(visit, d)
			}
			return false

		case ast.Expr:
			e = n

		default:
			return true
		}
		defer func() {
			if err := recover(); err != nil {
				t.Fatalf("panic (%v) on %T", err, e)
				//t.Fatalf("panic (%v) on %v at %v\n", err, e, FileSet.Position(e.Pos()))
			}
		}()
		obj, _ := ExprType(e, importer)
		if obj == nil && mustResolve {
			t.Errorf("no object for %v(%p, %T) at %v\n", e, e, e, FileSet.Position(e.Pos()))
		}
		return false
	}
	ast.Walk(visit, pkg)
}
コード例 #13
0
ファイル: singlemover.go プロジェクト: rwl/gorf
func MoveSingle(oldpath, newpath string, names []string) (err error) {
	for _, name := range names {
		if !IsLegalIdentifier(name) {
			return MakeErr("Name %s is not a legal identifier", name)
		}
	}

	var sm SingleMover

	pkg := LocalImporter(oldpath)
	sm.pkg = pkg
	sm.oldpath = oldpath
	sm.newpath = newpath

	moveNodes := make(map[ast.Node]*ast.Object)
	sm.moveNodes = moveNodes
	moveObjs := make(map[*ast.Object]ast.Node)
	sm.moveObjs = moveObjs
	allObjs := make(AllDeclFinder)
	sm.allObjs = allObjs

	//get all top level decl objs
	ast.Walk(allObjs, pkg)

	//find the nodes we want to move
	for _, name := range names {
		if !sm.CollectNameObjs(name) {
			return MakeErr("Unable to find %s in '%s'", name, oldpath)
		}
	}
	for node, obj := range moveNodes {
		moveObjs[obj] = node
	}

	//the objs in remainingObjs are not being moved to the new package
	remainingObjs := make(map[*ast.Object]bool)
	sm.remainingObjs = remainingObjs
	for obj := range sm.allObjs {
		if _, ok := sm.moveObjs[obj]; !ok {
			sm.remainingObjs[obj] = true
		}
	}

	//get a list of objects that are unexported (and therefore if they
	//are referenced elsewhere, the move cannot happen)
	sm.unexportedObjs = make(map[*ast.Object]bool)
	sm.CollectUnexportedObjs()

	err = sm.CreateNewSource()
	if err != nil {
		return
	}

	//identify locations in pkg source files that need to now change
	err = sm.RemoveUpdatePkg()
	if err != nil {
		return
	}

	//make changes in packages that import this one
	err = sm.UpdateOther()
	if err != nil {
		return
	}
	return
}
コード例 #14
0
ファイル: pkg.go プロジェクト: rwl/gorf
func PkgCmd(args []string) (err error) {
	if len(args) != 2 {
		return MakeErr("Usage: gorf [flags] pkg <path> <new name>")
	}

	path, newname := filepath.Clean(args[0]), args[1]

	if !IsLegalIdentifier(newname) {
		return MakeErr("New name %s is not a legal identifier", newname)
	}

	err = ScanAllForImports(LocalRoot)
	if err != nil {
		return
	}

	PreloadImportedBy(path)

	defer func() {
		if err != nil {
			UndoCmd([]string{})
		}
	}()

	if PackageTops[path] == nil {
		return MakeErr("No local package found in %s", path)
	}

	pkg := LocalImporter(path)

	oldname := pkg.Name

	for fpath, file := range pkg.Files {
		file.Name.Name = newname
		err = RewriteSource(fpath, file)
		if err != nil {
			return
		}
	}

	for _, ip := range ImportedBy[QuotePath(path)] {
		ipkg := LocalImporter(ip)
		if ipkg == nil {
			return MakeErr("Problem getting package in %s", ip)
		}
		for fpath, file := range ipkg.Files {
			uniqueName := GetUniqueIdent([]*ast.File{file}, newname)

			if uniqueName != newname {
				fmt.Printf("In %s: possible conflict with %s, using %s instead\n", fpath, newname, uniqueName)
			}

			pc := PkgChanger{
				path:    path,
				oldname: oldname,
				newname: uniqueName,
				pkgname: newname,
			}
			ast.Walk(&pc, file)
			if pc.Updated {
				RewriteSource(fpath, file)
			}
		}
	}

	return
}
コード例 #15
0
ファイル: singlemover.go プロジェクト: rwl/gorf
func (this *SingleMover) RemoveUpdatePkg() (err error) {
	for fpath, file := range this.pkg.Files {

		urw := ReferenceWalker{
			UnexportedObjs:       this.unexportedObjs,
			SkipNodes:            this.moveNodes,
			MoveObjs:             this.moveObjs,
			SkipNodeParents:      make(map[ast.Node]ast.Node),
			GoodReferenceParents: make(map[ast.Node]ast.Node),
			BadReferences:        new([]ast.Node),
		}
		ast.Walk(&urw, file)

		if len(*urw.BadReferences) != 0 {
			fmt.Printf("Cannot move some objects:\n")
			for node := range this.moveNodes {
				printer.Fprint(os.Stdout, token.NewFileSet(), node)
				fmt.Println()
			}
			fmt.Println("Unexported objects referenced:")
			for _, node := range *urw.BadReferences {
				position := AllSources.Position(node.Pos())
				fmt.Printf("At %v ", position)
				printer.Fprint(os.Stdout, token.NewFileSet(), node)
				fmt.Println()
			}
			return MakeErr("Objects to be moved in '%s' contains unexported objects referenced elsewhere in the package", this.oldpath)
		}

		removedStuff := false

		// remove the old definitions
		for node, parent := range urw.SkipNodeParents {
			removedStuff = true
			//fmt.Printf("%T %v\n", parent, parent)

			switch pn := parent.(type) {
			case *ast.File:
				for i, n := range pn.Decls {
					if n == node {
						if len(pn.Decls) > 1 {
							pn.Decls[i], pn.Decls[len(pn.Decls)-1] = pn.Decls[len(pn.Decls)-1], pn.Decls[i]
						}
						pn.Decls = pn.Decls[:len(pn.Decls)-1]
						break
					}
				}
			case *ast.GenDecl:
				for i, n := range pn.Specs {
					if n == node {
						if pn.Lparen == 0 {
							pn.Lparen = n.Pos()
							pn.Rparen = n.End()
						}
						if len(pn.Specs) > 1 {
							pn.Specs[i], pn.Specs[len(pn.Specs)-1] = pn.Specs[len(pn.Specs)-1], pn.Specs[i]
						}
						pn.Specs = pn.Specs[:len(pn.Specs)-1]
						break
					}
				}
			default:
				return MakeErr("Unanticipated parent type: %T", pn)
			}
		}

		//strip out imports that are unnecessary because things are no longer here
		if removedStuff {
			for _, file := range this.pkg.Files {
				iuc := make(ImportUseCollector)
				ast.Walk(iuc, file)

				ast.Walk(ImportFilterWalker(iuc), file)
			}
		}

		//if this file refernces things that are moving, import the new package
		if len(urw.GoodReferenceParents) != 0 {
			if this.referenceBack {
				return MakeErr("Moving objects from %s would create a cycle", this.oldpath)
			}

			newpkgname := GetUniqueIdent([]*ast.File{file}, this.pkg.Name)

			//construct the import
			is := &ast.ImportSpec{
				Name: &ast.Ident{Name: newpkgname},
				Path: &ast.BasicLit{
					Kind:  token.STRING,
					Value: QuotePath(this.newpath),
				},
			}

			gd := &ast.GenDecl{
				Tok:   token.IMPORT,
				Specs: []ast.Spec{is},
			}

			//stick it in there
			file.Decls = append([]ast.Decl{gd}, file.Decls...)

			//change the old references to talk about the new package, using our unique name
			for node, parent := range urw.GoodReferenceParents {
				getSel := func(idn *ast.Ident) *ast.SelectorExpr {
					return &ast.SelectorExpr{
						X: &ast.Ident{
							Name:    newpkgname,
							NamePos: idn.NamePos,
						},
						Sel: idn,
					}
				}

				switch p := parent.(type) {
				case *ast.CallExpr:
					if idn, ok := node.(*ast.Ident); ok {
						p.Fun = getSel(idn)
					} else {

						return MakeErr("CallExpr w/ unexpected type %T\n", node)
					}
				case *ast.AssignStmt:
					for i, x := range p.Lhs {
						if x == node {
							if idn, ok := x.(*ast.Ident); ok {
								p.Lhs[i] = getSel(idn)
							}
						}
					}
					for i, x := range p.Rhs {
						if x == node {
							if idn, ok := x.(*ast.Ident); ok {
								p.Rhs[i] = getSel(idn)
							}
						}
					}
				case *ast.StarExpr:
					if p.X == node {
						if idn, ok := p.X.(*ast.Ident); ok {
							p.X = getSel(idn)
						}
					}
				default:
					return MakeErr("Unexpected local parent %T\n", parent)
				}
			}
		}

		if removedStuff {
			err = RewriteSource(fpath, file)
			if err != nil {
				return
			}
		}

	}
	return
}
コード例 #16
0
ファイル: singlemover.go プロジェクト: rwl/gorf
func (this *SingleMover) UpdateOther() (err error) {
	for _, path := range ImportedBy[QuotePath(this.oldpath)] {
		opkg := LocalImporter(path)

		for fpath, file := range opkg.Files {
			rw := ReferenceWalker{
				UnexportedObjs:       make(map[*ast.Object]bool),
				MoveObjs:             this.moveObjs,
				SkipNodes:            make(map[ast.Node]*ast.Object),
				SkipNodeParents:      make(map[ast.Node]ast.Node),
				GoodReferenceParents: make(map[ast.Node]ast.Node),
				BadReferences:        &[]ast.Node{},
			}
			ast.Walk(&rw, file)

			if len(rw.GoodReferenceParents) == 0 {
				continue
			}

			newpkgname := GetUniqueIdent([]*ast.File{file}, this.pkg.Name)

			//construct the import
			nis := &ast.ImportSpec{
				Name: &ast.Ident{Name: newpkgname},
				Path: &ast.BasicLit{
					Kind:  token.STRING,
					Value: QuotePath(this.newpath),
				},
			}

			ngd := &ast.GenDecl{
				Tok:   token.IMPORT,
				Specs: []ast.Spec{nis},
			}
			file.Decls = append([]ast.Decl{ngd}, file.Decls...)

			for node, parent := range rw.GoodReferenceParents {
				getSel := func(sel *ast.SelectorExpr) *ast.SelectorExpr {
					obj, _ := types.ExprType(sel.X, LocalImporter)
					if obj.Kind == ast.Pkg {
						return &ast.SelectorExpr{
							X: &ast.Ident{
								Name:    newpkgname,
								NamePos: sel.X.Pos(),
							},
							Sel: sel.Sel,
						}
					}
					return sel
				}

				switch p := parent.(type) {
				case *ast.CallExpr:
					if sel, ok := node.(*ast.SelectorExpr); ok {

						p.Fun = getSel(sel)
					} else {

						return MakeErr("CallExpr w/ unexpected type %T\n", node)
					}
				case *ast.AssignStmt:
					for i, x := range p.Lhs {
						if x == node {
							if sel, ok := x.(*ast.SelectorExpr); ok {
								p.Lhs[i] = getSel(sel)
							}
						}
					}
					for i, x := range p.Rhs {
						if x == node {
							if sel, ok := x.(*ast.SelectorExpr); ok {
								p.Rhs[i] = getSel(sel)
							}
						}
					}
				case *ast.ValueSpec:
					if node == p.Type {
						if sel, ok := p.Type.(*ast.SelectorExpr); ok {
							p.Type = getSel(sel)
						}
					}
					for i, x := range p.Values {
						if x == node {
							if sel, ok := x.(*ast.SelectorExpr); ok {
								p.Values[i] = getSel(sel)
							}
						}
					}
				case *ast.StarExpr:
					if p.X == node {
						if sel, ok := p.X.(*ast.SelectorExpr); ok {
							p.X = getSel(sel)
						}
					}
				default:
					printer.Fprint(os.Stdout, AllSources, parent)
					return MakeErr("Unexpected remote parent %T\n", parent)
				}
			}

			//now that we've renamed some references, do we still need to import oldpath?
			oc := ObjChecker{
				Objs: this.remainingObjs,
			}
			ast.Walk(&oc, file)
			if !oc.Found {
				ast.Walk(&ImportRemover{nil, this.oldpath}, file)
			}

			err = RewriteSource(fpath, file)
			if err != nil {
				return
			}
		}
	}

	return
}
コード例 #17
0
ファイル: sym.go プロジェクト: juanman2/dot-emacs
// IterateSyms calls visitf for each identifier in the given file.  If
// visitf returns false, the iteration stops.  If visitf changes
// info.Ident.Name, the file is added to ctxt.ChangedFiles.
func (ctxt *Context) IterateSyms(f *ast.File, visitf func(info *Info) bool) {
	var visit astVisitor
	ok := true
	local := false // TODO set to true inside function body
	visit = func(n ast.Node) bool {
		if !ok {
			return false
		}
		switch n := n.(type) {
		case *ast.ImportSpec:
			// If the file imports a package to ".", abort
			// because we don't support that (yet).
			if n.Name != nil && n.Name.Name == "." {
				ctxt.logf(n.Pos(), "import to . not supported")
				ok = false
				return false
			}
			return true

		case *ast.FuncDecl:
			// add object for init functions
			if n.Recv == nil && n.Name.Name == "init" {
				n.Name.Obj = ast.NewObj(ast.Fun, "init")
			}
			if n.Recv != nil {
				ast.Walk(visit, n.Recv)
			}
			var e ast.Expr = n.Name
			if n.Recv != nil {
				// It's a method, so we need to synthesise a
				// selector expression so that visitExpr doesn't
				// just see a blank name.
				if len(n.Recv.List) != 1 {
					ctxt.logf(n.Pos(), "expected one receiver only!")
					return true
				}
				e = &ast.SelectorExpr{
					X:   n.Recv.List[0].Type,
					Sel: n.Name,
				}
			}
			ok = ctxt.visitExpr(f, e, false, visitf)
			local = true
			ast.Walk(visit, n.Type)
			if n.Body != nil {
				ast.Walk(visit, n.Body)
			}
			local = false
			return false

		case *ast.Ident:
			ok = ctxt.visitExpr(f, n, local, visitf)
			return false

		case *ast.KeyValueExpr:
			// don't try to resolve the key part of a key-value
			// because it might be a map key which doesn't
			// need resolving, and we can't tell without being
			// complicated with types.
			ast.Walk(visit, n.Value)
			return false

		case *ast.SelectorExpr:
			ast.Walk(visit, n.X)
			ok = ctxt.visitExpr(f, n, local, visitf)
			return false

		case *ast.File:
			for _, d := range n.Decls {
				ast.Walk(visit, d)
			}
			return false
		}

		return true
	}
	ast.Walk(visit, f)
}
コード例 #18
0
ファイル: singlemover.go プロジェクト: rwl/gorf
func (this *SingleMover) CreateNewSource() (err error) {

	liw := make(ListImportWalker)
	for n := range this.moveNodes {
		ast.Walk(liw, n)
	}
	finalImports := make(map[*ast.ImportSpec]bool)
	for obj, is := range liw {
		if _, ok := this.moveObjs[obj]; !ok {
			finalImports[is] = true
		}
	}

	newfile := &ast.File{
		Name: &ast.Ident{Name: this.pkg.Name},
	}

	if len(finalImports) != 0 {
		for is := range finalImports {
			gdl := &ast.GenDecl{
				Tok:   token.IMPORT,
				Specs: []ast.Spec{is},
			}
			newfile.Decls = append(newfile.Decls, gdl)
		}
	}

	var sortedNodes NodeSorter

	for mn := range this.moveNodes {
		sortedNodes = append(sortedNodes, mn)
	}
	sort.Sort(sortedNodes)

	for _, mn := range sortedNodes {
		switch m := mn.(type) {
		case ast.Decl:
			newfile.Decls = append(newfile.Decls, m)
		case *ast.TypeSpec:
			gdl := &ast.GenDecl{
				Tok:   token.TYPE,
				Specs: []ast.Spec{m},
			}
			newfile.Decls = append(newfile.Decls, gdl)
		}
	}

	npf := ExprParentFinder{
		ExprParents: make(map[ast.Expr]ast.Node),
	}
	for n := range this.moveNodes {
		ast.Walk(&npf, n)
	}

	var pkgfiles []*ast.File
	for _, pkgfile := range this.pkg.Files {
		pkgfiles = append(pkgfiles, pkgfile)
	}
	oldPkgNewName := GetUniqueIdent(pkgfiles, this.pkg.Name)

	needOldImport := false

	this.referenceBack = false

	for expr, parent := range npf.ExprParents {
		obj, _ := types.ExprType(expr, LocalImporter)
		if _, ok := this.moveObjs[obj]; ok {
			continue
		}

		if _, ok := this.allObjs[obj]; !ok {
			continue
		}

		if !unicode.IsUpper([]rune(obj.Name)[0] /*utf8.NewString(obj.Name).At(0)*/) {
			position := AllSources.Position(expr.Pos())
			fmt.Printf("At %v ", position)
			printer.Fprint(os.Stdout, token.NewFileSet(), expr)
			fmt.Println()
			err = MakeErr("Can't move code that references unexported objects")
			return
		}

		needOldImport = true
		this.referenceBack = true

		getSel := func(idn *ast.Ident) *ast.SelectorExpr {
			return &ast.SelectorExpr{
				X: &ast.Ident{
					Name:    oldPkgNewName,
					NamePos: idn.NamePos,
				},
				Sel: idn,
			}
		}

		switch p := parent.(type) {
		case *ast.CallExpr:
			if idn, ok := expr.(*ast.Ident); ok {
				p.Fun = getSel(idn)
			} else {
				err = MakeErr("CallExpr w/ unexpected type %T\n", expr)
				return
			}
		case *ast.AssignStmt:
			for i, x := range p.Lhs {
				if x == expr {
					if idn, ok := x.(*ast.Ident); ok {
						p.Lhs[i] = getSel(idn)
					}
				}
			}
			for i, x := range p.Rhs {
				if x == expr {
					if idn, ok := x.(*ast.Ident); ok {
						p.Rhs[i] = getSel(idn)
					}
				}
			}
		default:
			err = MakeErr("Unexpected parent %T\n", parent)
			return
		}
	}

	if needOldImport {
		is := &ast.ImportSpec{
			Name: &ast.Ident{Name: oldPkgNewName},
			Path: &ast.BasicLit{Value: QuotePath(this.oldpath)},
		}
		gdl := &ast.GenDecl{
			Tok:   token.IMPORT,
			Specs: []ast.Spec{is},
		}
		newfile.Decls = append([]ast.Decl{gdl}, newfile.Decls...)
	}

	err = os.MkdirAll(this.newpath, 0755)
	if err != nil {
		return
	}
	newSourcePath := filepath.Join(this.newpath, this.pkg.Name+".go")

	containedComments := make(CommentCollector)
	for node := range this.moveNodes {
		ast.Walk(containedComments, node)
	}

	for _, file := range this.pkg.Files {
		for i := len(file.Comments) - 1; i >= 0; i-- {
			cg := file.Comments[i]
			add := func() {
				newfile.Comments = append([]*ast.CommentGroup{cg}, newfile.Comments...)
				file.Comments[i] = file.Comments[len(file.Comments)-1]
				file.Comments = file.Comments[:len(file.Comments)-1]
			}
			if containedComments[cg] {
				add()
			} else {
				for node := range this.moveNodes {
					if node.Pos() <= cg.Pos() && node.End() >= cg.End() {
						add()
						break
					}
				}
			}
		}

	}
	err = NewSource(newSourcePath, newfile)
	if err != nil {
		return
	}

	return
}
コード例 #19
0
ファイル: rename.go プロジェクト: rwl/gorf
func RenameCmd(args []string) (err error) {
	if len(args) != 3 {
		return MakeErr("Usage: gorf [flags] rename <path> [<type>.]<old name> <new name>")
	}
	path, oldname, newname := filepath.Clean(args[0]), args[1], args[2]

	if oldnametoks := strings.SplitN(oldname, ".", 2); len(oldnametoks) == 2 {
		return FieldCmd([]string{path, oldnametoks[0], oldnametoks[1], newname})
	}

	if !IsLegalIdentifier(oldname) {
		return MakeErr("Old name %s is not a legal identifier", oldname)
	}
	if !IsLegalIdentifier(newname) {
		return MakeErr("New name %s is not a legal identifier", newname)
	}
	if oldname == newname {
		return MakeErr("Old name and new name are the same")
	}

	err = ScanAllForImports(LocalRoot)
	if err != nil {
		return
	}

	PreloadImportedBy(path)

	defer func() {
		if err != nil {
			UndoCmd([]string{})
		}
	}()

	if PackageTops[path] == nil {
		return MakeErr("No local package found in %s", path)
	}

	pkg := LocalImporter(path)

	updated := false

	var Obj *ast.Object

	for fpath, file := range pkg.Files {
		fdl := DeclFinder{oldname: oldname, newname: newname}
		ast.Walk(&fdl, file)

		if fdl.NameExists {
			return MakeErr("Name %s already exists", newname)
		}
		Obj = fdl.Obj

		if Obj != nil {
			updated = true
		}

		if updated {
			RenameInFile(file, newname, Obj)
			RewriteSource(fpath, file)
		}
	}

	if updated {
		err = RenameInAll(path, newname, Obj)
	}

	return
}
コード例 #20
0
ファイル: merge.go プロジェクト: rwl/gorf
func MergeCmd(args []string) (err error) {
	if len(args) != 2 {
		return MakeErr("Usage: gorf [flags] merge <old path> <new path>")
	}

	oldpath, newpath := filepath.Clean(args[0]), filepath.Clean(args[1])

	err = ScanAllForImports(LocalRoot)
	if err != nil {
		return
	}

	PreloadImportedBy(oldpath)

	defer func() {
		if err != nil {
			UndoCmd([]string{})
		}
	}()

	if PackageTops[oldpath] == nil {
		return MakeErr("Old path %s has no local package", oldpath)
	}

	if PackageTops[newpath] == nil {
		return MakeErr("New path %s has no local package", newpath)
	}

	oldpkg, newpkg := LocalImporter(oldpath), LocalImporter(newpath)

	// check for conflicts
	duplicates := false
	for name, oldobj := range oldpkg.Scope.Objects {
		if oldobj.Decl == nil {
			continue
		}
		if newobj, ok := newpkg.Scope.Objects[name]; ok && newobj.Decl != nil {

			duplicates = true

			fmt.Printf("Duplicate name %s\n", name)
			if oldNode, oldOk := oldobj.Decl.(ast.Node); oldOk {
				fmt.Printf(" %s\n", AllSources.Position(oldNode.Pos()))
			} else {
				fmt.Printf("%T\n", oldobj.Decl)
			}
			if newNode, newOk := newobj.Decl.(ast.Node); newOk {
				fmt.Printf(" %s\n", AllSources.Position(newNode.Pos()))
			} else {
				fmt.Printf("%T\n", newobj.Decl)
			}
		}
	}
	if duplicates {
		return MakeErr("Packages in '%s' and '%s' contain duplicate names", oldpath, newpath)
	}

	//move source files
	for fpath := range oldpkg.Files {
		_, fname := filepath.Split(fpath)
		npath := GetUniqueFilename(newpkg, filepath.Join(newpath, fname))

		err = MoveSource(fpath, npath)
		if err != nil {
			return
		}
	}

	//update imports
	for _, ipath := range ImportedBy[QuotePath(oldpath)] {
		pkg := LocalImporter(ipath)
		for fpath, file := range pkg.Files {
			ir := ImportRepath{
				OldName: oldpkg.Name,
				OldPath: oldpath,
				NewPath: newpath,
			}
			ast.Walk(&ir, file)
			if ir.Updated {
				err = RewriteSource(fpath, file)
				if err != nil {
					return
				}
			}
		}
	}

	return // MakeErr("not implemented yet")
}
コード例 #21
0
ファイル: field.go プロジェクト: rwl/gorf
func FieldCmd(args []string) (err error) {
	if len(args) != 4 {
		return MakeErr("Usage: gorf [flags] field <path> <type name> <old field name> <new field name>")
	}
	path, typename, oldname, newname := args[0], args[1], args[2], args[3]

	if !IsLegalIdentifier(typename) {
		return MakeErr("Type name %s is not a legal identifier", oldname)
	}
	if !IsLegalIdentifier(oldname) {
		return MakeErr("Old name %s is not a legal identifier", oldname)
	}
	if !IsLegalIdentifier(newname) {
		return MakeErr("New name %s is not a legal identifier", newname)
	}
	if oldname == newname {
		return MakeErr("Old name and new name are the same")
	}

	err = ScanAllForImports(LocalRoot)
	if err != nil {
		return
	}

	defer func() {
		if err != nil {
			UndoCmd([]string{})
		}
	}()

	pkg := LocalImporter(path)

	if pkg == nil {
		return MakeErr("No package found in %s", path)
	}

	updated := false

	var Obj *ast.Object

	for fpath, file := range pkg.Files {
		vdl := FieldDeclFinder{typename: typename, oldname: oldname, newname: newname}
		ast.Walk(&vdl, file)

		if vdl.NameExists {
			return MakeErr("Name %s already exists", newname)
		}
		Obj = vdl.Obj

		if vdl.Updated {
			updated = true
		}

		if updated {
			RenameInFile(file, newname, Obj)
			RewriteSource(fpath, file)
		}
	}

	if updated {
		err = RenameInAll(path, newname, Obj)
	}

	return
}
コード例 #22
0
ファイル: rename.go プロジェクト: rwl/gorf
func RenameInFile(file *ast.File, NewName string, Obj *ast.Object) bool {
	rw := RenameWalker{NewName: NewName, Obj: Obj}
	ast.Walk(&rw, file)
	return rw.Updated
}