7
7
"go/types"
8
8
"os"
9
9
"path/filepath"
10
+ "regexp"
10
11
"strings"
11
12
"time"
12
13
@@ -25,18 +26,20 @@ import (
25
26
)
26
27
27
28
type ContextLoader struct {
28
- cfg * config.Config
29
- log logutils.Log
30
- debugf logutils.DebugFunc
31
- goenv * goutil.Env
29
+ cfg * config.Config
30
+ log logutils.Log
31
+ debugf logutils.DebugFunc
32
+ goenv * goutil.Env
33
+ pkgTestIDRe * regexp.Regexp
32
34
}
33
35
34
36
func NewContextLoader (cfg * config.Config , log logutils.Log , goenv * goutil.Env ) * ContextLoader {
35
37
return & ContextLoader {
36
- cfg : cfg ,
37
- log : log ,
38
- debugf : logutils .Debug ("loader" ),
39
- goenv : goenv ,
38
+ cfg : cfg ,
39
+ log : log ,
40
+ debugf : logutils .Debug ("loader" ),
41
+ goenv : goenv ,
42
+ pkgTestIDRe : regexp .MustCompile (`^(.*) \[(.*)\.test\]` ),
40
43
}
41
44
}
42
45
@@ -222,19 +225,65 @@ func (cl ContextLoader) loadPackages(ctx context.Context, loadMode packages.Load
222
225
i , pkg .ID , pkg .GoFiles , pkg .CompiledGoFiles , syntaxFiles )
223
226
}
224
227
225
- var retPkgs []* packages.Package
226
228
for _ , pkg := range pkgs {
227
229
for _ , err := range pkg .Errors {
228
230
if strings .Contains (err .Msg , "no Go files" ) {
229
231
return nil , errors .Wrapf (exitcodes .ErrNoGoFiles , "package %s" , pkg .PkgPath )
230
232
}
231
233
}
232
- if ! shouldSkipPkg (pkg ) {
233
- retPkgs = append (retPkgs , pkg )
234
+ }
235
+
236
+ return cl .filterPackages (pkgs ), nil
237
+ }
238
+
239
+ func (cl ContextLoader ) tryParseTestPackage (pkg * packages.Package ) (name , testName string , isTest bool ) {
240
+ matches := cl .pkgTestIDRe .FindStringSubmatch (pkg .ID )
241
+ if matches == nil {
242
+ return "" , "" , false
243
+ }
244
+
245
+ return matches [1 ], matches [2 ], true
246
+ }
247
+
248
+ func (cl ContextLoader ) filterPackages (pkgs []* packages.Package ) []* packages.Package {
249
+ packagesWithTests := map [string ]bool {}
250
+ for _ , pkg := range pkgs {
251
+ name , testName , isTest := cl .tryParseTestPackage (pkg )
252
+ if ! isTest {
253
+ continue
254
+ }
255
+ packagesWithTests [name ] = true
256
+
257
+ if name != testName {
258
+ cl .log .Infof ("pkg ID=%s: %s != %s: %#v" , pkg .ID , name , testName , pkg )
259
+ }
260
+ }
261
+
262
+ cl .debugf ("package with tests: %#v" , packagesWithTests )
263
+
264
+ var retPkgs []* packages.Package
265
+ for _ , pkg := range pkgs {
266
+ if shouldSkipPkg (pkg ) {
267
+ cl .debugf ("skip pkg ID=%s" , pkg .ID )
268
+ continue
269
+ }
270
+
271
+ _ , _ , isTest := cl .tryParseTestPackage (pkg )
272
+ if ! isTest && packagesWithTests [pkg .PkgPath ] {
273
+ // If tests loading is enabled,
274
+ // for package with files a.go and a_test.go go/packages loads two packages:
275
+ // 1. ID=".../a" GoFiles=[a.go]
276
+ // 2. ID=".../a [.../a.test]" GoFiles=[a.go a_test.go]
277
+ // We need only the second package, otherwise we can get warnings about unused variables/fields/functions
278
+ // in a.go if they are used only in a_test.go.
279
+ cl .debugf ("skip pkg ID=%s because we load it with test package" , pkg .ID )
280
+ continue
234
281
}
282
+
283
+ retPkgs = append (retPkgs , pkg )
235
284
}
236
285
237
- return retPkgs , nil
286
+ return retPkgs
238
287
}
239
288
240
289
//nolint:gocyclo
0 commit comments