diff --git a/analyzer/testdata/src/regression/issue291.go b/analyzer/testdata/src/regression/issue291.go index 7ef84eb8..866aa8d3 100644 --- a/analyzer/testdata/src/regression/issue291.go +++ b/analyzer/testdata/src/regression/issue291.go @@ -3,21 +3,27 @@ package regression type explicitIntType int const ( - ZeroExplicit explicitIntType = iota // want `\Qavoid use of iota for constant types` + ZeroExplicit explicitIntType = iota // want `\Qgood, have explicit type` OneExplicit TwoExplicit ) type implicitIntType int +// Matched due to the #295. +const typedIotaWithoutGroup int = iota // want `\Qgood, have explicit type` + const ( - ZeroImplicit = iota // want `\Qavoid use of iota for constant types` + ZeroImplicit = iota // want `\Qavoid use of iota without explicit type` OneImplicit TwoImplicit ) type noIotaIntType int +// Matched due to the #295. +const iotaWithoutGroup = iota // want `\Qavoid use of iota without explicit type` + const ( ZeroNoIota = 0 OneNoIota = 1 diff --git a/analyzer/testdata/src/regression/rules.go b/analyzer/testdata/src/regression/rules.go index 98e2d1a6..259383fe 100644 --- a/analyzer/testdata/src/regression/rules.go +++ b/analyzer/testdata/src/regression/rules.go @@ -35,8 +35,13 @@ func issue192(m dsl.Matcher) { } func issue291(m dsl.Matcher) { - m.Match(`$_ $_ = $iota`, `const ( $_ = $iota; $*_ )`). + m.Match(`const ( $_ = $iota; $*_ )`). Where(m["iota"].Text == "iota"). At(m["iota"]). - Report("avoid use of iota for constant types") + Report("avoid use of iota without explicit type") + + m.Match(`const ( $_ $_ = $iota; $*_ )`). + Where(m["iota"].Text == "iota"). + At(m["iota"]). + Report("good, have explicit type") } diff --git a/internal/gogrep/compile.go b/internal/gogrep/compile.go index 7e267a53..8fd6b782 100644 --- a/internal/gogrep/compile.go +++ b/internal/gogrep/compile.go @@ -231,7 +231,7 @@ func (c *compiler) compileValueSpec(spec *ast.ValueSpec) { } c.emitInstOp(opEnd) if spec.Type != nil { - c.compileExpr(spec.Type) + c.compileOptExpr(spec.Type) } if len(spec.Values) != 0 { for _, v := range spec.Values { diff --git a/internal/gogrep/compile_test.go b/internal/gogrep/compile_test.go index 3f13a242..c9d9759f 100644 --- a/internal/gogrep/compile_test.go +++ b/internal/gogrep/compile_test.go @@ -356,6 +356,17 @@ func TestCompileWildcard(t *testing.T) { ` • Ident s`, ` • OptNode`, }, + + `const $_ $*_ = iota`: { + `ConstDecl`, + ` • TypedValueInitSpec`, + ` • • Node`, + ` • • End`, + ` • • OptNode`, + ` • • Ident iota`, + ` • • End`, + ` • End`, + }, }) for i := range tests { diff --git a/internal/gogrep/match.go b/internal/gogrep/match.go index 39b71c46..0e658ff3 100644 --- a/internal/gogrep/match.go +++ b/internal/gogrep/match.go @@ -529,7 +529,7 @@ func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast m.matchIdentSlice(state, n.Names) && m.matchNode(state, n.Type) case opTypedValueInitSpec: n, ok := n.(*ast.ValueSpec) - return ok && len(n.Values) != 0 && n.Type != nil && + return ok && len(n.Values) != 0 && m.matchIdentSlice(state, n.Names) && m.matchNode(state, n.Type) && m.matchExprSlice(state, n.Values) case opTypeSpec: diff --git a/internal/gogrep/match_test.go b/internal/gogrep/match_test.go index bee4427f..a884f28d 100644 --- a/internal/gogrep/match_test.go +++ b/internal/gogrep/match_test.go @@ -803,6 +803,14 @@ func TestMatch(t *testing.T) { {`func $_($_) {}`, 0, `package p; func f() {}`}, // Gen decl. + {`const $_ $*_ = iota`, 1, `const foo = iota`}, + {`const $_ $*_ = iota`, 1, `const foo int = iota`}, + {`const $_ $*_ = iota`, 1, `const (foo = iota)`}, + {`const $_ $*_ = iota`, 1, `const (foo int = iota)`}, + {`const $_ $*_ = iota`, 0, `const foo int = 0`}, + {`const $_ $*_ = iota`, 0, `var foo = iota`}, + {`const $_ $_ = iota`, 1, `const foo int = iota`}, + {`const $_ $_ = iota`, 0, `const foo = iota`}, {`const $x = $y`, 1, `const a = b`}, {`const $x = $y`, 1, `const (a = b)`}, {`const $x = $y`, 0, "const (a = b\nc = d)"},