github.com/daixiang0/gci@v0.13.4/pkg/analyzer/analyzer.go (about) 1 package analyzer 2 3 import ( 4 "fmt" 5 "go/token" 6 "strings" 7 8 "github.com/golangci/modinfo" 9 "golang.org/x/tools/go/analysis" 10 "golang.org/x/tools/go/analysis/passes/inspect" 11 12 "github.com/daixiang0/gci/pkg/config" 13 "github.com/daixiang0/gci/pkg/gci" 14 "github.com/daixiang0/gci/pkg/io" 15 "github.com/daixiang0/gci/pkg/log" 16 ) 17 18 const ( 19 NoInlineCommentsFlag = "noInlineComments" 20 NoPrefixCommentsFlag = "noPrefixComments" 21 SkipGeneratedFlag = "skipGenerated" 22 SectionsFlag = "Sections" 23 SectionSeparatorsFlag = "SectionSeparators" 24 SectionDelimiter = "," 25 ) 26 27 var ( 28 noInlineComments bool 29 noPrefixComments bool 30 skipGenerated bool 31 sectionsStr string 32 sectionSeparatorsStr string 33 ) 34 35 func init() { 36 Analyzer.Flags.BoolVar(&noInlineComments, NoInlineCommentsFlag, false, "If comments in the same line as the input should be present") 37 Analyzer.Flags.BoolVar(&noPrefixComments, NoPrefixCommentsFlag, false, "If comments above an input should be present") 38 Analyzer.Flags.BoolVar(&skipGenerated, SkipGeneratedFlag, false, "Skip generated files") 39 Analyzer.Flags.StringVar(§ionsStr, SectionsFlag, "", "Specify the Sections format that should be used to check the file formatting") 40 Analyzer.Flags.StringVar(§ionSeparatorsStr, SectionSeparatorsFlag, "", "Specify the Sections that are inserted as Separators between Sections") 41 42 log.InitLogger() 43 defer log.L().Sync() 44 } 45 46 var Analyzer = &analysis.Analyzer{ 47 Name: "gci", 48 Doc: "A tool that control Go package import order and make it always deterministic.", 49 Run: runAnalysis, 50 Requires: []*analysis.Analyzer{ 51 inspect.Analyzer, 52 modinfo.Analyzer, 53 }, 54 } 55 56 func runAnalysis(pass *analysis.Pass) (interface{}, error) { 57 var fileReferences []*token.File 58 // extract file references for all files in the analyzer pass 59 for _, pkgFile := range pass.Files { 60 fileForPos := pass.Fset.File(pkgFile.Package) 61 if fileForPos != nil { 62 fileReferences = append(fileReferences, fileForPos) 63 } 64 } 65 expectedNumFiles := len(pass.Files) 66 foundNumFiles := len(fileReferences) 67 if expectedNumFiles != foundNumFiles { 68 return nil, InvalidNumberOfFilesInAnalysis{expectedNumFiles, foundNumFiles} 69 } 70 71 file, err := modinfo.FindModuleFromPass(pass) 72 if err != nil { 73 return nil, err 74 } 75 76 gciCfg, err := generateGciConfiguration(file.Path).Parse() 77 if err != nil { 78 return nil, err 79 } 80 81 for _, file := range fileReferences { 82 filePath := file.Name() 83 unmodifiedFile, formattedFile, err := gci.LoadFormatGoFile(io.File{FilePath: filePath}, *gciCfg) 84 if err != nil { 85 return nil, err 86 } 87 fix, err := GetSuggestedFix(file, unmodifiedFile, formattedFile) 88 if err != nil { 89 return nil, err 90 } 91 if fix == nil { 92 // no difference 93 continue 94 } 95 pass.Report(analysis.Diagnostic{ 96 Pos: fix.TextEdits[0].Pos, 97 Message: fmt.Sprintf("fix by `%s %s`", generateCmdLine(*gciCfg), filePath), 98 SuggestedFixes: []analysis.SuggestedFix{*fix}, 99 }) 100 } 101 return nil, nil 102 } 103 104 func generateGciConfiguration(modPath string) *config.YamlConfig { 105 fmtCfg := config.BoolConfig{ 106 NoInlineComments: noInlineComments, 107 NoPrefixComments: noPrefixComments, 108 Debug: false, 109 SkipGenerated: skipGenerated, 110 } 111 112 var sectionStrings []string 113 if sectionsStr != "" { 114 sectionStrings = strings.Split(sectionsStr, SectionDelimiter) 115 } 116 117 var sectionSeparatorStrings []string 118 if sectionSeparatorsStr != "" { 119 sectionSeparatorStrings = strings.Split(sectionSeparatorsStr, SectionDelimiter) 120 fmt.Println(sectionSeparatorsStr) 121 } 122 123 return &config.YamlConfig{Cfg: fmtCfg, SectionStrings: sectionStrings, SectionSeparatorStrings: sectionSeparatorStrings, ModPath: modPath} 124 } 125 126 func generateCmdLine(cfg config.Config) string { 127 result := "gci write" 128 129 if cfg.BoolConfig.NoInlineComments { 130 result += " --NoInlineComments " 131 } 132 133 if cfg.BoolConfig.NoPrefixComments { 134 result += " --NoPrefixComments " 135 } 136 137 if cfg.BoolConfig.SkipGenerated { 138 result += " --skip-generated " 139 } 140 141 if cfg.BoolConfig.CustomOrder { 142 result += " --custom-order " 143 } 144 145 for _, s := range cfg.Sections.String() { 146 result += fmt.Sprintf(" --Section \"%s\" ", s) 147 } 148 for _, s := range cfg.SectionSeparators.String() { 149 result += fmt.Sprintf(" --SectionSeparator %s ", s) 150 } 151 return result 152 }