st1001.go raw

   1  package st1001
   2  
   3  import (
   4  	"honnef.co/go/tools/analysis/code"
   5  	"honnef.co/go/tools/analysis/facts/generated"
   6  	"honnef.co/go/tools/analysis/lint"
   7  	"honnef.co/go/tools/analysis/report"
   8  	"honnef.co/go/tools/config"
   9  
  10  	"golang.org/x/tools/go/analysis"
  11  )
  12  
  13  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
  14  	Analyzer: &analysis.Analyzer{
  15  		Name:     "ST1001",
  16  		Run:      run,
  17  		Requires: []*analysis.Analyzer{generated.Analyzer, config.Analyzer},
  18  	},
  19  	Doc: &lint.RawDocumentation{
  20  		Title: `Dot imports are discouraged`,
  21  		Text: `Dot imports that aren't in external test packages are discouraged.
  22  
  23  The \'dot_import_whitelist\' option can be used to whitelist certain
  24  imports.
  25  
  26  Quoting Go Code Review Comments:
  27  
  28  > The \'import .\' form can be useful in tests that, due to circular
  29  > dependencies, cannot be made part of the package being tested:
  30  > 
  31  >     package foo_test
  32  > 
  33  >     import (
  34  >         "bar/testutil" // also imports "foo"
  35  >         . "foo"
  36  >     )
  37  > 
  38  > In this case, the test file cannot be in package foo because it
  39  > uses \'bar/testutil\', which imports \'foo\'. So we use the \'import .\'
  40  > form to let the file pretend to be part of package foo even though
  41  > it is not. Except for this one case, do not use \'import .\' in your
  42  > programs. It makes the programs much harder to read because it is
  43  > unclear whether a name like \'Quux\' is a top-level identifier in the
  44  > current package or in an imported package.`,
  45  		Since:   "2019.1",
  46  		Options: []string{"dot_import_whitelist"},
  47  		MergeIf: lint.MergeIfAny,
  48  	},
  49  })
  50  
  51  var Analyzer = SCAnalyzer.Analyzer
  52  
  53  func run(pass *analysis.Pass) (interface{}, error) {
  54  	for _, f := range pass.Files {
  55  	imports:
  56  		for _, imp := range f.Imports {
  57  			path := imp.Path.Value
  58  			path = path[1 : len(path)-1]
  59  			for _, w := range config.For(pass).DotImportWhitelist {
  60  				if w == path {
  61  					continue imports
  62  				}
  63  			}
  64  
  65  			if imp.Name != nil && imp.Name.Name == "." && !code.IsInTest(pass, f) {
  66  				report.Report(pass, imp, "should not use dot imports", report.FilterGenerated())
  67  			}
  68  		}
  69  	}
  70  	return nil, nil
  71  }
  72