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 parseComments = flag.Bool("comments", false, "parse comments (ignored if -ast not set)")
31 printTrace = flag.Bool("trace", false, "print parse trace")
32 printAST = flag.Bool("ast", false, "print AST")
38 fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
43 func report(err error) {
44 scanner.PrintError(os.Stderr, err)
48 // parse returns the AST for the Go source src.
49 // The filename is for error reporting only.
50 // The result is nil if there were errors or if
51 // the file does not belong to the -p package.
52 func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
57 // ignore files with different package name
59 file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
64 if file.Name.Name != *pkgName {
66 fmt.Printf("\tignored (package %s)\n", file.Name.Name)
73 mode := parser.DeclarationErrors
75 mode |= parser.SpuriousErrors
77 if *parseComments && *printAST {
78 mode |= parser.ParseComments
83 file, err := parser.ParseFile(fset, filename, src, mode)
95 func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
96 files = make(map[string]*ast.File)
97 src, err := ioutil.ReadAll(os.Stdin)
102 const filename = "<standard input>"
103 if file := parse(fset, filename, src); file != nil {
104 files[filename] = file
109 func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
110 files = make(map[string]*ast.File)
111 for _, filename := range filenames {
112 src, err := ioutil.ReadFile(filename)
117 if file := parse(fset, filename, src); file != nil {
118 if files[filename] != nil {
119 report(errors.New(fmt.Sprintf("%q: duplicate file", filename)))
122 files[filename] = file
128 func isGoFilename(filename string) bool {
129 // ignore non-Go files
130 return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
133 func processDirectory(dirname string) {
134 f, err := os.Open(dirname)
139 filenames, err := f.Readdirnames(-1)
143 // continue since filenames may not be empty
145 for i, filename := range filenames {
146 filenames[i] = filepath.Join(dirname, filename)
148 processFiles(filenames, false)
151 func processFiles(filenames []string, allFiles bool) {
153 for _, filename := range filenames {
154 switch info, err := os.Stat(filename); {
158 if allFiles || *recursive {
159 processDirectory(filename)
162 if allFiles || isGoFilename(info.Name()) {
163 filenames[i] = filename
168 fset := token.NewFileSet()
169 processPackage(fset, parseFiles(fset, filenames[0:i]))
172 func processPackage(fset *token.FileSet, files map[string]*ast.File) {
173 // make a package (resolve all identifiers)
174 pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe)
179 _, err = types.Check(fset, pkg)
189 if flag.NArg() == 0 {
190 fset := token.NewFileSet()
191 processPackage(fset, parseStdin(fset))
193 processFiles(flag.Args(), true)