mirror of https://github.com/golang/go.git
go/types, types2: test that error format strings have matching parentheses/brackets
Also, for go/types, switch to using syntax.Inspect instead of (deprecated) syntax.Crawl. Change-Id: I8333079040e9676e0a61c23d09d41ca790526eeb Reviewed-on: https://go-review.googlesource.com/c/go/+/460759 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Run-TryBot: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
cf5dbd4459
commit
d4639ecdfc
|
|
@ -6,13 +6,18 @@ package types2_test
|
|||
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const errorfMinArgCount = 4
|
||||
const (
|
||||
errorfMinArgCount = 4
|
||||
errorfFormatIndex = 2
|
||||
)
|
||||
|
||||
// TestErrorCalls makes sure that check.errorf calls have at least
|
||||
// errorfMinArgCount arguments (otherwise we should use check.error).
|
||||
// errorfMinArgCount arguments (otherwise we should use check.error)
|
||||
// and use balanced parentheses/brackets.
|
||||
func TestErrorCalls(t *testing.T) {
|
||||
files, err := pkgFiles(".")
|
||||
if err != nil {
|
||||
|
|
@ -20,17 +25,17 @@ func TestErrorCalls(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, file := range files {
|
||||
syntax.Crawl(file, func(n syntax.Node) bool {
|
||||
syntax.Inspect(file, func(n syntax.Node) bool {
|
||||
call, _ := n.(*syntax.CallExpr)
|
||||
if call == nil {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
selx, _ := call.Fun.(*syntax.SelectorExpr)
|
||||
if selx == nil {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
if !(isName(selx.X, "check") && isName(selx.Sel, "errorf")) {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
// check.errorf calls should have at least errorfMinArgCount arguments:
|
||||
// position, code, format string, and arguments to format
|
||||
|
|
@ -38,6 +43,18 @@ func TestErrorCalls(t *testing.T) {
|
|||
t.Errorf("%s: got %d arguments, want at least %d", call.Pos(), n, errorfMinArgCount)
|
||||
return false
|
||||
}
|
||||
format := call.ArgList[errorfFormatIndex]
|
||||
syntax.Inspect(format, func(n syntax.Node) bool {
|
||||
if lit, _ := n.(*syntax.BasicLit); lit != nil && lit.Kind == syntax.StringLit {
|
||||
if s, err := strconv.Unquote(lit.Value); err == nil {
|
||||
if !balancedParentheses(s) {
|
||||
t.Errorf("%s: unbalanced parentheses/brackets", lit.Pos())
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
|
@ -49,3 +66,30 @@ func isName(n syntax.Node, name string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func balancedParentheses(s string) bool {
|
||||
var stack []byte
|
||||
for _, ch := range s {
|
||||
var open byte
|
||||
switch ch {
|
||||
case '(', '[', '{':
|
||||
stack = append(stack, byte(ch))
|
||||
continue
|
||||
case ')':
|
||||
open = '('
|
||||
case ']':
|
||||
open = '['
|
||||
case '}':
|
||||
open = '{'
|
||||
default:
|
||||
continue
|
||||
}
|
||||
// closing parenthesis/bracket must have matching opening
|
||||
top := len(stack) - 1
|
||||
if top < 0 || stack[top] != open {
|
||||
return false
|
||||
}
|
||||
stack = stack[:top]
|
||||
}
|
||||
return len(stack) == 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,18 @@ package types_test
|
|||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const errorfMinArgCount = 4
|
||||
const (
|
||||
errorfMinArgCount = 4
|
||||
errorfFormatIndex = 2
|
||||
)
|
||||
|
||||
// TestErrorCalls makes sure that check.errorf calls have at least
|
||||
// errorfMinArgCount arguments (otherwise we should use check.error).
|
||||
// errorfMinArgCount arguments (otherwise we should use check.error)
|
||||
// and use balanced parentheses/brackets.
|
||||
func TestErrorCalls(t *testing.T) {
|
||||
fset := token.NewFileSet()
|
||||
files, err := pkgFiles(fset, ".")
|
||||
|
|
@ -40,7 +45,19 @@ func TestErrorCalls(t *testing.T) {
|
|||
t.Errorf("%s: got %d arguments, want at least %d", fset.Position(call.Pos()), n, errorfMinArgCount)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
format := call.Args[errorfFormatIndex]
|
||||
ast.Inspect(format, func(n ast.Node) bool {
|
||||
if lit, _ := n.(*ast.BasicLit); lit != nil && lit.Kind == token.STRING {
|
||||
if s, err := strconv.Unquote(lit.Value); err == nil {
|
||||
if !balancedParentheses(s) {
|
||||
t.Errorf("%s: unbalanced parentheses/brackets", fset.Position(lit.ValuePos))
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -51,3 +68,30 @@ func isName(n ast.Node, name string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func balancedParentheses(s string) bool {
|
||||
var stack []byte
|
||||
for _, ch := range s {
|
||||
var open byte
|
||||
switch ch {
|
||||
case '(', '[', '{':
|
||||
stack = append(stack, byte(ch))
|
||||
continue
|
||||
case ')':
|
||||
open = '('
|
||||
case ']':
|
||||
open = '['
|
||||
case '}':
|
||||
open = '{'
|
||||
default:
|
||||
continue
|
||||
}
|
||||
// closing parenthesis/bracket must have matching opening
|
||||
top := len(stack) - 1
|
||||
if top < 0 || stack[top] != open {
|
||||
return false
|
||||
}
|
||||
stack = stack[:top]
|
||||
}
|
||||
return len(stack) == 0
|
||||
}
|
||||
Loading…
Reference in New Issue