func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) { flags := flag.NewFlagSet(args[0], flag.ContinueOnError) flags.BoolVar(&checker.Blank, "blank", false, "if true, check for errors assigned to blank identifier") flags.BoolVar(&checker.Asserts, "asserts", false, "if true, check for ignored type assertion results") flags.BoolVar(&checker.Verbose, "verbose", false, "produce more verbose logging") tags := tagsFlag{} flags.Var(&tags, "tags", "space-separated list of build tags to include") ignorePkg := flags.String("ignorepkg", "", "comma-separated list of package paths to ignore") ignore := ignoreFlag(map[string]*regexp.Regexp{ "fmt": dotStar, }) flags.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+ " the regex is used to ignore names within pkg") if err := flags.Parse(args[1:]); err != nil { return nil, exitFatalError } checker.Tags = tags for _, pkg := range strings.Split(*ignorePkg, ",") { if pkg != "" { ignore[pkg] = dotStar } } checker.Ignore = ignore ctx := gotool.Context{ BuildContext: build.Default, } ctx.BuildContext.BuildTags = tags // ImportPaths normalizes paths and expands '...' return gotool.ImportPaths(flags.Args()), exitCodeOk }
func main() { ignore := ignoreFlag(map[string]*regexp.Regexp{ "fmt": dotStar, }) flag.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+ " the regex is used to ignore names within pkg") ignorePkg := flag.String("ignorepkg", "", "comma-separated list of package paths to ignore") blank := flag.Bool("blank", false, "if true, check for errors assigned to blank identifier") flag.Parse() for _, pkg := range strings.Split(*ignorePkg, ",") { if pkg != "" { ignore[pkg] = dotStar } } var pkgPaths = gotool.ImportPaths(flag.Args()) if err := errcheck.CheckPackages(pkgPaths, ignore, *blank); err != nil { if e, ok := err.(errcheck.UncheckedErrors); ok { for _, uncheckedError := range e.Errors { fmt.Println(uncheckedError) } os.Exit(1) } else if err == errcheck.ErrNoGoFiles { fmt.Fprintln(os.Stderr, err) os.Exit(0) } Fatalf("failed to check package: %s", err) } os.Exit(0) }
func main() { flag.Parse() importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { return } var conf loader.Config conf.Fset = fset for _, importPath := range importPaths { conf.Import(importPath) } prog, err := conf.Load() if err != nil { log.Fatal(err) } for _, pkg := range prog.InitialPackages() { for _, file := range pkg.Files { ast.Inspect(file, func(node ast.Node) bool { if s, ok := node.(*ast.StructType); ok { malign(node.Pos(), pkg.Types[s].Type.(*types.Struct)) } return true }) } } }
func main() { flag.Parse() username, ok := os.LookupEnv(teamcityAPIUserEnv) if !ok { log.Fatalf("teamcity API username environment variable %s is not set", teamcityAPIUserEnv) } password, ok := os.LookupEnv(teamcityAPIPasswordEnv) if !ok { log.Fatalf("teamcity API password environment variable %s is not set", teamcityAPIPasswordEnv) } importPaths := gotool.ImportPaths([]string{"github.com/cockroachdb/cockroach/..."}) client := teamcity.New("teamcity.cockroachdb.com", username, password) // Queue a build per configuration per package. for _, params := range []map[string]string{ {}, // uninstrumented {"env.GOFLAGS": "-race"}, {"env.TAGS": "deadlock"}, } { for _, importPath := range importPaths { params["env.PKG"] = importPath build, err := client.QueueBuild(*buildTypeID, *branchName, params) if err != nil { log.Fatalf("failed to create teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, err) } log.Printf("created teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, build) } } }
func runTC(queueBuildFn func(map[string]string)) { importPaths := gotool.ImportPaths([]string{"github.com/cockroachdb/cockroach/pkg/..."}) // Queue a build per configuration per package. for _, properties := range []map[string]string{ {}, // uninstrumented {"env.GOFLAGS": "-race"}, {tagsKey: "deadlock"}, } { if tags, ok := properties[tagsKey]; ok { properties[tagsKey] = strings.Join([]string{tags, stressTag}, " ") } else { properties[tagsKey] = stressTag } for _, propEvalKV := range []bool{true, false} { properties["env.COCKROACH_PROPOSER_EVALUATED_KV"] = strconv.FormatBool(propEvalKV) for _, importPath := range importPaths { properties["env.PKG"] = importPath queueBuildFn(properties) } } } }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s\n", usage) flag.PrintDefaults() os.Exit(2) } flag.Parse() var err error cwd, err = os.Getwd() if err != nil { cwd = "." } pkgs := flag.Args() if len(pkgs) == 0 { pkgs = []string{"."} } exitStatus := 0 pkgs = gotool.ImportPaths(pkgs) for _, pkg := range pkgs { if err := writeImports(pkg); err != nil { fmt.Fprintf(os.Stderr, "error: %v", err) exitStatus = 1 } } os.Exit(exitStatus) }
func main() { flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } for _, pkgPath := range importPaths { visitor := &visitor{ info: types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Selections: make(map[*ast.SelectorExpr]*types.Selection), }, m: make(map[types.Type]map[string]int), skip: make(map[types.Type]struct{}), } fset, astFiles := check.ASTFilesForPackage(pkgPath, *loadTestFiles) imp := importer.New() // Preliminary cgo support. imp.Config = importer.Config{UseGcFallback: true} config := types.Config{Import: imp.Import} var err error visitor.pkg, err = config.Check(pkgPath, fset, astFiles, &visitor.info) if err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", pkgPath, err) continue } for _, f := range astFiles { ast.Walk(visitor, f) } for t := range visitor.m { if _, skip := visitor.skip[t]; skip { continue } for fieldName, v := range visitor.m[t] { if !*reportExported && ast.IsExported(fieldName) { continue } if v == 0 { field, _, _ := types.LookupFieldOrMethod(t, false, visitor.pkg, fieldName) if fieldName == "XMLName" { if named, ok := field.Type().(*types.Named); ok && named.Obj().Pkg().Path() == "encoding/xml" { continue } } pos := fset.Position(field.Pos()) fmt.Printf("%s: %s:%d:%d: %s.%s\n", pkgPath, pos.Filename, pos.Line, pos.Column, types.TypeString(t, nil), fieldName, ) exitStatus = 1 } } } } os.Exit(exitStatus) }
func main() { // TODO(kaneda): Add a commandline flag for specifying a target type. targetPkg := "github.com/cockroachdb/cockroach/roachpb" targetTypeName := "Error" if err := returncheck.Run(gotool.ImportPaths(os.Args[1:]), targetPkg, targetTypeName); err != nil { os.Exit(1) } }
func main() { if len(packages) == 0 { fmt.Fprintln(os.Stderr, "Need to specify at least one package to check.") flag.Usage() os.Exit(1) } if len(arguments)+len(returns) == 0 { fmt.Fprintln(os.Stderr, "Need at least one type to search for.") flag.Usage() os.Exit(1) } var typesToCheck []string typesToCheck = append(typesToCheck, arguments...) typesToCheck = append(typesToCheck, returns...) ctx := NewContext() funcs, errs := ctx.getFunctions(gotool.ImportPaths(packages)) listErrors(errs) signatures := make(map[string][]string) for _, fnc := range funcs { sig, ok := fnc.Type().(*types.Signature) if !ok { // Skipping over builtins continue } anyArg, allArg := checkTypes(sig.Params(), arguments) anyRet, allRet := checkTypes(sig.Results(), returns) if (!and && (anyArg || anyRet)) || (and && allArg && allRet) { prefix := "" if sig.Recv() != nil { prefix = fmt.Sprintf("(%s %s) ", noDot(sig.Recv().Name()), sig.Recv().Type().String()) } signatures[fnc.Pkg.Path()] = append(signatures[fnc.Pkg.Path()], fmt.Sprintf("%s%s(%s) (%s)", prefix, fnc.Name(), argsToString(sig.Params()), argsToString(sig.Results()))) } } for _, path := range sortedKeys(signatures) { sigs := signatures[path] fmt.Println(path + ":") for _, sig := range sigs { fmt.Println("\t" + sig) } fmt.Println() } }
func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) { flags := flag.NewFlagSet(args[0], flag.ContinueOnError) flags.BoolVar(&checker.Blank, "blank", false, "if true, check for errors assigned to blank identifier") flags.BoolVar(&checker.Asserts, "asserts", false, "if true, check for ignored type assertion results") flags.BoolVar(&checker.WithoutTests, "ignoretests", false, "if true, checking of _test.go files is disabled") flags.BoolVar(&checker.Verbose, "verbose", false, "produce more verbose logging") flags.BoolVar(&abspath, "abspath", false, "print absolute paths to files") tags := tagsFlag{} flags.Var(&tags, "tags", "space-separated list of build tags to include") ignorePkg := flags.String("ignorepkg", "", "comma-separated list of package paths to ignore") ignore := ignoreFlag(map[string]*regexp.Regexp{ "fmt": dotStar, }) flags.Var(ignore, "ignore", "[deprecated] comma-separated list of pairs of the form pkg:regex\n"+ " the regex is used to ignore names within pkg.") var excludeFile string flags.StringVar(&excludeFile, "exclude", "", "Path to a file containing a list of functions to exclude from checking") if err := flags.Parse(args[1:]); err != nil { return nil, exitFatalError } if excludeFile != "" { exclude := make(map[string]bool) fh, err := os.Open(excludeFile) if err != nil { fmt.Fprintf(os.Stderr, "Could not read exclude file: %s\n", err) return nil, exitFatalError } scanner := bufio.NewScanner(fh) for scanner.Scan() { exclude[scanner.Text()] = true } if err := scanner.Err(); err != nil { fmt.Fprintf(os.Stderr, "Could not read exclude file: %s\n", err) return nil, exitFatalError } checker.SetExclude(exclude) } checker.Tags = tags for _, pkg := range strings.Split(*ignorePkg, ",") { if pkg != "" { ignore[pkg] = dotStar } } checker.Ignore = ignore // ImportPaths normalizes paths and expands '...' return gotool.ImportPaths(flags.Args()), exitCodeOk }
// RemoveRepo removes go-gettable repo with no local changes (by moving it into trash). // importPathPattern must match exactly with the repo root. // For example, "github.com/user/repo/...". func RemoveRepo(importPathPattern string) error { // TODO: Use an official Go package for `go list` functionality whenever possible. importPaths := gotool.ImportPaths([]string{importPathPattern}) if len(importPaths) == 0 { return errors.New("no packages to remove") } var firstGoPackage *gist7480523.GoPackage for i, importPath := range importPaths { goPackage := gist7480523.GoPackageFromImportPath(importPath) if goPackage == nil { return errors.New("Import Path not found: " + importPath) } if goPackage.Bpkg.Goroot { return errors.New("can't remove packages from GOROOT") } goPackage.UpdateVcs() if goPackage.Dir.Repo == nil { return errors.New("can't get repo status") } if i == 0 { firstGoPackage = goPackage } else if firstGoPackage.Dir.Repo != goPackage.Dir.Repo { return errors.New("matched Go Packages span more than 1 repo: " + firstGoPackage.Dir.Repo.Vcs.RootPath() + " != " + goPackage.Dir.Repo.Vcs.RootPath()) } else if !strings.HasPrefix(goPackage.Bpkg.Dir, firstGoPackage.Dir.Repo.Vcs.RootPath()) { // TODO: This is probably not neccessary... return errors.New("Go Package not inside repo: " + goPackage.Bpkg.Dir + " doesn't have prefix " + firstGoPackage.Dir.Repo.Vcs.RootPath()) } } if repoImportPathPattern := gist7480523.GetRepoImportPathPattern(firstGoPackage.Dir.Repo.Vcs.RootPath(), firstGoPackage.Bpkg.SrcRoot); repoImportPathPattern != importPathPattern { return errors.New("importPathPattern not exact repo root match: " + importPathPattern + " != " + repoImportPathPattern) } firstGoPackage.UpdateVcsFields() cleanStatus := func(goPackage *gist7480523.GoPackage) bool { packageStatus := presenter(goPackage)[:4] return packageStatus == " " || packageStatus == " + " // Updates are okay to ignore. } if !cleanStatus(firstGoPackage) { return errors.New("non-clean status: " + presenter(firstGoPackage)) } err := trash.MoveTo(firstGoPackage.Dir.Repo.Vcs.RootPath()) return err // TODO: Clean up /pkg folder contents, if any, etc. }
func main() { flag.Parse() serverURL, ok := os.LookupEnv(teamcityServerURLEnv) if !ok { log.Fatalf("teamcity server URL environment variable %s is not set", teamcityServerURLEnv) } u, err := url.Parse(serverURL) if err != nil { log.Fatal(err) } username, ok := os.LookupEnv(teamcityAPIUserEnv) if !ok { log.Fatalf("teamcity API username environment variable %s is not set", teamcityAPIUserEnv) } password, ok := os.LookupEnv(teamcityAPIPasswordEnv) if !ok { log.Fatalf("teamcity API password environment variable %s is not set", teamcityAPIPasswordEnv) } importPaths := gotool.ImportPaths([]string{"github.com/cockroachdb/cockroach/pkg/..."}) client := teamcity.New(u.Host, username, password) // Queue a build per configuration per package. for _, params := range []map[string]string{ {}, // uninstrumented {"env.GOFLAGS": "-race"}, {tagsKey: "deadlock"}, } { if tags, ok := params[tagsKey]; ok { params[tagsKey] = strings.Join([]string{tags, stressTag}, " ") } else { params[tagsKey] = stressTag } for _, propEvalKV := range []bool{true, false} { params["env.COCKROACH_PROPOSER_EVALUATED_KV"] = strconv.FormatBool(propEvalKV) for _, importPath := range importPaths { params["env.PKG"] = importPath build, err := client.QueueBuild(*buildTypeID, *branchName, params) if err != nil { log.Fatalf("failed to create teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, err) } log.Printf("created teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, build) } } } }
func main() { flag.Parse() exitStatus = 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } for _, pkgPath := range importPaths { visitor := &visitor{pkgPath: pkgPath} fset, astFiles := check.ASTFilesForPackage(pkgPath, false) visitor.fset = fset for _, f := range astFiles { ast.Walk(visitor, f) } } os.Exit(exitStatus) }
func expandPackages(spec []string) ([]string, error) { // expand "..." paths := gotool.ImportPaths(spec) var r []string for _, path := range paths { pkg, err := build.Import(path, ".", 0) if _, ok := err.(*build.NoGoError); ok { // directory with no Go source files in it continue } if err != nil { return nil, err } if pkg.ImportPath == "" { return nil, fmt.Errorf("no import path found: %v", path) } r = append(r, pkg.ImportPath) } return r, nil }
func main() { dotStar := regexp.MustCompile(".*") ignore := ignoreFlag(make(map[string]*regexp.Regexp)) flag.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+ " the regex is used to ignore names within pkg") ignorePkg := flag.String("ignorepkg", "", "comma-separated list of package paths to ignore") blank := flag.Bool("blank", false, "if true, check for errors assigned to blank identifier") flag.Parse() for _, pkg := range strings.Split(*ignorePkg, ",") { if pkg != "" { ignore[pkg] = dotStar } } if _, ok := ignore["fmt"]; !ok { ignore["fmt"] = dotStar } var exitStatus int for _, pkgPath := range gotool.ImportPaths(flag.Args()) { if err := errcheck.CheckPackage(pkgPath, ignore, *blank); err != nil { if e, ok := err.(errcheck.UncheckedErrors); ok { for _, uncheckedError := range e.Errors { fmt.Println(uncheckedError) } exitStatus = 1 continue } else if err == errcheck.ErrNoGoFiles { fmt.Fprintln(os.Stderr, err) continue } Fatalf("failed to check package %s: %s", pkgPath, err) } } os.Exit(exitStatus) }
func main() { flag.Usage = func() { os.Stderr.WriteString(helpMessage) flag.PrintDefaults() os.Exit(2) } flag.Parse() pkgs := flag.Args() if len(pkgs) == 0 { pkgs = []string{"."} } if d, err := os.Getwd(); err != nil { log.Fatalf("cannot get working directory: %v", err) } else { cwd = d } pkgs = gotool.ImportPaths(pkgs) allPkgs := make(map[string][]string) for _, pkg := range pkgs { if err := findImports(pkg, allPkgs); err != nil { log.Fatalf("cannot find imports from %q: %v", pkg, err) } } result := make([]string, 0, len(allPkgs)) for name := range allPkgs { result = append(result, name) } sort.Strings(result) for _, r := range result { if *from { sort.Strings(allPkgs[r]) fmt.Printf("%s %s\n", r, strings.Join(allPkgs[r], " ")) } else { fmt.Println(r) } } }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s\n", usage) flag.PrintDefaults() os.Exit(2) } flag.Parse() if *revFile != "" { if flag.NArg() != 0 { flag.Usage() } update(*revFile) } else { pkgs := flag.Args() if len(pkgs) == 0 { pkgs = []string{"."} } pkgs = gotool.ImportPaths(pkgs) for _, info := range list(pkgs, *testDeps) { fmt.Println(info) } } os.Exit(exitCode) }
func multibuild(packages []string) (error, int) { // parse the names of the paths/packages provided on the command-line pkgs := gotool.ImportPaths(packages) // parse the main package: we need the package name and the path mainpkg, err := build.Import(pkgs[0], ".", 0) if err != nil { return fmt.Errorf("unable to import main package %s: %s", pkgs[0], err), -2 } // create the linker file in the main package directory, so that it will be // compiled and linked with the main package when we `go build` is invoked // the linker file is a go file in the same package of the main package that // imports all additional packages (normally for their side-effects) tmpFile, err := ioutil.TempFile(mainpkg.Dir, "pluggo") if err != nil { return fmt.Errorf("unable to create temporary file: %s", err), -3 } fmt.Fprintf(tmpFile, "package %s\n", mainpkg.Name) for _, pkgname := range pkgs[1:] { fmt.Fprintf(tmpFile, "import _ \"%s\"\n", pkgname) } tmpFile.Close() os.Rename(tmpFile.Name(), tmpFile.Name()+".go") defer os.Remove(tmpFile.Name() + ".go") // run go build on the main package output, err := exec.Command("go", "build", packages[0]).CombinedOutput() if err != nil { return fmt.Errorf("error executing go build: %s\ngo build output:\n%s", err, string(output)), -4 } return nil, 0 }
func main() { flag.Usage = func() { os.Stderr.WriteString(helpMessage) flag.PrintDefaults() os.Exit(2) } flag.Parse() pkgs := flag.Args() if len(pkgs) == 0 { pkgs = []string{"."} } if d, err := os.Getwd(); err != nil { log.Fatalf("cannot get working directory: %v", err) } else { cwd = d } if *why != "" { *all = true *from = true if isStdlib(*why) { *std = true } whyMatch = matchPattern(*why) } pkgs = gotool.ImportPaths(pkgs) rootPkgs := make(map[string]bool) for _, pkg := range pkgs { p, err := build.Default.Import(pkg, cwd, build.FindOnly) if err != nil { log.Fatalf("cannot find %q: %v", pkg, err) } rootPkgs[p.ImportPath] = true } allPkgs := make(map[string][]string) for _, pkg := range pkgs { if err := findImports(pkg, allPkgs, rootPkgs); err != nil { log.Fatalf("cannot find imports from %q: %v", pkg, err) } } if !*files { // Delete packages specified directly on the command line. for pkg := range rootPkgs { delete(allPkgs, pkg) } if whyMatch != nil { // Delete all packages that don't directly or indirectly import *why. marked := make(map[string]bool) for pkg := range allPkgs { if whyMatch(pkg) { markImporters(pkg, allPkgs, marked) } } for pkg := range allPkgs { if !marked[pkg] { delete(allPkgs, pkg) } } } } result := make([]string, 0, len(allPkgs)) for name := range allPkgs { result = append(result, name) } w := bufio.NewWriter(os.Stdout) defer w.Flush() sort.Strings(result) for _, r := range result { switch { case *files: pkg, _ := build.Default.Import(r, cwd, 0) showFiles(w, pkg, pkg.GoFiles) showFiles(w, pkg, pkg.CgoFiles) if rootPkgs[pkg.ImportPath] && !*noTestDeps { // It's a package specified directly on the command line. // Show its test files too. showFiles(w, pkg, pkg.TestGoFiles) showFiles(w, pkg, pkg.XTestGoFiles) } case *from: from := allPkgs[r] sort.Strings(from) from = uniq(from) fmt.Fprintf(w, "%s %s\n", r, strings.Join(from, " ")) default: fmt.Fprintln(w, r) } } }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) flag.Usage = usage flag.Parse() // Get current directory. wd, err := os.Getwd() if err != nil { panic(err) } shouldShow := func(goPackage *gist7480523.GoPackage) bool { // Check for notable status. return status.PorcelainPresenter(goPackage)[:4] != " " } if *vFlag == true { shouldShow = func(_ *gist7480523.GoPackage) bool { return true } } var presenter gist7480523.GoPackageStringer = status.PorcelainPresenter if *debugFlag == true { presenter = status.DebugPresenter } else if *plumbingFlag == true { presenter = status.PlumbingPresenter } // A map of repos that have been checked, to avoid doing same repo more than once. var lock sync.Mutex checkedRepos := map[string]bool{} // Input: Go package Import Path // Output: If a valid Go package and not inside GOROOT, output a status string, else nil. reduceFunc := func(in string) interface{} { goPackage, err := gist7480523.GoPackageFromPath(in, wd) if err != nil { fmt.Fprintf(os.Stderr, "can't load package: %s\n", err) return nil } if goPackage == nil { return nil } if goPackage.Bpkg.Goroot { return nil } goPackage.UpdateVcs() // Check that the same repo hasn't already been done. if goPackage.Dir.Repo != nil { rootPath := goPackage.Dir.Repo.Vcs.RootPath() lock.Lock() if !checkedRepos[rootPath] { checkedRepos[rootPath] = true lock.Unlock() } else { lock.Unlock() // Skip repos that were done. return nil } } goPackage.UpdateVcsFields() if shouldShow(goPackage) == false { return nil } return presenter(goPackage) } // Run reduceFunc on all import paths in parallel. var outChan <-chan interface{} switch *stdinFlag { case false: importPathPatterns := flag.Args() importPaths := gotool.ImportPaths(importPathPatterns) outChan = gist7651991.GoReduceLinesFromSlice(importPaths, numWorkers, reduceFunc) case true: outChan = gist7651991.GoReduceLinesFromReader(os.Stdin, numWorkers, reduceFunc) } // Output results. for out := range outChan { fmt.Println(out.(string)) } }
// Natives augment the standard library with GopherJS-specific changes. // This test ensures that none of the standard library packages are modified // in a way that adds imports which the original upstream standard library package // does not already import. Doing that can increase generated output size or cause // other unexpected issues (since the cmd/go tool does not know about these extra imports), // so it's best to avoid it. // // It checks all standard library packages. Each package is considered as a normal // package, as a test package, and as an external test package. func TestNativesDontImportExtraPackages(t *testing.T) { // Calculate the forward import graph for all standard library packages. // It's needed for populateImportSet. stdOnly := gobuild.Default stdOnly.GOPATH = "" // We only care about standard library, so skip all GOPATH packages. forward, _, err := importgraphutil.BuildNoTests(&stdOnly) if err != nil { t.Fatalf("importgraphutil.BuildNoTests: %v", err) } // populateImportSet takes a slice of imports, and populates set with those // imports, as well as their transitive dependencies. That way, the set can // be quickly queried to check if a package is in the import graph of imports. // // Note, this does not include transitive imports of test/xtest packages, // which could cause some false positives. It currently doesn't, but if it does, // then support for that should be added here. populateImportSet := func(imports []string, set *stringSet) { for _, p := range imports { (*set)[p] = struct{}{} switch p { case "sync": (*set)["github.com/gopherjs/gopherjs/nosync"] = struct{}{} } transitiveImports := forward.Search(p) for p := range transitiveImports { (*set)[p] = struct{}{} } } } // Check all standard library packages. // // The general strategy is to first import each standard library package using the // normal build.Import, which returns a *build.Package. That contains Imports, TestImports, // and XTestImports values that are considered the "real imports". // // That list of direct imports is then expanded to the transitive closure by populateImportSet, // meaning all packages that are indirectly imported are also added to the set. // // Then, github.com/gopherjs/gopherjs/build.parseAndAugment(*build.Package) returns []*ast.File. // Those augmented parsed Go files of the package are checked, one file at at time, one import // at a time. Each import is verified to belong in the set of allowed real imports. for _, pkg := range gotool.ImportPaths([]string{"std"}) { // Normal package. { // Import the real normal package, and populate its real import set. bpkg, err := gobuild.Import(pkg, "", gobuild.ImportComment) if err != nil { t.Fatalf("gobuild.Import: %v", err) } realImports := make(stringSet) populateImportSet(bpkg.Imports, &realImports) // Use parseAndAugment to get a list of augmented AST files. fset := token.NewFileSet() files, err := parseAndAugment(bpkg, false, fset) if err != nil { t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err) } // Verify imports of normal augmented AST files. for _, f := range files { fileName := fset.File(f.Pos()).Name() normalFile := !strings.HasSuffix(fileName, "_test.go") if !normalFile { continue } for _, imp := range f.Imports { importPath, err := strconv.Unquote(imp.Path.Value) if err != nil { t.Fatalf("strconv.Unquote(%v): %v", imp.Path.Value, err) } if importPath == "github.com/gopherjs/gopherjs/js" { continue } if _, ok := realImports[importPath]; !ok { t.Errorf("augmented normal package %q imports %q in file %v, but real %q doesn't:\nrealImports = %v", bpkg.ImportPath, importPath, fileName, bpkg.ImportPath, realImports) } } } } // Test package. { // Import the real test package, and populate its real import set. bpkg, err := gobuild.Import(pkg, "", gobuild.ImportComment) if err != nil { t.Fatalf("gobuild.Import: %v", err) } realTestImports := make(stringSet) populateImportSet(bpkg.TestImports, &realTestImports) // Use parseAndAugment to get a list of augmented AST files. fset := token.NewFileSet() files, err := parseAndAugment(bpkg, true, fset) if err != nil { t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err) } // Verify imports of test augmented AST files. for _, f := range files { fileName, pkgName := fset.File(f.Pos()).Name(), f.Name.String() testFile := strings.HasSuffix(fileName, "_test.go") && !strings.HasSuffix(pkgName, "_test") if !testFile { continue } for _, imp := range f.Imports { importPath, err := strconv.Unquote(imp.Path.Value) if err != nil { t.Fatalf("strconv.Unquote(%v): %v", imp.Path.Value, err) } if importPath == "github.com/gopherjs/gopherjs/js" { continue } if _, ok := realTestImports[importPath]; !ok { t.Errorf("augmented test package %q imports %q in file %v, but real %q doesn't:\nrealTestImports = %v", bpkg.ImportPath, importPath, fileName, bpkg.ImportPath, realTestImports) } } } } // External test package. { // Import the real external test package, and populate its real import set. bpkg, err := gobuild.Import(pkg, "", gobuild.ImportComment) if err != nil { t.Fatalf("gobuild.Import: %v", err) } realXTestImports := make(stringSet) populateImportSet(bpkg.XTestImports, &realXTestImports) // Add _test suffix to import path to cause parseAndAugment to use external test mode. bpkg.ImportPath += "_test" // Use parseAndAugment to get a list of augmented AST files, then check only the external test files. fset := token.NewFileSet() files, err := parseAndAugment(bpkg, true, fset) if err != nil { t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err) } // Verify imports of external test augmented AST files. for _, f := range files { fileName, pkgName := fset.File(f.Pos()).Name(), f.Name.String() xTestFile := strings.HasSuffix(fileName, "_test.go") && strings.HasSuffix(pkgName, "_test") if !xTestFile { continue } for _, imp := range f.Imports { importPath, err := strconv.Unquote(imp.Path.Value) if err != nil { t.Fatalf("strconv.Unquote(%v): %v", imp.Path.Value, err) } if importPath == "github.com/gopherjs/gopherjs/js" { continue } if _, ok := realXTestImports[importPath]; !ok { t.Errorf("augmented external test package %q imports %q in file %v, but real %q doesn't:\nrealXTestImports = %v", bpkg.ImportPath, importPath, fileName, bpkg.ImportPath, realXTestImports) } } } } } }
func main() { vPtr := flag.Bool("v", false, "verbose output (outputs recommended alignments)") flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } ctx := build.Default loadcfg := loader.Config{ Build: &ctx, } rest, err := loadcfg.FromArgs(importPaths, false) if err != nil { log.Fatalf("could not parse arguments: %s", err) } if len(rest) > 0 { log.Fatalf("unhandled extra arguments: %v", rest) } program, err := loadcfg.Load() if err != nil { log.Fatalf("could not type check: %s", err) } var lines []string for _, pkgInfo := range program.InitialPackages() { for _, obj := range pkgInfo.Defs { if obj == nil { continue } if _, ok := obj.(*types.TypeName); !ok { continue } typ, ok := obj.Type().(*types.Named) if !ok { continue } strukt, ok := typ.Underlying().(*types.Struct) if !ok { continue } structAlign := int(stdSizes.Alignof(strukt)) structSize := int(stdSizes.Sizeof(strukt)) if structSize%structAlign != 0 { structSize += structAlign - structSize%structAlign } fields := make(fieldList, 0, strukt.NumFields()) minSize := 0 for i := 0; i < strukt.NumFields(); i++ { field := strukt.Field(i) fieldType := field.Type() typeSize := int(stdSizes.Sizeof(fieldType)) minSize += typeSize fields = append(fields, structField{ name: field.Name(), size: typeSize, }) } if minSize%structAlign != 0 { minSize += structAlign - minSize%structAlign } if minSize != structSize { pos := program.Fset.Position(obj.Pos()) fieldLines := make([]string, 0, len(fields)) sort.Sort(fields) for _, v := range fields { fieldLines = append(fieldLines, fmt.Sprintf( "\t\t%s (size %d)", v.name, v.size, )) } line := fmt.Sprintf( "%s: %s:%d:%d: struct %s could have size %d (currently %d)", obj.Pkg().Path(), pos.Filename, pos.Line, pos.Column, obj.Name(), minSize, structSize, ) if *vPtr { line = line + fmt.Sprintf( ":\n\tRecommended alignment:\n%s", strings.Join(fieldLines, "\n"), ) } lines = append(lines, line) exitStatus = 1 } } } sort.Strings(lines) for _, line := range lines { fmt.Println(line) } os.Exit(exitStatus) }
func main() { flag.Usage = usage flag.Parse() var shouldShow RepoFilter switch { default: shouldShow = func(r *Repo) bool { // Check for notable status. return PorcelainPresenter(r)[:4] != " " } case *vFlag: shouldShow = func(*Repo) bool { return true } } var presenter RepoPresenter switch { case *debugFlag: presenter = DebugPresenter default: presenter = PorcelainPresenter } workspace := NewWorkspace(shouldShow, presenter) // Feed input into workspace processing pipeline. switch *stdinFlag { case false: go func() { // This needs to happen in the background because sending input will be blocked on processing and receiving output. importPathPatterns := flag.Args() importPaths := gotool.ImportPaths(importPathPatterns) for _, importPath := range importPaths { workspace.ImportPaths <- importPath } close(workspace.ImportPaths) }() case true: go func() { // This needs to happen in the background because sending input will be blocked on processing and receiving output. br := bufio.NewReader(os.Stdin) for line, err := br.ReadString('\n'); err == nil; line, err = br.ReadString('\n') { importPath := line[:len(line)-1] // Trim last newline. workspace.ImportPaths <- importPath } close(workspace.ImportPaths) }() } // Output results. for workspace.Statuses != nil || workspace.Errors != nil { select { case status, ok := <-workspace.Statuses: if !ok { workspace.Statuses = nil continue } fmt.Println(status) case error, ok := <-workspace.Errors: if !ok { workspace.Errors = nil continue } fmt.Fprintln(os.Stderr, error) } } }
func main() { flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } ctx := build.Default loadcfg := loader.Config{ Build: &ctx, } rest, err := loadcfg.FromArgs(importPaths, false) if err != nil { log.Fatalf("could not parse arguments: %s", err) } if len(rest) > 0 { log.Fatalf("unhandled extra arguments: %v", rest) } program, err := loadcfg.Load() if err != nil { log.Fatalf("could not type check: %s", err) } var lines []string for _, pkgInfo := range program.InitialPackages() { for _, obj := range pkgInfo.Defs { if obj == nil { continue } if _, ok := obj.(*types.TypeName); !ok { continue } typ, ok := obj.Type().(*types.Named) if !ok { continue } strukt, ok := typ.Underlying().(*types.Struct) if !ok { continue } structAlign := int(stdSizes.Alignof(strukt)) structSize := int(stdSizes.Sizeof(strukt)) if structSize%structAlign != 0 { structSize += structAlign - structSize%structAlign } minSize := 0 for i := 0; i < strukt.NumFields(); i++ { field := strukt.Field(i) fieldType := field.Type() typeSize := int(stdSizes.Sizeof(fieldType)) minSize += typeSize } if minSize%structAlign != 0 { minSize += structAlign - minSize%structAlign } if minSize != structSize { pos := program.Fset.Position(obj.Pos()) lines = append(lines, fmt.Sprintf( "%s: %s:%d:%d: struct %s could have size %d (currently %d)", obj.Pkg().Path(), pos.Filename, pos.Line, pos.Column, obj.Name(), minSize, structSize, )) exitStatus = 1 } } } sort.Strings(lines) for _, line := range lines { fmt.Println(line) } os.Exit(exitStatus) }
func main() { flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } ctx := build.Default loadcfg := loader.Config{ Build: &ctx, } rest, err := loadcfg.FromArgs(importPaths, true) if err != nil { log.Fatalf("could not parse arguments: %s", err) } if len(rest) > 0 { log.Fatalf("unhandled extra arguments: %v", rest) } program, err := loadcfg.Load() if err != nil { log.Fatalf("could not type check: %s", err) } uses := make(map[object]int) positions := make(map[object]token.Position) for _, pkgInfo := range program.InitialPackages() { if pkgInfo.Pkg.Path() == "unsafe" { continue } v := &visitor{ prog: program, pkg: pkgInfo, uses: uses, positions: positions, } for _, f := range v.pkg.Files { ast.Walk(v, f) } } var lines []string for obj, useCount := range uses { if useCount == 0 && (*reportExported || !ast.IsExported(obj.name)) { pos := positions[obj] lines = append(lines, fmt.Sprintf("%s: %s:%d:%d: %s", obj.pkgPath, pos.Filename, pos.Line, pos.Column, obj.name)) exitStatus = 1 } } sort.Strings(lines) for _, line := range lines { fmt.Println(line) } os.Exit(exitStatus) }
func main() { flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } ctx := build.Default for _, pkgPath := range importPaths { visitor := &visitor{ m: make(map[types.Type]map[string]int), skip: make(map[types.Type]struct{}), } loadcfg := loader.Config{ Build: &ctx, } rest, err := loadcfg.FromArgs([]string{pkgPath}, *loadTestFiles) if err != nil { fmt.Fprintf(os.Stderr, "could not parse arguments: %s", err) continue } if len(rest) > 0 { fmt.Fprintf(os.Stderr, "unhandled extra arguments: %v", rest) continue } program, err := loadcfg.Load() if err != nil { fmt.Fprintf(os.Stderr, "could not type check: %s", err) continue } pkg := program.InitialPackages()[0] visitor.prog = program visitor.pkg = pkg for _, f := range pkg.Files { ast.Walk(visitor, f) } for t := range visitor.m { if _, skip := visitor.skip[t]; skip { continue } for fieldName, v := range visitor.m[t] { if !*reportExported && ast.IsExported(fieldName) { continue } if v == 0 { field, _, _ := types.LookupFieldOrMethod(t, false, pkg.Pkg, fieldName) if fieldName == "XMLName" { if named, ok := field.Type().(*types.Named); ok && named.Obj().Pkg().Path() == "encoding/xml" { continue } } pos := program.Fset.Position(field.Pos()) fmt.Printf("%s: %s:%d:%d: %s.%s\n", pkgPath, pos.Filename, pos.Line, pos.Column, types.TypeString(t, nil), fieldName, ) exitStatus = 1 } } } } os.Exit(exitStatus) }