DeclarationParser: allow local record declarations

GitOrigin-RevId: f829792d6849fd3af59f587664e0fc8b2e3d7839
This commit is contained in:
Roman.Ivanov
2019-12-24 08:41:04 +00:00
committed by intellij-monorepo-bot
parent 158abe45b8
commit 18e6f7ba1f
7 changed files with 114 additions and 35 deletions
@@ -63,7 +63,16 @@ public class DeclarationParser {
@Nullable
private PsiBuilder.Marker parseClassFromKeyword(PsiBuilder builder, PsiBuilder.Marker declaration, boolean isAnnotation, Context context) {
final IElementType keywordTokenType = builder.getTokenType();
IElementType keywordTokenType = builder.getTokenType();
if (isRecordToken(builder, keywordTokenType)) {
if (builder.lookAhead(1) == JavaTokenType.IDENTIFIER) {
builder.remapCurrentToken(JavaTokenType.RECORD_KEYWORD);
keywordTokenType = JavaTokenType.RECORD_KEYWORD;
} else {
declaration.drop();
return null;
}
}
assert ElementType.CLASS_KEYWORD_BIT_SET.contains(keywordTokenType) : keywordTokenType;
builder.advanceLexer();
final boolean isEnum = (keywordTokenType == JavaTokenType.ENUM_KEYWORD);
@@ -234,21 +243,20 @@ public class DeclarationParser {
if (tokenType == JavaTokenType.LBRACE) {
if (context == Context.FILE || context == Context.CODE_BLOCK) return null;
}
else if (isRecordToken(builder, tokenType)) {
if (context == Context.CODE_BLOCK) return null;
}
else if (TYPE_START.contains(tokenType) && tokenType != JavaTokenType.AT) {
if (context == Context.FILE) return null;
}
else if (tokenType instanceof ILazyParseableElementType) {
builder.advanceLexer();
return null;
}
else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) &&
!ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) &&
tokenType != JavaTokenType.AT &&
(context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) {
return null;
else if (!isRecordToken(builder, tokenType)) {
if (TYPE_START.contains(tokenType) && tokenType != JavaTokenType.AT) {
if (context == Context.FILE) return null;
}
else if (tokenType instanceof ILazyParseableElementType) {
builder.advanceLexer();
return null;
}
else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) &&
!ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) &&
tokenType != JavaTokenType.AT &&
(context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) {
return null;
}
}
final PsiBuilder.Marker declaration = builder.mark();
@@ -267,12 +275,7 @@ public class DeclarationParser {
return null;
}
}
boolean isRecord = false;
if (ElementType.CLASS_KEYWORD_BIT_SET.contains(builder.getTokenType()) ||
(isRecord = isRecordToken(builder, builder.getTokenType()))) {
if (isRecord) {
builder.remapCurrentToken(JavaTokenType.RECORD_KEYWORD);
}
if (ElementType.CLASS_KEYWORD_BIT_SET.contains(builder.getTokenType()) || isRecordToken(builder, builder.getTokenType())) {
final PsiBuilder.Marker result = parseClassFromKeyword(builder, declaration, false, context);
return result != null ? result : modList;
}
@@ -395,7 +398,7 @@ public class DeclarationParser {
}
private static boolean isRecordToken(PsiBuilder builder, IElementType tokenType) {
return tokenType == JavaTokenType.IDENTIFIER && PsiKeyword.RECORD.equals(builder.getTokenText());
return tokenType == JavaTokenType.IDENTIFIER && PsiKeyword.RECORD.equals(builder.getTokenText()) && builder.lookAhead(1) == JavaTokenType.IDENTIFIER;
}
@NotNull
@@ -23,7 +23,7 @@ import java.io.IOException;
* @author max
*/
public class JavaFileElementType extends ILightStubFileElementType<PsiJavaFileStub> {
public static final int STUB_VERSION = 44;
public static final int STUB_VERSION = 45;
public JavaFileElementType() {
super("java.FILE", JavaLanguage.INSTANCE);
@@ -0,0 +1,5 @@
class A {
void test() {
record A(String s) { }
}
}
@@ -0,0 +1,70 @@
PsiJavaFile:LocalRecord.java
PsiImportList
<empty list>
PsiClass:A
PsiModifierList:
<empty list>
PsiKeyword:class('class')
PsiWhiteSpace(' ')
PsiIdentifier:A('A')
PsiTypeParameterList
<empty list>
PsiReferenceList
<empty list>
PsiReferenceList
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiMethod:test
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:test('test')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiDeclarationStatement
PsiClass:A
PsiModifierList:
<empty list>
PsiKeyword:record('record')
PsiWhiteSpace(' ')
PsiIdentifier:A('A')
PsiTypeParameterList
<empty list>
PsiRecordHeader
PsiJavaToken:LPARENTH('(')
PsiRecordComponent:s
PsiModifierList:
<empty list>
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:s('s')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiReferenceList
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace('\n ')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace('\n')
PsiJavaToken:RBRACE('}')
@@ -1,6 +1,6 @@
class A {
void test() {
record
record.
foo();
}
}
@@ -35,18 +35,18 @@ PsiJavaFile:RecordInCodeBlock.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n ')
PsiExpressionStatement
PsiReferenceExpression:record
PsiReferenceParameterList
<empty list>
PsiIdentifier:record('record')
PsiErrorElement:';' expected
<empty list>
PsiWhiteSpace('\n ')
PsiExpressionStatement
PsiMethodCallExpression:foo()
PsiReferenceExpression:foo
PsiMethodCallExpression:record.
foo()
PsiReferenceExpression:record.
foo
PsiReferenceExpression:record
PsiReferenceParameterList
<empty list>
PsiIdentifier:record('record')
PsiJavaToken:DOT('.')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace('\n ')
PsiIdentifier:foo('foo')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
@@ -51,6 +51,7 @@ public class ClassParsingTest extends JavaParsingTestCase {
public void testRecordNoClosingTypeBracket() { doTest(true); }
public void testRecordWithModifiers() { doTest(true); }
public void testRecordInCodeBlock() { doTest(true); }
public void testLocalRecord() { doTest(true); }
public void testCompactConstructor0() { doTest(true); }
public void testCompactConstructor1() { doTest(true); }
}