Repository: mgechev/revive (go)

Issue:
Data race in rule function-length
**Describe the bug**
When revive is installed with Go's race detector enabled, any use of the function-length rule triggers a data race.

**To Reproduce**
Steps to reproduce the behavior:
1. Install revive with the race detector enabled `go install -a -race github.com/mgechev/revive@latest`
2. Run it with the following flags & configuration file:

```shell
# shell command
revive -config revive_function_length_data_race.toml ./...
```

```toml
# config file
[rule.function-length]
  arguments = [10,0]
```

**Expected behavior**
No data race detected.

**Logs**
```
==================
WARNING: DATA RACE
Write at 0x00c0000fa210 by goroutine 175:
  github.com/mgechev/revive/rule.(*FunctionLength).configure()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/rule/function-length.go:23 +0x98
  github.com/mgechev/revive/rule.(*FunctionLength).Apply()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/rule/function-length.go:31 +0x84
  github.com/mgechev/revive/lint.(*File).lint()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/file.go:105 +0x201
  github.com/mgechev/revive/lint.(*Package).lint.func1()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/package.go:185 +0x104
  github.com/mgechev/revive/lint.(*Package).lint.func2()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/package.go:187 +0x47

Previous read at 0x00c0000fa210 by goroutine 174:
  github.com/mgechev/revive/rule.(*FunctionLength).Apply()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/rule/function-length.go:37 +0xcc
  github.com/mgechev/revive/lint.(*File).lint()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/file.go:105 +0x201
  github.com/mgechev/revive/lint.(*Package).lint.func1()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/package.go:185 +0x104
  github.com/mgechev/revive/lint.(*Package).lint.func2()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/package.go:187 +0x47

Goroutine 175 (running) created at:
  github.com/mgechev/revive/lint.(*Package).lint()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/package.go:184 +0xed
  github.com/mgechev/revive/lint.(*Linter).lintPackage()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/linter.go:106 +0x2b7
  github.com/mgechev/revive/lint.(*Linter).Lint.func1()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/linter.go:64 +0x137
  github.com/mgechev/revive/lint.(*Linter).Lint.func3()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/linter.go:69 +0x66

Goroutine 174 (finished) created at:
  github.com/mgechev/revive/lint.(*Package).lint()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/package.go:184 +0xed
  github.com/mgechev/revive/lint.(*Linter).lintPackage()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/linter.go:106 +0x2b7
  github.com/mgechev/revive/lint.(*Linter).Lint.func1()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/linter.go:64 +0x137
  github.com/mgechev/revive/lint.(*Linter).Lint.func3()
      /home/hansg/go/pkg/mod/github.com/mgechev/revive@v1.2.3/lint/linter.go:69 +0x66
==================
```

**Desktop (please complete the following information):**
 - OS: Debian 9 (stretch)
 - Version of Go: Go 1.19 (but also reproduced with Go 1.18 and 1.17)

**Additional context**
N/A

Pull request:
fix bug #736: Data race in rule function-length
Closes #736 


Patch:
diff --git a/rule/function-length.go b/rule/function-length.go
index 717ddbf..d600d7a 100644
--- a/rule/function-length.go
+++ b/rule/function-length.go
@@ -11,17 +11,19 @@ import (
 
 // FunctionLength lint.
 type FunctionLength struct {
-	maxStmt  int
-	maxLines int
+	maxStmt    int
+	maxLines   int
+	configured bool
 	sync.Mutex
 }
 
 func (r *FunctionLength) configure(arguments lint.Arguments) {
 	r.Lock()
-	if r.maxLines == 0 {
+	if !r.configured {
 		maxStmt, maxLines := r.parseArguments(arguments)
 		r.maxStmt = int(maxStmt)
 		r.maxLines = int(maxLines)
+		r.configured = true
 	}
 	r.Unlock()
 }
diff --git a/rule/nested-structs.go b/rule/nested-structs.go
index b4f7352..968511f 100644
--- a/rule/nested-structs.go
+++ b/rule/nested-structs.go
@@ -43,6 +43,11 @@ func (l *lintNestedStructs) Visit(n ast.Node) ast.Visitor {
 		}
 		return nil
 	case *ast.Field:
+		_, isChannelField := v.Type.(*ast.ChanType)
+		if isChannelField {
+			return nil
+		}
+
 		filter := func(n ast.Node) bool {
 			switch n.(type) {
 			case *ast.StructType:


Test patch:
diff --git a/testdata/nested-structs.go b/testdata/nested-structs.go
index 7e5abaf..8823d65 100644
--- a/testdata/nested-structs.go
+++ b/testdata/nested-structs.go
@@ -35,3 +35,8 @@ func fred() interface{} {
 type Bad struct {
 	Field []struct{} // MATCH /no nested structs are allowed/
 }
+
+// issue744
+type issue744 struct {
+	c chan struct{}
+}