[java-parser] IDEA-363168 Incomplete record declaration should mark 'record' as a keyword

GitOrigin-RevId: 003fcac350447df675685c79d9619e7604813bc7
This commit is contained in:
Tagir Valeev
2024-11-14 12:12:11 +00:00
committed by intellij-monorepo-bot
parent 7c8933354e
commit 01822cb3c9
20 changed files with 477 additions and 23 deletions
@@ -82,7 +82,10 @@ public class BasicDeclarationParser {
IElementType keywordTokenType = builder.getTokenType();
final boolean isRecord = isRecordToken(builder, keywordTokenType);
if (isRecord) {
builder.remapCurrentToken(JavaTokenType.RECORD_KEYWORD);
if (builder.lookAhead(1) != JavaTokenType.IDENTIFIER) {
builder.advanceLexer();
error(builder, JavaPsiBundle.message("expected.identifier"));
declaration.drop();
return null;
}
@@ -96,7 +99,6 @@ public class BasicDeclarationParser {
declaration.drop();
return null;
}
builder.remapCurrentToken(JavaTokenType.RECORD_KEYWORD);
keywordTokenType = JavaTokenType.RECORD_KEYWORD;
}
assert BASIC_CLASS_KEYWORD_BIT_SET.contains(keywordTokenType) : keywordTokenType;
@@ -414,11 +416,17 @@ public class BasicDeclarationParser {
return parseFieldOrLocalVariable(builder, declaration, declarationStart, context);
}
static boolean isRecordToken(PsiBuilder builder, IElementType tokenType) {
if (tokenType == JavaTokenType.IDENTIFIER && PsiKeyword.RECORD.equals(builder.getTokenText()) &&
builder.lookAhead(1) == JavaTokenType.IDENTIFIER) {
LanguageLevel level = getLanguageLevel(builder);
return JavaFeature.RECORDS.isSufficient(level);
boolean isRecordToken(PsiBuilder builder, IElementType tokenType) {
if (tokenType == JavaTokenType.IDENTIFIER && PsiKeyword.RECORD.equals(builder.getTokenText())) {
IElementType nextToken = builder.lookAhead(1);
if (nextToken == JavaTokenType.IDENTIFIER ||
// The following tokens cannot be part of a valid record declaration,
// but we assume it to be a malformed record, rather than a malformed type.
BASIC_MODIFIER_BIT_SET.contains(nextToken) || BASIC_CLASS_KEYWORD_BIT_SET.contains(nextToken) || TYPE_START.contains(nextToken) ||
nextToken == JavaTokenType.AT || nextToken == JavaTokenType.LBRACE || nextToken == JavaTokenType.RBRACE) {
LanguageLevel level = getLanguageLevel(builder);
return JavaFeature.RECORDS.isSufficient(level);
}
}
return false;
}
@@ -104,7 +104,7 @@ public class BasicFileParser {
private boolean stopImportListParsing(PsiBuilder b) {
IElementType type = b.getTokenType();
if (IMPORT_LIST_STOPPER_SET.contains(type) || BasicDeclarationParser.isRecordToken(b, type)) return true;
if (IMPORT_LIST_STOPPER_SET.contains(type) || myParser.getDeclarationParser().isRecordToken(b, type)) return true;
if (type == JavaTokenType.IDENTIFIER) {
String text = b.getTokenText();
if (PsiKeyword.OPEN.equals(text) || PsiKeyword.MODULE.equals(text)) return true;
@@ -213,6 +213,7 @@ public class BasicStatementParser {
PsiBuilder.Marker pos = builder.mark();
PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder);
IElementType incompleteDeclarationRestrictedTokenType = null;
if (expr != null) {
int count = 1;
@@ -242,7 +243,17 @@ public class BasicStatementParser {
done(statement, myJavaElementTypeContainer.EXPRESSION_STATEMENT, myWhiteSpaceAndCommentSetHolder);
return statement;
}
boolean singleToken = expr.getEndIndex() - expr.getStartIndex() == 1;
pos.rollbackTo();
if (singleToken && builder.getTokenType() == JavaTokenType.IDENTIFIER) {
String text = builder.getTokenText();
if (PsiKeyword.RECORD.equals(text) && JavaFeature.RECORDS.isSufficient(getLanguageLevel(builder))) {
incompleteDeclarationRestrictedTokenType = JavaTokenType.RECORD_KEYWORD;
}
if (PsiKeyword.VAR.equals(text) && JavaFeature.LVTI.isSufficient(getLanguageLevel(builder))) {
incompleteDeclarationRestrictedTokenType = JavaTokenType.VAR_KEYWORD;
}
}
}
else {
pos.drop();
@@ -265,9 +276,18 @@ public class BasicStatementParser {
if (expr != null) {
PsiBuilder.Marker statement = builder.mark();
myParser.getExpressionParser().parse(builder);
semicolon(builder);
done(statement, myJavaElementTypeContainer.EXPRESSION_STATEMENT, myWhiteSpaceAndCommentSetHolder);
IElementType statementType;
if (incompleteDeclarationRestrictedTokenType != null) {
builder.remapCurrentToken(incompleteDeclarationRestrictedTokenType);
builder.advanceLexer();
error(builder, JavaPsiBundle.message("expected.identifier"));
statementType = myJavaElementTypeContainer.DECLARATION_STATEMENT;
} else {
myParser.getExpressionParser().parse(builder);
statementType = myJavaElementTypeContainer.EXPRESSION_STATEMENT;
semicolon(builder);
}
done(statement, statementType, myWhiteSpaceAndCommentSetHolder);
return statement;
}