8167343: JShell: Completeness analysis infers an incomplete declaration as COMPLETE_WITH_SEMI, which is a first line of Allman style

Reviewed-by: rfield
This commit is contained in:
Shinya Yoshida 2016-10-11 00:28:49 +09:00
parent ece1def9ae
commit a53b8b8a5d
2 changed files with 29 additions and 6 deletions

View file

@ -166,6 +166,7 @@ class CompletenessAnalyzer {
private static final int XTERM = 0b100000000; // Can terminate (last before EOF) private static final int XTERM = 0b100000000; // Can terminate (last before EOF)
private static final int XSTART = 0b1000000000; // Boundary, must be XTERM before private static final int XSTART = 0b1000000000; // Boundary, must be XTERM before
private static final int XERRO = 0b10000000000; // Is an error private static final int XERRO = 0b10000000000; // Is an error
private static final int XBRACESNEEDED = 0b100000000000; // Expect {ANY} LBRACE
/** /**
* An extension of the compiler's TokenKind which adds our combined/processed * An extension of the compiler's TokenKind which adds our combined/processed
@ -190,7 +191,7 @@ class CompletenessAnalyzer {
ERROR(TokenKind.ERROR, XERRO), // ERROR(TokenKind.ERROR, XERRO), //
IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM), // IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM), //
UNDERSCORE(TokenKind.UNDERSCORE, XERRO), // _ UNDERSCORE(TokenKind.UNDERSCORE, XERRO), // _
CLASS(TokenKind.CLASS, XEXPR|XDECL1), // class decl (MAPPED: DOTCLASS) CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED), // class decl (MAPPED: DOTCLASS)
MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1), // @ MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1), // @
IMPORT(TokenKind.IMPORT, XDECL1|XSTART), // import -- consider declaration IMPORT(TokenKind.IMPORT, XDECL1|XSTART), // import -- consider declaration
SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART), // ; SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART), // ;
@ -202,10 +203,10 @@ class CompletenessAnalyzer {
CUSTOM(TokenKind.CUSTOM, XERRO), // No uses CUSTOM(TokenKind.CUSTOM, XERRO), // No uses
// Declarations // Declarations
ENUM(TokenKind.ENUM, XDECL1), // enum ENUM(TokenKind.ENUM, XDECL1|XBRACESNEEDED), // enum
IMPLEMENTS(TokenKind.IMPLEMENTS, XDECL), // implements IMPLEMENTS(TokenKind.IMPLEMENTS, XDECL), // implements
INTERFACE(TokenKind.INTERFACE, XDECL1), // interface INTERFACE(TokenKind.INTERFACE, XDECL1|XBRACESNEEDED), // interface
THROWS(TokenKind.THROWS, XDECL), // throws THROWS(TokenKind.THROWS, XDECL|XBRACESNEEDED), // throws
// Primarive type names // Primarive type names
BOOLEAN(TokenKind.BOOLEAN, XEXPR1|XDECL1), // boolean BOOLEAN(TokenKind.BOOLEAN, XEXPR1|XDECL1), // boolean
@ -381,6 +382,10 @@ class CompletenessAnalyzer {
return (belongs & XSTART) != 0; return (belongs & XSTART) != 0;
} }
boolean isBracesNeeded() {
return (belongs & XBRACESNEEDED) != 0;
}
/** /**
* After construction, check that all compiler TokenKind values have * After construction, check that all compiler TokenKind values have
* corresponding TK values. * corresponding TK values.
@ -641,7 +646,9 @@ class CompletenessAnalyzer {
public Completeness parseDeclaration() { public Completeness parseDeclaration() {
boolean isImport = token.kind == IMPORT; boolean isImport = token.kind == IMPORT;
boolean isBracesNeeded = false;
while (token.kind.isDeclaration()) { while (token.kind.isDeclaration()) {
isBracesNeeded |= token.kind.isBracesNeeded();
nextToken(); nextToken();
} }
switch (token.kind) { switch (token.kind) {
@ -666,6 +673,9 @@ class CompletenessAnalyzer {
case SEMI: case SEMI:
return Completeness.COMPLETE; return Completeness.COMPLETE;
case IDENTIFIER: case IDENTIFIER:
return isBracesNeeded
? Completeness.DEFINITELY_INCOMPLETE
: Completeness.COMPLETE_WITH_SEMI;
case BRACKETS: case BRACKETS:
return Completeness.COMPLETE_WITH_SEMI; return Completeness.COMPLETE_WITH_SEMI;
case DOTSTAR: case DOTSTAR:

View file

@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 8149524 8131024 8165211 8080071 8130454 * @bug 8149524 8131024 8165211 8080071 8130454 8167343
* @summary Test SourceCodeAnalysis * @summary Test SourceCodeAnalysis
* @build KullaTesting TestingInputStream * @build KullaTesting TestingInputStream
* @run testng CompletenessTest * @run testng CompletenessTest
@ -117,6 +117,7 @@ public class CompletenessTest extends KullaTesting {
"bar: g()", "bar: g()",
"baz: while (true) if (t()) printf('-'); else break baz", "baz: while (true) if (t()) printf('-'); else break baz",
"java.util.function.IntFunction<int[]> ggg = int[]::new", "java.util.function.IntFunction<int[]> ggg = int[]::new",
"List<? extends Object> l",
}; };
static final String[] considered_incomplete = new String[] { static final String[] considered_incomplete = new String[] {
@ -162,7 +163,19 @@ public class CompletenessTest extends KullaTesting {
"enum TK { EOF(TokenKind.EOF, 0),", "enum TK { EOF(TokenKind.EOF, 0),",
"enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)", "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)",
"enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ", "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ",
"enum Tt { FOO, BAR, BAZ,;" "enum Tt { FOO, BAR, BAZ,;",
"class C",
"class C extends D",
"class C implements D",
"class C implements D, E",
"interface I extends D",
"interface I extends D, E",
"enum E",
"enum E implements I1",
"enum E implements I1, I2",
"@interface Anno",
"void f()",
"void f() throws E",
}; };
static final String[] unknown = new String[] { static final String[] unknown = new String[] {