]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: remove unnecessary isValidNumber call
authorDaniel Martí <mvdan@mvdan.cc>
Tue, 2 Jul 2019 22:37:05 +0000 (00:37 +0200)
committerDaniel Martí <mvdan@mvdan.cc>
Tue, 27 Aug 2019 17:53:55 +0000 (17:53 +0000)
The decoder called this function to check numbers being decoded into a
json.Number. However, these can't be quoted as strings, so the tokenizer
has already verified they are valid JSON numbers.

Verified this by adding a test with such an input. As expected, it
produces a syntax error, not the fmt.Errorf - that line could never
execute.

Since the only remaining non-test caller of isvalidnumber is in
encode.go, move the function there.

This change should slightly reduce the amount of work when decoding into
json.Number, though that isn't very common nor part of any current
benchmarks.

Change-Id: I67a1723deb3d18d5b542d6dd35f3ae56a43f23eb
Reviewed-on: https://go-review.googlesource.com/c/go/+/184817
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/encoding/json/decode.go
src/encoding/json/decode_test.go
src/encoding/json/encode.go

index cbd71acfc6c38f7827dd4290fcf6ca7bfbb68d47..df1c085917832ab831bc7ae171da8db603a37e2b 100644 (file)
@@ -199,66 +199,6 @@ func (n Number) Int64() (int64, error) {
        return strconv.ParseInt(string(n), 10, 64)
 }
 
-// isValidNumber reports whether s is a valid JSON number literal.
-func isValidNumber(s string) bool {
-       // This function implements the JSON numbers grammar.
-       // See https://tools.ietf.org/html/rfc7159#section-6
-       // and https://json.org/number.gif
-
-       if s == "" {
-               return false
-       }
-
-       // Optional -
-       if s[0] == '-' {
-               s = s[1:]
-               if s == "" {
-                       return false
-               }
-       }
-
-       // Digits
-       switch {
-       default:
-               return false
-
-       case s[0] == '0':
-               s = s[1:]
-
-       case '1' <= s[0] && s[0] <= '9':
-               s = s[1:]
-               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
-                       s = s[1:]
-               }
-       }
-
-       // . followed by 1 or more digits.
-       if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
-               s = s[2:]
-               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
-                       s = s[1:]
-               }
-       }
-
-       // e or E followed by an optional - or + and
-       // 1 or more digits.
-       if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
-               s = s[1:]
-               if s[0] == '+' || s[0] == '-' {
-                       s = s[1:]
-                       if s == "" {
-                               return false
-                       }
-               }
-               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
-                       s = s[1:]
-               }
-       }
-
-       // Make sure we are at the end.
-       return s == ""
-}
-
 // decodeState represents the state while decoding a JSON value.
 type decodeState struct {
        data         []byte
@@ -1027,10 +967,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                switch v.Kind() {
                default:
                        if v.Kind() == reflect.String && v.Type() == numberType {
+                               // s must be a valid number, because it's
+                               // already been tokenized.
                                v.SetString(s)
-                               if !isValidNumber(s) {
-                                       return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)
-                               }
                                break
                        }
                        if fromQuoted {
index d66be44d4e134f138a3cf8cf0980eac2cb11fdd3..8dcb08cbd27762a39efa5d7a3336c8368484e6ea 100644 (file)
@@ -448,6 +448,7 @@ var unmarshalTests = []unmarshalTest{
        {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
        {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
        {in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}},
+       {in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}},
 
        // raw value errors
        {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
index 67412763d64009d47ba3b51b110819b1474f3317..07d3098f1c1edf4fa1746752177cfec3a1551366 100644 (file)
@@ -611,6 +611,66 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
        }
 }
 
+// isValidNumber reports whether s is a valid JSON number literal.
+func isValidNumber(s string) bool {
+       // This function implements the JSON numbers grammar.
+       // See https://tools.ietf.org/html/rfc7159#section-6
+       // and https://json.org/number.gif
+
+       if s == "" {
+               return false
+       }
+
+       // Optional -
+       if s[0] == '-' {
+               s = s[1:]
+               if s == "" {
+                       return false
+               }
+       }
+
+       // Digits
+       switch {
+       default:
+               return false
+
+       case s[0] == '0':
+               s = s[1:]
+
+       case '1' <= s[0] && s[0] <= '9':
+               s = s[1:]
+               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+                       s = s[1:]
+               }
+       }
+
+       // . followed by 1 or more digits.
+       if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
+               s = s[2:]
+               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+                       s = s[1:]
+               }
+       }
+
+       // e or E followed by an optional - or + and
+       // 1 or more digits.
+       if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
+               s = s[1:]
+               if s[0] == '+' || s[0] == '-' {
+                       s = s[1:]
+                       if s == "" {
+                               return false
+                       }
+               }
+               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+                       s = s[1:]
+               }
+       }
+
+       // Make sure we are at the end.
+       return s == ""
+}
+
 func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) {
        if v.IsNil() {
                e.WriteString("null")