1
2
3
4
5 package types2_test
6
7 import (
8 "cmd/compile/internal/syntax"
9 "strconv"
10 "testing"
11 )
12
13 const (
14 errorfMinArgCount = 4
15 errorfFormatIndex = 2
16 )
17
18
19
20
21 func TestErrorCalls(t *testing.T) {
22 files, err := pkgFiles(".")
23 if err != nil {
24 t.Fatal(err)
25 }
26
27 for _, file := range files {
28 syntax.Inspect(file, func(n syntax.Node) bool {
29 call, _ := n.(*syntax.CallExpr)
30 if call == nil {
31 return true
32 }
33 selx, _ := call.Fun.(*syntax.SelectorExpr)
34 if selx == nil {
35 return true
36 }
37 if !(isName(selx.X, "check") && isName(selx.Sel, "errorf")) {
38 return true
39 }
40
41
42 if n := len(call.ArgList); n < errorfMinArgCount {
43 t.Errorf("%s: got %d arguments, want at least %d", call.Pos(), n, errorfMinArgCount)
44 return false
45 }
46 format := call.ArgList[errorfFormatIndex]
47 syntax.Inspect(format, func(n syntax.Node) bool {
48 if lit, _ := n.(*syntax.BasicLit); lit != nil && lit.Kind == syntax.StringLit {
49 if s, err := strconv.Unquote(lit.Value); err == nil {
50 if !balancedParentheses(s) {
51 t.Errorf("%s: unbalanced parentheses/brackets", lit.Pos())
52 }
53 }
54 return false
55 }
56 return true
57 })
58 return false
59 })
60 }
61 }
62
63 func isName(n syntax.Node, name string) bool {
64 if n, ok := n.(*syntax.Name); ok {
65 return n.Value == name
66 }
67 return false
68 }
69
70 func balancedParentheses(s string) bool {
71 var stack []byte
72 for _, ch := range s {
73 var open byte
74 switch ch {
75 case '(', '[', '{':
76 stack = append(stack, byte(ch))
77 continue
78 case ')':
79 open = '('
80 case ']':
81 open = '['
82 case '}':
83 open = '{'
84 default:
85 continue
86 }
87
88 top := len(stack) - 1
89 if top < 0 || stack[top] != open {
90 return false
91 }
92 stack = stack[:top]
93 }
94 return len(stack) == 0
95 }
96
View as plain text