Commit 7c8e057a authored by Rob Pike's avatar Rob Pike

fmt: make the %#v verb a special flag

The %#v verb is special: it says all values below need to print as %#v.
However, for some situations the # flag has other meanings and this
causes some issues, particularly in how Formatters work. Since %#v
dominates all formatting, translate it into actual state of the formatter
and decouple it from the # flag itself within the calculations (although
it must be restored when methods are doing the work.)
The result is cleaner code and correct handling of # for Formatters.
TODO: Apply the same thinking to the + flag in a followup CL.

Also, the wasString return value in handleMethods is always false,
so eliminate it.

Update #8835

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/146650043
parent 28ddfb09
...@@ -1144,10 +1144,10 @@ var panictests = []struct { ...@@ -1144,10 +1144,10 @@ var panictests = []struct {
} }
func TestPanics(t *testing.T) { func TestPanics(t *testing.T) {
for _, tt := range panictests { for i, tt := range panictests {
s := Sprintf(tt.fmt, tt.in) s := Sprintf(tt.fmt, tt.in)
if s != tt.out { if s != tt.out {
t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out) t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
} }
} }
} }
...@@ -1207,3 +1207,94 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { ...@@ -1207,3 +1207,94 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
} }
} }
// Formatters did not get delivered flags correctly in all cases. Issue 8835.
type fp struct{}
func (fp) Format(f State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
s += string(i)
}
}
if w, ok := f.Width(); ok {
s += Sprintf("%d", w)
}
if p, ok := f.Precision(); ok {
s += Sprintf(".%d", p)
}
s += string(c)
io.WriteString(f, "["+s+"]")
}
var formatterFlagTests = []struct {
in string
val interface{}
out string
}{
// scalar values with the (unused by fmt) 'a' verb.
{"%a", fp{}, "[%a]"},
{"%-a", fp{}, "[%-a]"},
{"%+a", fp{}, "[%+a]"},
{"%#a", fp{}, "[%#a]"},
{"% a", fp{}, "[% a]"},
{"%0a", fp{}, "[%0a]"},
{"%1.2a", fp{}, "[%1.2a]"},
{"%-1.2a", fp{}, "[%-1.2a]"},
{"%+1.2a", fp{}, "[%+1.2a]"},
{"%-+1.2a", fp{}, "[%+-1.2a]"},
{"%-+1.2abc", fp{}, "[%+-1.2a]bc"},
{"%-1.2abc", fp{}, "[%-1.2a]bc"},
// composite values with the 'a' verb
{"%a", [1]fp{}, "[[%a]]"},
{"%-a", [1]fp{}, "[[%-a]]"},
{"%+a", [1]fp{}, "[[%+a]]"},
{"%#a", [1]fp{}, "[[%#a]]"},
{"% a", [1]fp{}, "[[% a]]"},
{"%0a", [1]fp{}, "[[%0a]]"},
{"%1.2a", [1]fp{}, "[[%1.2a]]"},
{"%-1.2a", [1]fp{}, "[[%-1.2a]]"},
{"%+1.2a", [1]fp{}, "[[%+1.2a]]"},
{"%-+1.2a", [1]fp{}, "[[%+-1.2a]]"},
{"%-+1.2abc", [1]fp{}, "[[%+-1.2a]]bc"},
{"%-1.2abc", [1]fp{}, "[[%-1.2a]]bc"},
// simple values with the 'v' verb
{"%v", fp{}, "[%v]"},
{"%-v", fp{}, "[%-v]"},
{"%+v", fp{}, "[%+v]"},
{"%#v", fp{}, "[%#v]"},
{"% v", fp{}, "[% v]"},
{"%0v", fp{}, "[%0v]"},
{"%1.2v", fp{}, "[%1.2v]"},
{"%-1.2v", fp{}, "[%-1.2v]"},
{"%+1.2v", fp{}, "[%+1.2v]"},
{"%-+1.2v", fp{}, "[%+-1.2v]"},
{"%-+1.2vbc", fp{}, "[%+-1.2v]bc"},
{"%-1.2vbc", fp{}, "[%-1.2v]bc"},
// composite values with the 'v' verb. Some are still broken.
{"%v", [1]fp{}, "[[%v]]"},
{"%-v", [1]fp{}, "[[%-v]]"},
//{"%+v", [1]fp{}, "[[%+v]]"},
{"%#v", [1]fp{}, "[1]fmt_test.fp{[%#v]}"},
{"% v", [1]fp{}, "[[% v]]"},
{"%0v", [1]fp{}, "[[%0v]]"},
{"%1.2v", [1]fp{}, "[[%1.2v]]"},
{"%-1.2v", [1]fp{}, "[[%-1.2v]]"},
//{"%+1.2v", [1]fp{}, "[[%+1.2v]]"},
//{"%-+1.2v", [1]fp{}, "[[%+-1.2v]]"},
//{"%-+1.2vbc", [1]fp{}, "[[%+-1.2v]]bc"},
{"%-1.2vbc", [1]fp{}, "[[%-1.2v]]bc"},
}
func TestFormatterFlags(t *testing.T) {
for _, tt := range formatterFlagTests {
s := Sprintf(tt.in, tt.val)
if s != tt.out {
t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out)
}
}
}
...@@ -49,6 +49,11 @@ type fmt struct { ...@@ -49,6 +49,11 @@ type fmt struct {
plus bool plus bool
sharp bool sharp bool
space bool space bool
// For the format %#v, we set this flag and
// clear the plus flag, since it is in effect
// a different, flagless format set at the top level.
// TODO: plusV could use this too.
sharpV bool
unicode bool unicode bool
uniQuote bool // Use 'x'= prefix for %U if printable. uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool zero bool
...@@ -63,6 +68,7 @@ func (f *fmt) clearflags() { ...@@ -63,6 +68,7 @@ func (f *fmt) clearflags() {
f.plus = false f.plus = false
f.sharp = false f.sharp = false
f.space = false f.space = false
f.sharpV = false
f.unicode = false f.unicode = false
f.uniQuote = false f.uniQuote = false
f.zero = false f.zero = false
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment