1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
23 // main operation modes
24 pkgName = flag.String("p", "", "process only those files in package pkgName")
25 recursive = flag.Bool("r", false, "recursively process subdirectories")
26 verbose = flag.Bool("v", false, "verbose mode")
27 allErrors = flag.Bool("e", false, "print all (including spurious) errors")
30 printTrace = flag.Bool("trace", false, "print parse trace")
31 printAST = flag.Bool("ast", false, "print AST")
37 fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
42 func report(err error) {
43 scanner.PrintError(os.Stderr, err)
47 // parse returns the AST for the Go source src.
48 // The filename is for error reporting only.
49 // The result is nil if there were errors or if
50 // the file does not belong to the -p package.
51 func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
56 // ignore files with different package name
58 file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
63 if file.Name.Name != *pkgName {
65 fmt.Printf("\tignored (package %s)\n", file.Name.Name)
72 mode := parser.DeclarationErrors
74 mode |= parser.SpuriousErrors
79 file, err := parser.ParseFile(fset, filename, src, mode)
91 func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
92 files = make(map[string]*ast.File)
93 src, err := ioutil.ReadAll(os.Stdin)
98 const filename = "<standard input>"
99 if file := parse(fset, filename, src); file != nil {
100 files[filename] = file
105 func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
106 files = make(map[string]*ast.File)
107 for _, filename := range filenames {
108 src, err := ioutil.ReadFile(filename)
113 if file := parse(fset, filename, src); file != nil {
114 if files[filename] != nil {
115 report(errors.New(fmt.Sprintf("%q: duplicate file", filename)))
118 files[filename] = file
124 func isGoFilename(filename string) bool {
125 // ignore non-Go files
126 return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
129 func processDirectory(dirname string) {
130 f, err := os.Open(dirname)
135 filenames, err := f.Readdirnames(-1)
139 // continue since filenames may not be empty
141 for i, filename := range filenames {
142 filenames[i] = filepath.Join(dirname, filename)
144 processFiles(filenames, false)
147 func processFiles(filenames []string, allFiles bool) {
149 for _, filename := range filenames {
150 switch info, err := os.Stat(filename); {
153 case info.IsRegular():
154 if allFiles || isGoFilename(info.Name) {
155 filenames[i] = filename
158 case info.IsDirectory():
159 if allFiles || *recursive {
160 processDirectory(filename)
164 fset := token.NewFileSet()
165 processPackage(fset, parseFiles(fset, filenames[0:i]))
168 func processPackage(fset *token.FileSet, files map[string]*ast.File) {
169 // make a package (resolve all identifiers)
170 pkg, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe)
175 _, err = types.Check(fset, pkg)
185 if flag.NArg() == 0 {
186 fset := token.NewFileSet()
187 processPackage(fset, parseStdin(fset))
189 processFiles(flag.Args(), true)