Skip to content

Commit f6440c8

Browse files
AlexanderYastrebovtimothy-king
authored andcommitted
x/tools: print check misses concatenated strings
Fixes golang/go#30436 Change-Id: I5b843e65b2188040a1ea5f17e1756b57babb0c22 GitHub-Last-Rev: 3ee8e18 GitHub-Pull-Request: #344 Reviewed-on: https://go-review.googlesource.com/c/tools/+/356830 Trust: Tim King <taking@google.com> Trust: Zvonimir Pavlinovic <zpavlinovic@google.com> Run-TryBot: Tim King <taking@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
1 parent bb4add0 commit f6440c8

File tree

2 files changed

+19
-11
lines changed

2 files changed

+19
-11
lines changed

go/analysis/passes/printf/printf.go

+14-8
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,15 @@ func stringConstantArg(pass *analysis.Pass, call *ast.CallExpr, idx int) (string
452452
if idx >= len(call.Args) {
453453
return "", false
454454
}
455-
arg := call.Args[idx]
456-
lit := pass.TypesInfo.Types[arg].Value
455+
return stringConstantExpr(pass, call.Args[idx])
456+
}
457+
458+
// stringConstantExpr returns expression's string constant value.
459+
//
460+
// ("", false) is returned if expression isn't a string
461+
// constant.
462+
func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) {
463+
lit := pass.TypesInfo.Types[expr].Value
457464
if lit != nil && lit.Kind() == constant.String {
458465
return constant.StringVal(lit), true
459466
}
@@ -1053,10 +1060,10 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
10531060
}
10541061

10551062
arg := args[0]
1056-
if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
1057-
// Ignore trailing % character in lit.Value.
1063+
if s, ok := stringConstantExpr(pass, arg); ok {
1064+
// Ignore trailing % character
10581065
// The % in "abc 0.0%" couldn't be a formatting directive.
1059-
s := strings.TrimSuffix(lit.Value, `%"`)
1066+
s = strings.TrimSuffix(s, "%")
10601067
if strings.Contains(s, "%") {
10611068
m := printFormatRE.FindStringSubmatch(s)
10621069
if m != nil {
@@ -1067,9 +1074,8 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
10671074
if strings.HasSuffix(fn.Name(), "ln") {
10681075
// The last item, if a string, should not have a newline.
10691076
arg = args[len(args)-1]
1070-
if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
1071-
str, _ := strconv.Unquote(lit.Value)
1072-
if strings.HasSuffix(str, "\n") {
1077+
if s, ok := stringConstantExpr(pass, arg); ok {
1078+
if strings.HasSuffix(s, "\n") {
10731079
pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName())
10741080
}
10751081
}

go/analysis/passes/printf/testdata/src/a/a.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ func PrintfTests() {
153153
fmt.Println("%s", "hi") // want "fmt.Println call has possible formatting directive %s"
154154
fmt.Println("%v", "hi") // want "fmt.Println call has possible formatting directive %v"
155155
fmt.Println("%T", "hi") // want "fmt.Println call has possible formatting directive %T"
156+
fmt.Println("%s"+" there", "hi") // want "fmt.Println call has possible formatting directive %s"
156157
fmt.Println("0.0%") // correct (trailing % couldn't be a formatting directive)
157158
fmt.Printf("%s", "hi", 3) // want "fmt.Printf call needs 1 arg but has 2 args"
158159
_ = fmt.Sprintf("%"+("s"), "hi", 3) // want "fmt.Sprintf call needs 1 arg but has 2 args"
@@ -768,9 +769,10 @@ func UnexportedStringerOrError() {
768769
fmt.Printf("%s", uei) // want "Printf format %s has arg uei of wrong type a.unexportedErrorInterface"
769770
fmt.Println("foo\n", "bar") // not an error
770771

771-
fmt.Println("foo\n") // want "Println arg list ends with redundant newline"
772-
fmt.Println("foo\\n") // not an error
773-
fmt.Println(`foo\n`) // not an error
772+
fmt.Println("foo\n") // want "Println arg list ends with redundant newline"
773+
fmt.Println("foo" + "\n") // want "Println arg list ends with redundant newline"
774+
fmt.Println("foo\\n") // not an error
775+
fmt.Println(`foo\n`) // not an error
774776

775777
intSlice := []int{3, 4}
776778
fmt.Printf("%s", intSlice) // want `fmt.Printf format %s has arg intSlice of wrong type \[\]int`

0 commit comments

Comments
 (0)