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

Issue:
unlambda: false positive 
```go
func New(options ...string) error {
	return nil
}

var NewWithTimeout = func(options ...string) error {
	return New(append(options, "timeout")...)
}
```

```
unlambda: replace `func(options ...string) error {
        return New(append(options, "timeout")...)
}` with `New` (gocritic)
var NewWithTimeout = func(options ...string) error {
                     ^

```


Pull request description:
checkers/unlambda: correct calculation amount args.
Count args of CallExpr.

Example: `a(b(1,2))` will be 2, not 1.

fixes #1362

Patch:
diff --git a/checkers/unlambda_checker.go b/checkers/unlambda_checker.go
index bcfe5a0..0401bf5 100644
--- a/checkers/unlambda_checker.go
+++ b/checkers/unlambda_checker.go
@@ -91,7 +91,7 @@ func (c *unlambdaChecker) VisitExpr(x ast.Expr) {
 		}
 	}
 
-	if len(result.Args) == n {
+	if c.lenArgs(result.Args) == n {
 		c.warn(fn, callable)
 	}
 }
@@ -99,3 +99,20 @@ func (c *unlambdaChecker) VisitExpr(x ast.Expr) {
 func (c *unlambdaChecker) warn(cause ast.Node, suggestion string) {
 	c.ctx.Warn(cause, "replace `%s` with `%s`", cause, suggestion)
 }
+
+func (c *unlambdaChecker) lenArgs(args []ast.Expr) int {
+	lenArgs := len(args)
+
+	for _, arg := range args {
+		callExp, ok := arg.(*ast.CallExpr)
+		if !ok {
+			continue
+		}
+
+		// Don't count function call. only args.
+		lenArgs--
+		lenArgs += c.lenArgs(callExp.Args)
+	}
+
+	return lenArgs
+}


Test patch:
diff --git a/checkers/testdata/unlambda/negative_tests.go b/checkers/testdata/unlambda/negative_tests.go
index 218c63f..6a7357e 100644
--- a/checkers/testdata/unlambda/negative_tests.go
+++ b/checkers/testdata/unlambda/negative_tests.go
@@ -128,3 +128,13 @@ func varFunc() {
 	var varfunc func(x int) int
 	_ = func(x int) int { return varfunc(x) }
 }
+
+func wrap(options ...string) error { return nil }
+
+var _ = func(options ...string) error {
+	return wrap(append(options, "timeout")...)
+}
+
+var _ = func(options ...string) error {
+	return wrap(append(append(append(options, "timeout")))...)
+}
diff --git a/checkers/testdata/unlambda/positive_tests.go b/checkers/testdata/unlambda/positive_tests.go
index 204f63d..6ef2cc6 100644
--- a/checkers/testdata/unlambda/positive_tests.go
+++ b/checkers/testdata/unlambda/positive_tests.go
@@ -48,6 +48,9 @@ func variadicTest() {
 
 	_ = func(x int, ys ...int) int { return variadicInt(1, 2) }
 	_ = func(x int, y int, _ ...int) int { return variadicInt(x, y) }
+
+	/*! replace `func(options ...string) error { return wrap(append(append(append(options)))...) }` with `wrap` */
+	_ = func(options ...string) error { return wrap(append(append(append(options)))...) }
 }
 
 func variadicInterfaces(x int, y interface{}, ys ...interface{}) int { return 0 }