コード例 #1
0
ファイル: main.go プロジェクト: rakyll/GCSolutions
//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
}