//do useful for testing func do(writer io.Writer, flags *flag.FlagSet, args []string) error { var pkgPath string var rematchUser string flags.Usage = usage writeToFilesFlag := flags.Bool("w", false, "write to files") simulateFlag := flags.Bool("s", false, "simulate updates") flags.Parse(args) pkgPath, rematchUser = parseArgs(flags) packages, err := parser.ParseDir(fileSet, pkgPath, isGoFile, 0) if err != nil { return fmt.Errorf("parserDir: %s", err.Error()) } info := types.Info{ Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), } var files []*ast.File fileByPath := make(map[string]*os.File) //cache files for _, pkg := range packages { for filePath, file := range pkg.Files { fp, err := os.OpenFile(filePath, os.O_RDWR, 0777) if err != nil { return err } defer fp.Close() files = append(files, file) fileByPath[filePath] = fp } } //parse package var conf types.Config conf.Importer = importer.Default() conf.DisableUnusedImportCheck = true conf.Error = func(err error) { //omit errors try parse it } pkg, _ := conf.Check(pkgPath, fileSet, files, &info) //queries for user matching queries := make(chan *queryIdent) //queries for unexported fields used it for detect collision chqueriesUnexported := make(chan *queryIdent) go buildQueryStrings(queries, pkg, &info, true) go buildQueryStrings(chqueriesUnexported, pkg, &info, false) queriesUnexported := make(map[string]*ast.Ident) for queryUnexport := range chqueriesUnexported { queriesUnexported[queryUnexport.Query] = queryUnexport.Ident } //go routine for unexporting doneSave := make(chan bool) unexportPositions := make(chan token.Position, 1) unexports := make(map[string]bool) //start updater on files go unexportOnFile(doneSave, fileByPath, unexportPositions, *simulateFlag) //try match user query var where func(string) bool if rematchUser == "" { rematchUser = "******" } where = regexp.MustCompile(rematchUser).MatchString //used only for showing var generalQueries []*queryIdent for query := range queries { if where(query.Query) { //detect collision _, isKeyword := goKeywords[nameUnexported(query.Ident.Name)] if queriesUnexported[query.Query] != nil || isKeyword { if !*writeToFilesFlag { generalQueries = append(generalQueries, &queryIdent{query.Query + " !!collision", query.Ident}) } else { fmt.Fprintln(writer, "sorry collision detected for", query.Query) } continue } pos := fileSet.Position(query.Ident.Pos()) unexports[query.Ident.Name] = true if !*writeToFilesFlag { generalQueries = append(generalQueries, query) continue } fmt.Fprintln(writer, "Unexported", query.Ident.Name, "from", query.Query) unexportPositions <- pos } } displayUses := make(map[string]map[string][]string) for ident := range info.Uses { if _, ok := unexports[ident.Name]; ok { pos := fileSet.Position(ident.Pos()) if !*writeToFilesFlag { if _, ok := displayUses[pos.Filename]; !ok { displayUses[pos.Filename] = make(map[string][]string) } posLine := fmt.Sprintf("\t\t\t\t%s:%d:%d", pos.Filename, pos.Line, pos.Column) displayUses[pos.Filename][ident.Name] = append(displayUses[pos.Filename][ident.Name], posLine) continue } unexportPositions <- pos } } if !*writeToFilesFlag { sort.Sort(byQuery(generalQueries)) prettyQueries(writer, generalQueries, displayUses) return nil } close(unexportPositions) <-doneSave return nil }