github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/chore/godecl/godecl.go (about) 1 /* 2 Copyright 2022 The GoPlus Authors (goplus.org) 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package main 15 16 import ( 17 "flag" 18 "fmt" 19 "go/ast" 20 "go/importer" 21 "go/parser" 22 "go/token" 23 "go/types" 24 "io/fs" 25 "log" 26 "os" 27 "strings" 28 "unicode" 29 ) 30 31 var ( 32 internal = flag.Bool("i", false, "print internal declarations") 33 ) 34 35 func usage() { 36 fmt.Fprintf(os.Stderr, "Usage: godecl [-i] [source.go ...]\n") 37 flag.PrintDefaults() 38 } 39 40 func isDir(name string) bool { 41 if fi, err := os.Lstat(name); err == nil { 42 return fi.IsDir() 43 } 44 return false 45 } 46 47 func isPublic(name string) bool { 48 for _, c := range name { 49 return unicode.IsUpper(c) 50 } 51 return false 52 } 53 54 func main() { 55 flag.Parse() 56 if flag.NArg() < 1 { 57 usage() 58 return 59 } 60 initGoEnv() 61 62 var files []*ast.File 63 64 // Parse the input string, []byte, or io.Reader, 65 // recording position information in fset. 66 // ParseFile returns an *ast.File, a syntax tree. 67 fset := token.NewFileSet() 68 if infile := flag.Arg(0); isDir(infile) { 69 pkgs, first := parser.ParseDir(fset, infile, func(fi fs.FileInfo) bool { 70 return !strings.HasSuffix(fi.Name(), "_test.go") 71 }, 0) 72 check(first) 73 for name, pkg := range pkgs { 74 if !strings.HasSuffix(name, "_test") { 75 for _, f := range pkg.Files { 76 files = append(files, f) 77 } 78 break 79 } 80 } 81 } else { 82 for i, n := 0, flag.NArg(); i < n; i++ { 83 f, err := parser.ParseFile(fset, flag.Arg(i), nil, 0) 84 check(err) 85 files = append(files, f) 86 } 87 } 88 89 // A Config controls various options of the type checker. 90 // The defaults work fine except for one setting: 91 // we must specify how to deal with imports. 92 imp := importer.ForCompiler(fset, "source", nil) 93 conf := types.Config{ 94 Importer: imp, 95 IgnoreFuncBodies: true, 96 DisableUnusedImportCheck: true, 97 } 98 99 // Type-check the package containing only file f. 100 // Check returns a *types.Package. 101 pkg, err := conf.Check("", fset, files, nil) 102 check(err) 103 104 scope := pkg.Scope() 105 names := scope.Names() 106 for _, name := range names { 107 if *internal || isPublic(name) { 108 fmt.Println(scope.Lookup(name)) 109 } 110 } 111 } 112 113 func check(err error) { 114 if err != nil { 115 log.Panicln(err) 116 } 117 }