@@ -10,9 +10,10 @@ import (
1010 "strings"
1111 "sync"
1212
13- errcheck "github.com/golangci /errcheck/golangci "
13+ "github.com/kisielk /errcheck/errcheck "
1414 "github.com/pkg/errors"
1515 "golang.org/x/tools/go/analysis"
16+ "golang.org/x/tools/go/packages"
1617
1718 "github.com/golangci/golangci-lint/pkg/config"
1819 "github.com/golangci/golangci-lint/pkg/fsutils"
@@ -23,51 +24,70 @@ import (
2324
2425func NewErrcheck () * goanalysis.Linter {
2526 const linterName = "errcheck"
27+
2628 var mu sync.Mutex
2729 var res []goanalysis.Issue
30+
2831 analyzer := & analysis.Analyzer {
2932 Name : linterName ,
3033 Doc : goanalysis .TheOnlyanalyzerDoc ,
3134 }
35+
3236 return goanalysis .NewLinter (
3337 linterName ,
3438 "Errcheck is a program for checking for unchecked errors " +
3539 "in go programs. These unchecked errors can be critical bugs in some cases" ,
3640 []* analysis.Analyzer {analyzer },
3741 nil ,
3842 ).WithContextSetter (func (lintCtx * linter.Context ) {
43+ // copied from errcheck
44+ checker , err := getChecker (& lintCtx .Settings ().Errcheck )
45+ if err != nil {
46+ lintCtx .Log .Errorf ("failed to get checker: %v" , err )
47+ return
48+ }
49+
50+ checker .Tags = lintCtx .Cfg .Run .BuildTags
51+
3952 analyzer .Run = func (pass * analysis.Pass ) (interface {}, error ) {
40- prog := goanalysis .MakeFakeLoaderProgram (pass )
41- errCfg , err := genConfig (& lintCtx .Settings ().Errcheck )
42- if err != nil {
43- return nil , err
44- }
45- errcheckIssues , err := errcheck .RunWithConfig (prog , errCfg )
46- if err != nil {
47- return nil , err
53+ pkg := & packages.Package {
54+ Fset : pass .Fset ,
55+ Syntax : pass .Files ,
56+ Types : pass .Pkg ,
57+ TypesInfo : pass .TypesInfo ,
4858 }
4959
50- if len (errcheckIssues ) == 0 {
60+ errcheckIssues := checker .CheckPackage (pkg ).Unique ()
61+ if len (errcheckIssues .UncheckedErrors ) == 0 {
5162 return nil , nil
5263 }
5364
54- issues := make ([]goanalysis.Issue , 0 , len (errcheckIssues ))
55- for _ , i := range errcheckIssues {
65+ issues := make ([]goanalysis.Issue , len (errcheckIssues . UncheckedErrors ))
66+ for i , err := range errcheckIssues . UncheckedErrors {
5667 var text string
57- if i .FuncName != "" {
58- text = fmt .Sprintf ("Error return value of %s is not checked" , formatCode (i .FuncName , lintCtx .Cfg ))
68+ if err .FuncName != "" {
69+ text = fmt .Sprintf (
70+ "Error return value of %s is not checked" ,
71+ formatCode (err .SelectorName , lintCtx .Cfg ),
72+ )
5973 } else {
6074 text = "Error return value is not checked"
6175 }
62- issues = append (issues , goanalysis .NewIssue (& result.Issue {
63- FromLinter : linterName ,
64- Text : text ,
65- Pos : i .Pos ,
66- }, pass ))
76+
77+ issues [i ] = goanalysis .NewIssue (
78+ & result.Issue {
79+ FromLinter : linterName ,
80+ Text : text ,
81+ Pos : err .Pos ,
82+ },
83+ pass ,
84+ )
6785 }
86+
6887 mu .Lock ()
6988 res = append (res , issues ... )
7089 mu .Unlock ()
90+
7191 return nil , nil
7292 }
7393 }).WithIssuesReporter (func (* linter.Context ) []goanalysis.Issue {
@@ -104,27 +124,35 @@ func parseIgnoreConfig(s string) (map[string]*regexp.Regexp, error) {
104124 return cfg , nil
105125}
106126
107- func genConfig (errCfg * config.ErrcheckSettings ) (* errcheck.Config , error ) {
127+ func getChecker (errCfg * config.ErrcheckSettings ) (* errcheck.Checker , error ) {
108128 ignoreConfig , err := parseIgnoreConfig (errCfg .Ignore )
109129 if err != nil {
110130 return nil , errors .Wrap (err , "failed to parse 'ignore' directive" )
111131 }
112132
113- c := & errcheck.Config {
114- Ignore : ignoreConfig ,
115- Blank : errCfg .CheckAssignToBlank ,
116- Asserts : errCfg .CheckTypeAssertions ,
133+ checker := errcheck.Checker {
134+ Exclusions : errcheck.Exclusions {
135+ BlankAssignments : ! errCfg .CheckAssignToBlank ,
136+ TypeAssertions : ! errCfg .CheckTypeAssertions ,
137+ SymbolRegexpsByPackage : map [string ]* regexp.Regexp {},
138+ Symbols : append ([]string {}, errcheck .DefaultExcludedSymbols ... ),
139+ },
140+ }
141+
142+ for pkg , re := range ignoreConfig {
143+ checker .Exclusions .SymbolRegexpsByPackage [pkg ] = re
117144 }
118145
119146 if errCfg .Exclude != "" {
120147 exclude , err := readExcludeFile (errCfg .Exclude )
121148 if err != nil {
122149 return nil , err
123150 }
124- c .Exclude = exclude
151+
152+ checker .Exclusions .Symbols = append (checker .Exclusions .Symbols , exclude ... )
125153 }
126154
127- return c , nil
155+ return & checker , nil
128156}
129157
130158func getFirstPathArg () string {
@@ -192,7 +220,7 @@ func setupConfigFileSearch(name string) []string {
192220 return configSearchPaths
193221}
194222
195- func readExcludeFile (name string ) (map [ string ] bool , error ) {
223+ func readExcludeFile (name string ) ([] string , error ) {
196224 var err error
197225 var fh * os.File
198226
@@ -205,13 +233,17 @@ func readExcludeFile(name string) (map[string]bool, error) {
205233 if fh == nil {
206234 return nil , errors .Wrapf (err , "failed reading exclude file: %s" , name )
207235 }
236+
208237 scanner := bufio .NewScanner (fh )
209- exclude := make (map [string ]bool )
238+
239+ var excludes []string
210240 for scanner .Scan () {
211- exclude [ scanner .Text ()] = true
241+ excludes = append ( excludes , scanner .Text ())
212242 }
243+
213244 if err := scanner .Err (); err != nil {
214245 return nil , errors .Wrapf (err , "failed scanning file: %s" , name )
215246 }
216- return exclude , nil
247+
248+ return excludes , nil
217249}
0 commit comments