src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

st1019.go (2676B)


      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     )
     31 
     32 However, this is very rarely done on purpose. Usually, it is a
     33 sign of code that got refactored, accidentally adding duplicate
     34 import statements. It is also a rarely known feature, which may
     35 contribute to confusion.
     36 
     37 Do note that sometimes, this feature may be used
     38 intentionally (see for example
     39 https://github.com/golang/go/commit/3409ce39bfd7584523b7a8c150a310cea92d879d)
     40 – if you want to allow this pattern in your code base, you're
     41 advised to disable this check.
     42 
     43 It is acceptable to import the same package twice if one of the imports
     44 uses the blank identifier. This is allowed in order to increase
     45 resilience against erroneous changes when using the same package for its
     46 side effects as well as its exported API.`,
     47 		Since:   "2020.1",
     48 		MergeIf: lint.MergeIfAny,
     49 	},
     50 })
     51 
     52 var Analyzer = SCAnalyzer.Analyzer
     53 
     54 func run(pass *analysis.Pass) (any, error) {
     55 	for _, f := range pass.Files {
     56 		// Collect all imports by their import path
     57 		imports := make(map[string][]*ast.ImportSpec, len(f.Imports))
     58 		for _, imp := range f.Imports {
     59 			if imp.Name != nil && imp.Name.Name == "_" {
     60 				// Allow blank imports to coexist with one normal import.
     61 				//
     62 				// We don't have to count the number of blank imports,
     63 				// goimports removes duplicates.
     64 				continue
     65 			}
     66 			imports[imp.Path.Value] = append(imports[imp.Path.Value], imp)
     67 		}
     68 
     69 		for path, value := range imports {
     70 			if path[1:len(path)-1] == "unsafe" {
     71 				// Don't flag unsafe. Cgo generated code imports
     72 				// unsafe as _cgo_unsafe, in addition to the user's import.
     73 				continue
     74 			}
     75 			// If there's more than one import per path, we flag that
     76 			if len(value) > 1 {
     77 				s := fmt.Sprintf("package %s is being imported more than once", path)
     78 				opts := []report.Option{report.FilterGenerated()}
     79 				for _, imp := range value[1:] {
     80 					opts = append(opts, report.Related(imp, fmt.Sprintf("other import of %s", path)))
     81 				}
     82 				report.Report(pass, value[0], s, opts...)
     83 			}
     84 		}
     85 	}
     86 	return nil, nil
     87 }