github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/stylecheck/st1019/st1019.go (about) 1 package st1019 2 3 import ( 4 "fmt" 5 "go/ast" 6 7 "github.com/amarpal/go-tools/analysis/facts/generated" 8 "github.com/amarpal/go-tools/analysis/lint" 9 "github.com/amarpal/go-tools/analysis/report" 10 11 "golang.org/x/tools/go/analysis" 12 ) 13 14 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 15 Analyzer: &analysis.Analyzer{ 16 Name: "ST1019", 17 Run: run, 18 Requires: []*analysis.Analyzer{generated.Analyzer}, 19 }, 20 Doc: &lint.Documentation{ 21 Title: `Importing the same package multiple times`, 22 Text: `Go allows importing the same package multiple times, as long as 23 different import aliases are being used. That is, the following 24 bit of code is valid: 25 26 import ( 27 "fmt" 28 fumpt "fmt" 29 format "fmt" 30 _ "fmt" 31 ) 32 33 However, this is very rarely done on purpose. Usually, it is a 34 sign of code that got refactored, accidentally adding duplicate 35 import statements. It is also a rarely known feature, which may 36 contribute to confusion. 37 38 Do note that sometimes, this feature may be used 39 intentionally (see for example 40 https://github.com/golang/go/commit/3409ce39bfd7584523b7a8c150a310cea92d879d) 41 – if you want to allow this pattern in your code base, you're 42 advised to disable this check.`, 43 Since: "2020.1", 44 MergeIf: lint.MergeIfAny, 45 }, 46 }) 47 48 var Analyzer = SCAnalyzer.Analyzer 49 50 func run(pass *analysis.Pass) (interface{}, error) { 51 for _, f := range pass.Files { 52 // Collect all imports by their import path 53 imports := make(map[string][]*ast.ImportSpec, len(f.Imports)) 54 for _, imp := range f.Imports { 55 imports[imp.Path.Value] = append(imports[imp.Path.Value], imp) 56 } 57 58 for path, value := range imports { 59 if path[1:len(path)-1] == "unsafe" { 60 // Don't flag unsafe. Cgo generated code imports 61 // unsafe using the blank identifier, and most 62 // user-written cgo code also imports unsafe 63 // explicitly. 64 continue 65 } 66 // If there's more than one import per path, we flag that 67 if len(value) > 1 { 68 s := fmt.Sprintf("package %s is being imported more than once", path) 69 opts := []report.Option{report.FilterGenerated()} 70 for _, imp := range value[1:] { 71 opts = append(opts, report.Related(imp, fmt.Sprintf("other import of %s", path))) 72 } 73 report.Report(pass, value[0], s, opts...) 74 } 75 } 76 } 77 return nil, nil 78 }