github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa4019/sa4019.go (about) 1 package sa4019 2 3 import ( 4 "fmt" 5 "go/ast" 6 "sort" 7 "strings" 8 9 "github.com/amarpal/go-tools/analysis/facts/generated" 10 "github.com/amarpal/go-tools/analysis/lint" 11 "github.com/amarpal/go-tools/analysis/report" 12 "github.com/amarpal/go-tools/go/ast/astutil" 13 14 "golang.org/x/tools/go/analysis" 15 ) 16 17 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 18 Analyzer: &analysis.Analyzer{ 19 Name: "SA4019", 20 Run: run, 21 Requires: []*analysis.Analyzer{generated.Analyzer}, 22 }, 23 Doc: &lint.Documentation{ 24 Title: `Multiple, identical build constraints in the same file`, 25 Since: "2017.1", 26 Severity: lint.SeverityWarning, 27 MergeIf: lint.MergeIfAny, 28 }, 29 }) 30 31 var Analyzer = SCAnalyzer.Analyzer 32 33 func buildTagsIdentical(s1, s2 []string) bool { 34 if len(s1) != len(s2) { 35 return false 36 } 37 s1s := make([]string, len(s1)) 38 copy(s1s, s1) 39 sort.Strings(s1s) 40 s2s := make([]string, len(s2)) 41 copy(s2s, s2) 42 sort.Strings(s2s) 43 for i, s := range s1s { 44 if s != s2s[i] { 45 return false 46 } 47 } 48 return true 49 } 50 51 func run(pass *analysis.Pass) (interface{}, error) { 52 for _, f := range pass.Files { 53 constraints := buildTags(f) 54 for i, constraint1 := range constraints { 55 for j, constraint2 := range constraints { 56 if i >= j { 57 continue 58 } 59 if buildTagsIdentical(constraint1, constraint2) { 60 msg := fmt.Sprintf("identical build constraints %q and %q", 61 strings.Join(constraint1, " "), 62 strings.Join(constraint2, " ")) 63 report.Report(pass, f, msg, report.FilterGenerated(), report.ShortRange()) 64 } 65 } 66 } 67 } 68 return nil, nil 69 } 70 71 func buildTags(f *ast.File) [][]string { 72 var out [][]string 73 for _, line := range strings.Split(astutil.Preamble(f), "\n") { 74 if !strings.HasPrefix(line, "+build ") { 75 continue 76 } 77 line = strings.TrimSpace(strings.TrimPrefix(line, "+build ")) 78 fields := strings.Fields(line) 79 out = append(out, fields) 80 } 81 return out 82 }