Don't warn about negative/parenthesized int literals for non-int var decls.
diff --git a/lint.go b/lint.go
index f862a76..347209b 100644
--- a/lint.go
+++ b/lint.go
@@ -533,10 +533,8 @@
return false
}
// If the RHS is an int literal, only warn if the LHS type is "int".
- if lit, ok := rhs.(*ast.BasicLit); ok && lit.Kind == token.INT {
- if !isIdent(v.Type, "int") {
- return false
- }
+ if isIntLiteral(rhs) && !isIdent(v.Type, "int") {
+ return false
}
f.errorf(v.Type, 0.8, "should omit type %s from declaration of var %s; it will be inferred from the right-hand side", f.render(v.Type), v.Names[0])
return false
@@ -601,6 +599,14 @@
return buf.String()
}
+func (f *file) debugRender(x interface{}) string {
+ var buf bytes.Buffer
+ if err := ast.Fprint(&buf, f.fset, x, nil); err != nil {
+ panic(err)
+ }
+ return buf.String()
+}
+
// walker adapts a function to satisfy the ast.Visitor interface.
// The function return whether the walk should proceed into the node's children.
type walker func(ast.Node) bool
@@ -617,6 +623,30 @@
return ok && id.Name == ident
}
+func isIntLiteral(expr ast.Expr) bool {
+ // Either a BasicLit with Kind token.INT,
+ // or some combination of a UnaryExpr with Op token.SUB (for "-<lit>")
+ // or a ParenExpr (for "(<lit>)").
+Loop:
+ for {
+ switch v := expr.(type) {
+ case *ast.UnaryExpr:
+ if v.Op == token.SUB {
+ expr = v.X
+ continue Loop
+ }
+ case *ast.ParenExpr:
+ expr = v.X
+ continue Loop
+ case *ast.BasicLit:
+ if v.Kind == token.INT {
+ return true
+ }
+ }
+ return false
+ }
+}
+
// srcLine returns the complete line at p, including the terminating newline.
func srcLine(src []byte, p token.Position) string {
// Run to end of line in both directions if not at line start/end.
diff --git a/lint_test.go b/lint_test.go
index 4a06bca..e4ccbf3 100644
--- a/lint_test.go
+++ b/lint_test.go
@@ -8,6 +8,7 @@
import (
"bytes"
+ "flag"
"go/parser"
"go/printer"
"go/token"
@@ -18,8 +19,14 @@
"testing"
)
+var lintMatch = flag.String("lint.match", "", "restrict testdata matches to this pattern")
+
func TestAll(t *testing.T) {
l := new(Linter)
+ rx, err := regexp.Compile(*lintMatch)
+ if err != nil {
+ t.Fatalf("Bad -lint.match value %q: %v", *lintMatch, err)
+ }
baseDir := "testdata"
fis, err := ioutil.ReadDir(baseDir)
@@ -30,6 +37,9 @@
t.Fatalf("no files in %v", baseDir)
}
for _, fi := range fis {
+ if !rx.MatchString(fi.Name()) {
+ continue
+ }
//t.Logf("Testing %s", fi.Name())
src, err := ioutil.ReadFile(path.Join(baseDir, fi.Name()))
if err != nil {
diff --git a/testdata/var-decl.go b/testdata/var-decl.go
index 6b0f663..01c9dd6 100644
--- a/testdata/var-decl.go
+++ b/testdata/var-decl.go
@@ -30,6 +30,9 @@
// No warnings because the RHS is an ideal int, and the LHS is a different int type.
var userID int64 = 1235
+var negID int64 = -1
+var parenID int64 = (17)
+var crazyID int64 = -(-(-(-9)))
// No warning because the LHS names an interface type.
var data interface{} = googleIPs