Skip to content

Commit f8abdd6

Browse files
committed
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 <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 613f0a3 commit f8abdd6

File tree

3 files changed

+63
-14
lines changed

3 files changed

+63
-14
lines changed

src/cmd/gofmt/gofmt.go

+38-13
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,9 @@ func backupFile(filename string, data []byte, perm os.FileMode) (string, error)
330330
}
331331

332332
// normalizeNumbers rewrites base prefixes and exponents to
333-
// use lower-case letters. It leaves hexadecimal digits alone.
333+
// use lower-case letters, and removes leading 0's from
334+
// integer imaginary literals. It leaves hexadecimal digits
335+
// alone.
334336
func normalizeNumbers(n ast.Node) bool {
335337
lit, _ := n.(*ast.BasicLit)
336338
if lit == nil {
@@ -339,37 +341,60 @@ func normalizeNumbers(n ast.Node) bool {
339341
if len(lit.Value) < 2 {
340342
return false // only one digit - nothing to do
341343
}
342-
// lit.Value >= 2
344+
// len(lit.Value) >= 2
343345

346+
x := lit.Value
344347
switch lit.Kind {
345348
case token.INT:
346-
switch lit.Value[:2] {
349+
switch x[:2] {
347350
case "0X":
348-
lit.Value = "0x" + lit.Value[2:]
351+
lit.Value = "0x" + x[2:]
349352
case "0O":
350-
lit.Value = "0o" + lit.Value[2:]
353+
lit.Value = "0o" + x[2:]
351354
case "0B":
352-
lit.Value = "0b" + lit.Value[2:]
355+
lit.Value = "0b" + x[2:]
353356
}
354357

355358
case token.FLOAT:
356359
switch lit.Value[:2] {
357360
default:
358-
if i := strings.LastIndexByte(lit.Value, 'E'); i >= 0 {
359-
lit.Value = lit.Value[:i] + "e" + lit.Value[i+1:]
361+
if i := strings.LastIndexByte(x, 'E'); i >= 0 {
362+
lit.Value = x[:i] + "e" + x[i+1:]
360363
}
361364
case "0x":
362-
if i := strings.LastIndexByte(lit.Value, 'P'); i >= 0 {
363-
lit.Value = lit.Value[:i] + "p" + lit.Value[i+1:]
365+
if i := strings.LastIndexByte(x, 'P'); i >= 0 {
366+
lit.Value = x[:i] + "p" + x[i+1:]
364367
}
365368
case "0X":
366-
if i := strings.LastIndexByte(lit.Value, 'P'); i >= 0 {
367-
lit.Value = "0x" + lit.Value[2:i] + "p" + lit.Value[i+1:]
369+
if i := strings.LastIndexByte(x, 'P'); i >= 0 {
370+
lit.Value = "0x" + x[2:i] + "p" + x[i+1:]
368371
} else {
369-
lit.Value = "0x" + lit.Value[2:]
372+
lit.Value = "0x" + x[2:]
373+
}
374+
}
375+
376+
case token.IMAG:
377+
// Note that integer imaginary literals may contain
378+
// any decimal digit even if they start with zero.
379+
// Imaginary literals should always end in 'i' but be
380+
// conservative and check anyway before proceeding.
381+
if x[0] == '0' && x[len(x)-1] == 'i' && isDecimals(x[1:len(x)-1]) {
382+
x = strings.TrimLeft(x, "0_")
383+
if x == "i" {
384+
x = "0i"
370385
}
386+
lit.Value = x
371387
}
372388
}
373389

374390
return false
375391
}
392+
393+
// isDecimals reports whether x consists entirely of decimal digits and underscores.
394+
func isDecimals(x string) bool {
395+
i := 0
396+
for i < len(x) && ('0' <= x[i] && x[i] <= '9' || x[i] == '_') {
397+
i++
398+
}
399+
return i == len(x)
400+
}

src/cmd/gofmt/testdata/go2numbers.golden

+13-1
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,22 @@ const (
141141

142142
// imaginaries
143143
_ = 0i
144-
_ = 00i
144+
_ = 0i
145+
_ = 8i
146+
_ = 0i
147+
_ = 123i
148+
_ = 123i
149+
_ = 56789i
145150
_ = 1234i
146151
_ = 1234567i
147152

153+
_ = 0i
154+
_ = 0i
155+
_ = 8i
156+
_ = 0i
157+
_ = 123i
158+
_ = 123i
159+
_ = 56_789i
148160
_ = 1_234i
149161
_ = 1_234_567i
150162

src/cmd/gofmt/testdata/go2numbers.input

+12
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,21 @@ const (
142142
// imaginaries
143143
_ = 0i
144144
_ = 00i
145+
_ = 08i
146+
_ = 0000000000i
147+
_ = 0123i
148+
_ = 0000000123i
149+
_ = 0000056789i
145150
_ = 1234i
146151
_ = 1234567i
147152

153+
_ = 0i
154+
_ = 0_0i
155+
_ = 0_8i
156+
_ = 0_000_000_000i
157+
_ = 0_123i
158+
_ = 0_000_000_123i
159+
_ = 0_000_056_789i
148160
_ = 1_234i
149161
_ = 1_234_567i
150162

0 commit comments

Comments
 (0)