Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support mutiple platform/architect dependent definitions #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go/ast/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type Object struct {
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil
Next *Object // corresponding platform dependent implement; or nil
}

// NewObj creates a new object of a given kind and name.
Expand Down
71 changes: 71 additions & 0 deletions go/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"fmt"
"regexp"
"strconv"
"strings"
)

// The mode parameter to the Parse* functions is a set of flags (or 0).
Expand Down Expand Up @@ -216,6 +217,11 @@ func (p *parser) declare1(decl ast.Node, scope *ast.Scope, kind ast.ObjKind, ide
}

func (p *parser) redeclared(ident *ast.Ident, prev *ast.Object, reason string) {
if f := p.fset.File(ident.Pos()); f.IsPlatformDependent() {
ident.Obj.Next = prev.Next
prev.Next = ident.Obj
return
}
if p.mode&DeclarationErrors == 0 {
return
}
Expand Down Expand Up @@ -2215,6 +2221,9 @@ func (p *parser) parseFile() *ast.File {
}
initialScope := p.topScope

// get platform dependent info from file name or build tag
platformDependent(p.file, p.comments)

// package clause
doc := p.leadComment
pos := p.expect(token.PACKAGE)
Expand Down Expand Up @@ -2248,3 +2257,65 @@ func (p *parser) parseFile() *ast.File {

return &ast.File{doc, pos, ident, decls, p.fileScope, nil, nil, p.comments}
}

var (
goosSuffixes = []string{
"_dragonfly.go",
"_netbsd.go",
"_openbsd.go",
"_solaris.go",
"_freebsd.go",
"_nacl.go",
"_android.go",
"_plan9.go",
"_darwin.go",
"_linux.go",
"_windows.go",
}
goarchSuffixes = []string{
"_amd64.go",
"_amd64p32.go",
"_arm.go",
"_ppc64.go",
"_ppc64le.go",
"_386.go",
}
buildPrefix = "// +build"
)

// platformDependent sets file is platform dependent or not
func platformDependent(f *token.File, cgs []*ast.CommentGroup) {
if f == nil {
return
}

//TODO: if file already has platform dependent info, return

// get from file name
fn := f.Name()
for _, os := range goosSuffixes {
if strings.HasSuffix(fn, os) {
f.PlatformDependent()
return
}
}
for _, arch := range goarchSuffixes {
if strings.HasSuffix(fn, arch) {
f.PlatformDependent()
return
}
}

// get from build constraint
if cgs == nil {
return
}
for _, cg := range cgs {
for _, c := range cg.List {
if strings.HasPrefix(c.Text, buildPrefix) {
f.PlatformDependent()
return
}
}
}
}
14 changes: 13 additions & 1 deletion go/token/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ type File struct {
// lines and infos are protected by set.mutex
lines []int
infos []lineInfo

platformDep bool // platformDep indicate whether this file is platform dependent
}

// Name returns the file name of file f as registered with AddFile.
Expand Down Expand Up @@ -314,6 +316,16 @@ func (f *File) info(offset int) (filename string, line, column int) {
return
}

// IsPlatformDependent returns whether this file platform dependent
func (f *File) IsPlatformDependent() bool {
return f.platformDep
}

// PlatformDependent sets this file is platform dependent (default is false)
func (f *File) PlatformDependent() {
f.platformDep = true
}

// A FileSet represents a set of source files.
// Methods of file sets are synchronized; multiple goroutines
// may invoke them concurrently.
Expand Down Expand Up @@ -366,7 +378,7 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
panic("illegal base or size")
}
// base >= s.base && size >= 0
f := &File{s, filename, base, size, []int{0}, nil}
f := &File{s, filename, base, size, []int{0}, nil, false}
base += size + 1 // +1 because EOF also has a position
if base < 0 {
panic("token.Pos offset overflow (> 2G of source code in file set)")
Expand Down
10 changes: 7 additions & 3 deletions go/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,20 @@ type Importer func(path string) *ast.Package
var FileSet = token.NewFileSet()

// GoPath is used by DefaultImporter to find packages.
var GoPath = []string{filepath.Join(os.Getenv("GOROOT"), "src", "pkg")}
var GoPath = []string{filepath.Join(os.Getenv("GOROOT"), "src")}

// DefaultGetPackage looks for the package; if it finds it,
// it parses and returns it. If no package was found, it returns nil.
func DefaultImporter(path string) *ast.Package {
build.Default.UseAllFiles = true
bpkg, err := build.Default.Import(path, "", 0)
if err != nil {
return nil
// Tolerant mutiple package err here due to ignore build constraint
if _, ok := err.(*build.MultiplePackageError); !ok {
return nil
}
}
pkgs, err := parser.ParseDir(FileSet, bpkg.Dir, isGoFile, 0)
pkgs, err := parser.ParseDir(FileSet, bpkg.Dir, isGoFile, parser.ParseComments)
if err != nil {
if Debug {
switch err := err.(type) {
Expand Down
16 changes: 12 additions & 4 deletions godef.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var aflag = flag.Bool("a", false, "print public type and member information")
var Aflag = flag.Bool("A", false, "print all type and members information")
var fflag = flag.String("f", "", "Go source filename")
var acmeFlag = flag.Bool("acme", false, "use current acme window")
var pflag = flag.Bool("p", false, "print all platform-dependent definitions")

func fail(s string, a ...interface{}) {
fmt.Fprint(os.Stderr, "godef: "+fmt.Sprintf(s, a...)+"\n")
Expand Down Expand Up @@ -86,7 +87,7 @@ func main() {
src = b
}
pkgScope := ast.NewScope(parser.Universe)
f, err := parser.ParseFile(types.FileSet, filename, src, 0, pkgScope)
f, err := parser.ParseFile(types.FileSet, filename, src, parser.ParseComments, pkgScope)
if f == nil {
fail("cannot parse %s: %v", filename, err)
}
Expand Down Expand Up @@ -218,8 +219,15 @@ func (o orderedObjects) Swap(i, j int) { o[i], o[j] = o[j], o[i] }

func done(obj *ast.Object, typ types.Type) {
defer os.Exit(0)
pos := types.FileSet.Position(types.DeclPos(obj))
fmt.Printf("%v\n", pos)
if *pflag {
for o := obj; o != nil; o = o.Next {
pos := types.FileSet.Position(types.DeclPos(o))
fmt.Printf("%v\n", pos)
}
} else {
pos := types.FileSet.Position(types.DeclPos(obj))
fmt.Printf("%v\n", pos)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what existing editor plugins will make of this... Perhaps we need a flag to ask for all definitions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have add a flag to trigger this.
BTW anyone who use editor with godef will adjust the plugin to support the multiple line output of godef, I indeed have done this...

}
if typ.Kind == ast.Bad || !*tflag {
return
}
Expand Down Expand Up @@ -317,7 +325,7 @@ func parseLocalPackage(filename string, src *ast.File, pkgScope *ast.Scope) (*as
pkgName(file) != pkg.Name {
continue
}
src, err := parser.ParseFile(types.FileSet, file, nil, 0, pkg.Scope)
src, err := parser.ParseFile(types.FileSet, file, nil, parser.ParseComments, pkg.Scope)
if err == nil {
pkg.Files[file] = src
}
Expand Down