st1019.go raw

   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