Repository: go-critic/go-critic (go)

Issue:
fatal error: concurrent map writes
Hey! I was trying to run this linter on [`github.com/moov-io/ach`](https://github.com/moov-io/ach), but ran into the following panic.

I've tried on windows and linux, but both panic, both are on Go 1.11.

```
C:\Users\adam\go\bin>gocritic.exe check-package -enable=all -withExperimental -withOpinionated github.com/moov-io/ach
fatal error: concurrent map writes

goroutine 539 [running]:
runtime.throw(0x85c0e0, 0x15)
        C:/Go/src/runtime/panic.go:608 +0x79 fp=0xc00a009de0 sp=0xc00a009db0 pc=0x42cd99
runtime.mapassign_fast64ptr(0x7da860, 0xc006586cc0, 0xc0073f9ce0, 0xc003a4fad8)
        C:/Go/src/runtime/map_fast64.go:258 +0x314 fp=0xc00a009e20 sp=0xc00a009de0 pc=0x4111d4
github.com/go-critic/go-critic/lint.resolvePkgObjects(0xc00949a7d0, 0xc0002b8400)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/lint/lint_private.go:208 +0x287 fp=0xc00a009eb0 sp=0xc00a009e20 pc=0x762cf7
github.com/go-critic/go-critic/lint.(*Checker).Check(0xc00949b2c0, 0xc0002b8400, 0xc00947ffe4, 0xc00949b2c0, 0x0)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/lint/lint.go:96 +0xc6 fp=0xc00a009ed0 sp=0xc00a009eb0 pc=0x761f36
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949b2c0)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:290 +0x9b fp=0xc00a009fc0 sp=0xc00a009ed0 pc=0x78065b
runtime.goexit()
        C:/Go/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc00a009fc8 sp=0xc00a009fc0 pc=0x456af1
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc00947ffe4)
        C:/Go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0xc00947ffe4)
        C:/Go/src/sync/waitgroup.go:130 +0x6b
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile(0xc0000cbdc0, 0xc0002b8400)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:300 +0xde
github.com/go-critic/go-critic/cmd/criticize.(*linter).CheckPackage(0xc0000cbdc0, 0xc000064100, 0x16)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:241 +0x1bd
github.com/go-critic/go-critic/cmd/criticize.Main()
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:102 +0xd4
main.main()
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/gocritic/main.go:68 +0x1c0

goroutine 520 [runnable]:
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949ab90)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3

goroutine 530 [runnable]:
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949afa0)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3

goroutine 514 [runnable]:
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949a9b0)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3

goroutine 518 [runnable]:
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949aaf0)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3

goroutine 517 [runnable]:
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949aaa0)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3

goroutine 529 [runnable]:
github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile.func1(0xc00947ffe4, 0xc0002b8400, 0xc0000cbdc0, 0xc00949af50)
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272
created by github.com/go-critic/go-critic/cmd/criticize.(*linter).checkFile
        C:/Users/adam/go/src/github.com/go-critic/go-critic/cmd/criticize/main.go:272 +0xb3
```



Pull request:
lint: fix concurrent map write in Checker.Check(file)
Move file-related resource loading into Context.SetFileInfo.
This way, integrating code can resolve these Context.require
fields before running checkers concurrently.

Fixes #617

Patch:
diff --git a/cmd/criticize/main.go b/cmd/criticize/main.go
index fb8e69c..c40192b 100644
--- a/cmd/criticize/main.go
+++ b/cmd/criticize/main.go
@@ -237,7 +237,7 @@ func (l *linter) CheckPackage(pkgPath string) {
 		if !l.flags.CheckGenerated && l.isGenerated(f) {
 			continue
 		}
-		l.ctx.SetFileInfo(l.getFilename(f))
+		l.ctx.SetFileInfo(l.getFilename(f), f)
 		l.checkFile(f)
 	}
 }
diff --git a/lint/lint.go b/lint/lint.go
index 408758a..b5af768 100644
--- a/lint/lint.go
+++ b/lint/lint.go
@@ -92,12 +92,6 @@ type Checker struct {
 // Check runs rule checker over file f.
 func (c *Checker) Check(f *ast.File) []Warning {
 	c.ctx.warnings = c.ctx.warnings[:0]
-	if c.ctx.require.pkgObjects {
-		resolvePkgObjects(c.ctx.Context, f)
-	}
-	if c.ctx.require.pkgRenames {
-		resolvePkgRenames(c.ctx.Context, f)
-	}
 	c.walker.WalkFile(f)
 	return c.ctx.warnings
 }
@@ -187,8 +181,14 @@ func (c *Context) SetPackageInfo(info *types.Info, pkg *types.Package) {
 // SetFileInfo sets file-related metadata.
 //
 // Must be called for every source code file being checked.
-func (c *Context) SetFileInfo(filename string) {
-	c.filename = filename
+func (c *Context) SetFileInfo(name string, f *ast.File) {
+	c.filename = name
+	if c.require.pkgObjects {
+		resolvePkgObjects(c, f)
+	}
+	if c.require.pkgRenames {
+		resolvePkgRenames(c, f)
+	}
 }
 
 // Documentation holds rule structured documentation.


Test patch:
diff --git a/lint/all_checkers_test.go b/lint/all_checkers_test.go
index 5fce769..6d5b427 100644
--- a/lint/all_checkers_test.go
+++ b/lint/all_checkers_test.go
@@ -101,6 +101,7 @@ func checkFiles(t *testing.T, rule *Rule, ctx *Context, prog *loader.Program, pk
 
 	for _, f := range files {
 		filename := getFilename(prog, f)
+		ctx.SetFileInfo(filename, f)
 		testFilename := filepath.Join("testdata", rule.Name(), filename)
 		goldenWarns := newGoldenFile(t, testFilename)