1 package st1019
2 3 import (
4 "fmt"
5 "go/ast"
6 7 "honnef.co/go/tools/analysis/facts/generated"
8 "honnef.co/go/tools/analysis/lint"
9 "honnef.co/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.RawDocumentation{
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 }
79