8056897: Improve error recovery for empty binary and hexadecimal literals.
Reviewed-by: mcimadamore
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Fri Jan 08 22:24:15 2016 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Mon Jan 11 11:21:10 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -301,15 +301,16 @@
}
/** Read a number.
- * @param radix The radix of the number; one of 2, j8, 10, 16.
+ * @param radix The radix of the number; one of 2, 8, 10, 16.
*/
private void scanNumber(int pos, int radix) {
// for octal, allow base-10 digit in case it's a float literal
this.radix = radix;
int digitRadix = (radix == 8 ? 10 : radix);
- boolean seendigit = false;
- if (reader.digit(pos, digitRadix) >= 0) {
- seendigit = true;
+ int firstDigit = reader.digit(pos, Math.max(10, digitRadix));
+ boolean seendigit = firstDigit >= 0;
+ boolean seenValidDigit = firstDigit >= 0 && firstDigit < digitRadix;
+ if (seendigit) {
scanDigits(pos, digitRadix);
}
if (radix == 16 && reader.ch == '.') {
@@ -325,6 +326,16 @@
reader.ch == 'd' || reader.ch == 'D')) {
scanFractionAndSuffix(pos);
} else {
+ if (!seenValidDigit) {
+ switch (radix) {
+ case 2:
+ lexError(pos, "invalid.binary.number");
+ break;
+ case 16:
+ lexError(pos, "invalid.hex.number");
+ break;
+ }
+ }
if (reader.ch == 'l' || reader.ch == 'L') {
reader.scanChar();
tk = TokenKind.LONGLITERAL;
@@ -491,13 +502,7 @@
if (reader.ch == 'x' || reader.ch == 'X') {
reader.scanChar();
skipIllegalUnderscores();
- if (reader.ch == '.') {
- scanHexFractionAndSuffix(pos, false);
- } else if (reader.digit(pos, 16) < 0) {
- lexError(pos, "invalid.hex.number");
- } else {
- scanNumber(pos, 16);
- }
+ scanNumber(pos, 16);
} else if (reader.ch == 'b' || reader.ch == 'B') {
if (!allowBinaryLiterals) {
lexError(pos, "unsupported.binary.lit", source.name);
@@ -505,11 +510,7 @@
}
reader.scanChar();
skipIllegalUnderscores();
- if (reader.digit(pos, 2) < 0) {
- lexError(pos, "invalid.binary.number");
- } else {
- scanNumber(pos, 2);
- }
+ scanNumber(pos, 2);
} else {
reader.putChar('0');
if (reader.ch == '_') {
--- a/langtools/test/tools/javac/BadHexConstant.java Fri Jan 08 22:24:15 2016 -0800
+++ b/langtools/test/tools/javac/BadHexConstant.java Mon Jan 11 11:21:10 2016 +0100
@@ -1,6 +1,6 @@
/*
* @test /nodynamiccopyright/
- * @bug 4049982
+ * @bug 4049982 8056897
* @summary Compiler permitted invalid hex literal.
* @author turnidge
*
--- a/langtools/test/tools/javac/BadHexConstant.out Fri Jan 08 22:24:15 2016 -0800
+++ b/langtools/test/tools/javac/BadHexConstant.out Mon Jan 11 11:21:10 2016 +0100
@@ -1,3 +1,2 @@
BadHexConstant.java:12:14: compiler.err.invalid.hex.number
-BadHexConstant.java:12:17: compiler.err.expected: token.identifier
-2 errors
+1 error
--- a/langtools/test/tools/javac/diags/examples/IdentifierExpected.java Fri Jan 08 22:24:15 2016 -0800
+++ b/langtools/test/tools/javac/diags/examples/IdentifierExpected.java Mon Jan 11 11:21:10 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,9 @@
// key: compiler.misc.token.identifier
// key: compiler.err.expected
-// key: compiler.err.invalid.binary.number
-// key: compiler.misc.count.error.plural
+// key: compiler.misc.count.error
// key: compiler.err.error
// run: backdoor
-class IdentifierExpected {
- long bl = 0BL;
+class {
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lexer/JavaLexerTest.java Mon Jan 11 11:21:10 2016 +0100
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8056897
+ * @summary Proper lexing of integer literals.
+ */
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Objects;
+
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+
+import com.sun.tools.javac.parser.JavaTokenizer;
+import com.sun.tools.javac.parser.ScannerFactory;
+import com.sun.tools.javac.parser.Tokens.Token;
+import com.sun.tools.javac.parser.Tokens.TokenKind;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+
+public class JavaLexerTest {
+ public static void main(String... args) throws Exception {
+ new JavaLexerTest().run();
+ }
+
+ void run() throws Exception {
+ Context ctx = new Context();
+ Log log = Log.instance(ctx);
+ String input = "0bL 0b20L 0xL ";
+ log.useSource(new SimpleJavaFileObject(new URI("mem://Test.java"), JavaFileObject.Kind.SOURCE) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return input;
+ }
+ });
+ char[] inputArr = input.toCharArray();
+ JavaTokenizer tokenizer = new JavaTokenizer(ScannerFactory.instance(ctx), inputArr, inputArr.length) {
+ };
+
+ assertKind(input, tokenizer, TokenKind.LONGLITERAL, "0bL");
+ assertKind(input, tokenizer, TokenKind.LONGLITERAL, "0b20L");
+ assertKind(input, tokenizer, TokenKind.LONGLITERAL, "0xL");
+ }
+
+ void assertKind(String input, JavaTokenizer tokenizer, TokenKind kind, String expectedText) {
+ Token token = tokenizer.readToken();
+
+ if (token.kind != kind) {
+ throw new AssertionError("Unexpected token kind: " + token.kind);
+ }
+
+ String actualText = input.substring(token.pos, token.endPos);
+
+ if (!Objects.equals(actualText, expectedText)) {
+ throw new AssertionError("Unexpected token text: " + actualText);
+ }
+ }
+}
\ No newline at end of file
--- a/langtools/test/tools/javac/literals/T6891079.java Fri Jan 08 22:24:15 2016 -0800
+++ b/langtools/test/tools/javac/literals/T6891079.java Mon Jan 11 11:21:10 2016 +0100
@@ -1,5 +1,5 @@
/* @test /nodynamiccopyright/
- * @bug 6891079
+ * @bug 6891079 8056897
* @summary Compiler allows invalid binary literals 0b and oBL
* @compile/fail/ref=T6891079.out -XDrawDiagnostics T6891079.java
*/
--- a/langtools/test/tools/javac/literals/T6891079.out Fri Jan 08 22:24:15 2016 -0800
+++ b/langtools/test/tools/javac/literals/T6891079.out Mon Jan 11 11:21:10 2016 +0100
@@ -1,7 +1,5 @@
T6891079.java:8:14: compiler.err.invalid.binary.number
T6891079.java:9:15: compiler.err.invalid.binary.number
-T6891079.java:9:18: compiler.err.expected: token.identifier
T6891079.java:10:14: compiler.err.invalid.hex.number
T6891079.java:11:15: compiler.err.invalid.hex.number
-T6891079.java:11:18: compiler.err.expected: token.identifier
-6 errors
+4 errors