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  }