From: Robert Griesemer Date: Thu, 14 Feb 2019 00:38:01 +0000 (-0800) Subject: cmd/gofmt: normalize integer imaginary literals starting with 0 X-Git-Tag: go1.13beta1~1460 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f8abdd6c8a6bb4882e708f87d1e83ba5f897aeff;p=gostls13.git cmd/gofmt: normalize integer imaginary literals starting with 0 An 'i' suffix on an integer literal marks the integer literal as a decimal integer imaginary value, even if the literal without the suffix starts with a 0 and thus looks like an octal value: 0123i == 123i // != 0123 * 1i This is at best confusing, and at worst a potential source of bugs. It is always safe to rewrite such literals into the equivalent literal without the leading 0. This CL implements this normalization. Change-Id: Ib77ad535f98b5be912ecbdec20ca1b472c1b4973 Reviewed-on: https://go-review.googlesource.com/c/162538 Run-TryBot: Robert Griesemer Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index ce4613fb60..4bba44489d 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -330,7 +330,9 @@ func backupFile(filename string, data []byte, perm os.FileMode) (string, error) } // normalizeNumbers rewrites base prefixes and exponents to -// use lower-case letters. It leaves hexadecimal digits alone. +// use lower-case letters, and removes leading 0's from +// integer imaginary literals. It leaves hexadecimal digits +// alone. func normalizeNumbers(n ast.Node) bool { lit, _ := n.(*ast.BasicLit) if lit == nil { @@ -339,37 +341,60 @@ func normalizeNumbers(n ast.Node) bool { if len(lit.Value) < 2 { return false // only one digit - nothing to do } - // lit.Value >= 2 + // len(lit.Value) >= 2 + x := lit.Value switch lit.Kind { case token.INT: - switch lit.Value[:2] { + switch x[:2] { case "0X": - lit.Value = "0x" + lit.Value[2:] + lit.Value = "0x" + x[2:] case "0O": - lit.Value = "0o" + lit.Value[2:] + lit.Value = "0o" + x[2:] case "0B": - lit.Value = "0b" + lit.Value[2:] + lit.Value = "0b" + x[2:] } case token.FLOAT: switch lit.Value[:2] { default: - if i := strings.LastIndexByte(lit.Value, 'E'); i >= 0 { - lit.Value = lit.Value[:i] + "e" + lit.Value[i+1:] + if i := strings.LastIndexByte(x, 'E'); i >= 0 { + lit.Value = x[:i] + "e" + x[i+1:] } case "0x": - if i := strings.LastIndexByte(lit.Value, 'P'); i >= 0 { - lit.Value = lit.Value[:i] + "p" + lit.Value[i+1:] + if i := strings.LastIndexByte(x, 'P'); i >= 0 { + lit.Value = x[:i] + "p" + x[i+1:] } case "0X": - if i := strings.LastIndexByte(lit.Value, 'P'); i >= 0 { - lit.Value = "0x" + lit.Value[2:i] + "p" + lit.Value[i+1:] + if i := strings.LastIndexByte(x, 'P'); i >= 0 { + lit.Value = "0x" + x[2:i] + "p" + x[i+1:] } else { - lit.Value = "0x" + lit.Value[2:] + lit.Value = "0x" + x[2:] + } + } + + case token.IMAG: + // Note that integer imaginary literals may contain + // any decimal digit even if they start with zero. + // Imaginary literals should always end in 'i' but be + // conservative and check anyway before proceeding. + if x[0] == '0' && x[len(x)-1] == 'i' && isDecimals(x[1:len(x)-1]) { + x = strings.TrimLeft(x, "0_") + if x == "i" { + x = "0i" } + lit.Value = x } } return false } + +// isDecimals reports whether x consists entirely of decimal digits and underscores. +func isDecimals(x string) bool { + i := 0 + for i < len(x) && ('0' <= x[i] && x[i] <= '9' || x[i] == '_') { + i++ + } + return i == len(x) +} diff --git a/src/cmd/gofmt/testdata/go2numbers.golden b/src/cmd/gofmt/testdata/go2numbers.golden index 2fab834bcd..abefcb6c58 100644 --- a/src/cmd/gofmt/testdata/go2numbers.golden +++ b/src/cmd/gofmt/testdata/go2numbers.golden @@ -141,10 +141,22 @@ const ( // imaginaries _ = 0i - _ = 00i + _ = 0i + _ = 8i + _ = 0i + _ = 123i + _ = 123i + _ = 56789i _ = 1234i _ = 1234567i + _ = 0i + _ = 0i + _ = 8i + _ = 0i + _ = 123i + _ = 123i + _ = 56_789i _ = 1_234i _ = 1_234_567i diff --git a/src/cmd/gofmt/testdata/go2numbers.input b/src/cmd/gofmt/testdata/go2numbers.input index 7b3fd391da..51a9f8eaf6 100644 --- a/src/cmd/gofmt/testdata/go2numbers.input +++ b/src/cmd/gofmt/testdata/go2numbers.input @@ -142,9 +142,21 @@ const ( // imaginaries _ = 0i _ = 00i + _ = 08i + _ = 0000000000i + _ = 0123i + _ = 0000000123i + _ = 0000056789i _ = 1234i _ = 1234567i + _ = 0i + _ = 0_0i + _ = 0_8i + _ = 0_000_000_000i + _ = 0_123i + _ = 0_000_000_123i + _ = 0_000_056_789i _ = 1_234i _ = 1_234_567i