mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 09:19:13 +07:00
New Java parser - diamonds support
This commit is contained in:
@@ -205,7 +205,7 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
// adding a reference, not simple tokens allows "Browse ..." to work well
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false);
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false, false);
|
||||
if (ref == null) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
@@ -518,7 +518,7 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
// adding a reference, not simple tokens allows "Browse .." to work well
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false);
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false, false);
|
||||
if (ref == null && builder.getTokenType() != null) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
@@ -538,7 +538,7 @@ public class DeclarationParser {
|
||||
|
||||
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
|
||||
final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) :
|
||||
ReferenceParser.parseType(builder, true, true);
|
||||
ReferenceParser.parseType(builder, true, true, false);
|
||||
|
||||
if (type == null && modListInfo.second) {
|
||||
param.rollbackTo();
|
||||
@@ -676,7 +676,7 @@ public class DeclarationParser {
|
||||
final PsiBuilder.Marker anno = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
final PsiBuilder.Marker classRef = ReferenceParser.parseJavaCodeReference(builder, true, false, false);
|
||||
final PsiBuilder.Marker classRef = ReferenceParser.parseJavaCodeReference(builder, true, false, false, false);
|
||||
if (classRef == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.class.reference"));
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker copy = startMarker.precede();
|
||||
startMarker.rollbackTo();
|
||||
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, false, true, false);
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, false, true, false, false);
|
||||
if (ref == null || builder.getTokenType() != JavaTokenType.DOT) {
|
||||
copy.rollbackTo();
|
||||
return parsePrimary(builder, BreakPoint.P2);
|
||||
@@ -383,7 +383,7 @@ public class ExpressionParser {
|
||||
else {
|
||||
dotPos.drop();
|
||||
final PsiBuilder.Marker refExpr = expr.precede();
|
||||
ReferenceParser.parseReferenceParameterList(builder, false);
|
||||
ReferenceParser.parseReferenceParameterList(builder, false, false);
|
||||
|
||||
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier"))) {
|
||||
refExpr.done(JavaElementType.REFERENCE_EXPRESSION);
|
||||
@@ -637,14 +637,15 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker newExpr = (start != null ? start.precede() : builder.mark());
|
||||
builder.advanceLexer();
|
||||
|
||||
ReferenceParser.parseReferenceParameterList(builder, false);
|
||||
final boolean parseDiamonds = areDiamondsSupported(builder);
|
||||
ReferenceParser.parseReferenceParameterList(builder, false, parseDiamonds);
|
||||
|
||||
final PsiBuilder.Marker refOrType;
|
||||
final boolean parseAnnotations = areTypeAnnotationsSupported(builder) && builder.getTokenType() == JavaTokenType.AT;
|
||||
|
||||
final IElementType tokenType = builder.getTokenType();
|
||||
if (tokenType == JavaTokenType.IDENTIFIER || parseAnnotations) {
|
||||
refOrType = ReferenceParser.parseJavaCodeReference(builder, true, true, parseAnnotations);
|
||||
refOrType = ReferenceParser.parseJavaCodeReference(builder, true, true, parseAnnotations, parseDiamonds);
|
||||
if (refOrType == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
newExpr.done(JavaElementType.NEW_EXPRESSION);
|
||||
@@ -715,7 +716,7 @@ public class ExpressionParser {
|
||||
private static PsiBuilder.Marker parseClassObjectAccess(final PsiBuilder builder) {
|
||||
final PsiBuilder.Marker expr = builder.mark();
|
||||
|
||||
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, false, false);
|
||||
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, false, false, false);
|
||||
if (type == null) {
|
||||
expr.drop();
|
||||
return null;
|
||||
|
||||
@@ -116,7 +116,7 @@ public class FileParser {
|
||||
}
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, false, false);
|
||||
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, false, false, false);
|
||||
if (ref == null) {
|
||||
statement.rollbackTo();
|
||||
return null;
|
||||
|
||||
@@ -116,8 +116,11 @@ public class JavaParserUtil {
|
||||
}
|
||||
|
||||
public static boolean areTypeAnnotationsSupported(final PsiBuilder builder) {
|
||||
final LanguageLevel level = getLanguageLevel(builder);
|
||||
return level.isAtLeast(LanguageLevel.JDK_1_7);
|
||||
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
|
||||
}
|
||||
|
||||
public static boolean areDiamondsSupported(final PsiBuilder builder) {
|
||||
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_7);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import static com.intellij.lang.PsiBuilderUtil.expect;
|
||||
import static com.intellij.lang.PsiBuilderUtil.nextTokenType;
|
||||
import static com.intellij.lang.java.parser.JavaParserUtil.*;
|
||||
import static com.intellij.lang.java.parser.JavaParserUtil.emptyElement;
|
||||
|
||||
|
||||
public class ReferenceParser {
|
||||
@@ -45,18 +46,18 @@ public class ReferenceParser {
|
||||
|
||||
@Nullable
|
||||
public static TypeInfo parseType(final PsiBuilder builder) {
|
||||
return parseTypeWithInfo(builder, true, true);
|
||||
return parseTypeWithInfo(builder, true, true, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
|
||||
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard);
|
||||
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
|
||||
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard, diamonds);
|
||||
return typeInfo != null ? typeInfo.marker : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseTypeWithEllipsis(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
|
||||
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard);
|
||||
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard, false);
|
||||
if (typeInfo == null) return null;
|
||||
|
||||
PsiBuilder.Marker type = typeInfo.marker;
|
||||
@@ -70,7 +71,7 @@ public class ReferenceParser {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
|
||||
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
|
||||
if (builder.getTokenType() == null) return null;
|
||||
|
||||
final TypeInfo typeInfo = new TypeInfo();
|
||||
@@ -86,13 +87,19 @@ public class ReferenceParser {
|
||||
typeInfo.isPrimitive = true;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.IDENTIFIER) {
|
||||
parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, false, false, typeInfo);
|
||||
parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, false, false, diamonds, typeInfo);
|
||||
}
|
||||
else if (wildcard && tokenType == JavaTokenType.QUEST) {
|
||||
type.drop();
|
||||
typeInfo.marker = parseWildcardType(builder);
|
||||
return typeInfo.marker != null ? typeInfo : null;
|
||||
}
|
||||
else if (diamonds && tokenType == JavaTokenType.GT) {
|
||||
emptyElement(builder, JavaElementType.DIAMOND_TYPE);
|
||||
type.done(JavaElementType.TYPE);
|
||||
typeInfo.marker = type;
|
||||
return typeInfo;
|
||||
}
|
||||
else {
|
||||
type.drop();
|
||||
return null;
|
||||
@@ -129,7 +136,7 @@ public class ReferenceParser {
|
||||
builder.advanceLexer();
|
||||
|
||||
if (expect(builder, WILDCARD_KEYWORD_SET)) {
|
||||
final PsiBuilder.Marker boundType = parseType(builder, true, false);
|
||||
final PsiBuilder.Marker boundType = parseType(builder, true, false, false);
|
||||
if (boundType == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.type"));
|
||||
}
|
||||
@@ -141,13 +148,13 @@ public class ReferenceParser {
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot,
|
||||
final boolean parameterList, final boolean annotations) {
|
||||
return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, false, false, new TypeInfo());
|
||||
final boolean parameterList, final boolean annotations, final boolean diamonds) {
|
||||
return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, false, false, diamonds, new TypeInfo());
|
||||
}
|
||||
|
||||
public static boolean parseImportCodeReference(final PsiBuilder builder, final boolean isStatic) {
|
||||
final TypeInfo typeInfo = new TypeInfo();
|
||||
parseJavaCodeReference(builder, true, false, false, true, isStatic, typeInfo);
|
||||
parseJavaCodeReference(builder, true, false, false, true, isStatic, false, typeInfo);
|
||||
return !typeInfo.hasErrors;
|
||||
}
|
||||
|
||||
@@ -155,7 +162,7 @@ public class ReferenceParser {
|
||||
private static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot,
|
||||
final boolean parameterList, final boolean annotations,
|
||||
final boolean isImport, final boolean isStaticImport,
|
||||
final TypeInfo typeInfo) {
|
||||
final boolean diamonds, final TypeInfo typeInfo) {
|
||||
PsiBuilder.Marker refElement = builder.mark();
|
||||
|
||||
if (annotations) {
|
||||
@@ -173,7 +180,7 @@ public class ReferenceParser {
|
||||
|
||||
if (parameterList) {
|
||||
typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT);
|
||||
parseReferenceParameterList(builder, true);
|
||||
parseReferenceParameterList(builder, true, diamonds);
|
||||
}
|
||||
else {
|
||||
if (!isStaticImport || builder.getTokenType() == JavaTokenType.DOT) {
|
||||
@@ -223,7 +230,7 @@ public class ReferenceParser {
|
||||
|
||||
if (parameterList) {
|
||||
typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT);
|
||||
parseReferenceParameterList(builder, true);
|
||||
parseReferenceParameterList(builder, true, diamonds);
|
||||
}
|
||||
else if (!isStaticImport || builder.getTokenType() == JavaTokenType.DOT) {
|
||||
emptyElement(builder, JavaElementType.REFERENCE_PARAMETER_LIST);
|
||||
@@ -235,7 +242,7 @@ public class ReferenceParser {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiBuilder.Marker parseReferenceParameterList(final PsiBuilder builder, final boolean wildcard) {
|
||||
public static PsiBuilder.Marker parseReferenceParameterList(final PsiBuilder builder, final boolean wildcard, final boolean diamonds) {
|
||||
final PsiBuilder.Marker list = builder.mark();
|
||||
if (!expect(builder, JavaTokenType.LT)) {
|
||||
list.done(JavaElementType.REFERENCE_PARAMETER_LIST);
|
||||
@@ -243,7 +250,7 @@ public class ReferenceParser {
|
||||
}
|
||||
|
||||
while (true) {
|
||||
final PsiBuilder.Marker type = parseType(builder, true, wildcard);
|
||||
final PsiBuilder.Marker type = parseType(builder, true, wildcard, diamonds);
|
||||
if (type == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
@@ -323,7 +330,7 @@ public class ReferenceParser {
|
||||
|
||||
if (expect(builder, start)) {
|
||||
while (true) {
|
||||
final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true);
|
||||
final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true, false);
|
||||
if (classReference == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ public class StatementParser {
|
||||
final PsiBuilder.Marker declStatement = builder.mark();
|
||||
final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK);
|
||||
if (decl == null) {
|
||||
ReferenceParser.parseType(builder, false, false);
|
||||
ReferenceParser.parseType(builder, false, false, false);
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
done(declStatement, JavaElementType.DECLARATION_STATEMENT);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
{
|
||||
new A<>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
PsiJavaFile:New15.java
|
||||
PsiImportList
|
||||
<empty list>
|
||||
PsiClass:Foo
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiKeyword:class('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:Foo('Foo')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiClassInitializer
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiExpressionStatement
|
||||
PsiNewExpression:new A<>()
|
||||
PsiKeyword:new('new')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaCodeReferenceElement:A<>
|
||||
PsiIdentifier:A('A')
|
||||
PsiReferenceParameterList
|
||||
PsiJavaToken:LT('<')
|
||||
PsiTypeElement:
|
||||
PsiElement(DIAMOND_TYPE)
|
||||
<empty list>
|
||||
PsiJavaToken:GT('>')
|
||||
PsiExpressionList
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,10 @@
|
||||
PsiJavaFile:Type7.java
|
||||
PsiTypeElement:Diamond<>
|
||||
PsiJavaCodeReferenceElement:Diamond<>
|
||||
PsiIdentifier:Diamond('Diamond')
|
||||
PsiReferenceParameterList
|
||||
PsiJavaToken:LT('<')
|
||||
PsiTypeElement:
|
||||
PsiElement(DIAMOND_TYPE)
|
||||
<empty list>
|
||||
PsiJavaToken:GT('>')
|
||||
@@ -16,6 +16,8 @@
|
||||
package com.intellij.lang.java.parser;
|
||||
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
|
||||
public class ExpressionParsingTest extends JavaParsingTestCase {
|
||||
|
||||
public ExpressionParsingTest() {
|
||||
@@ -73,6 +75,10 @@ public class ExpressionParsingTest extends JavaParsingTestCase {
|
||||
public void testNew12() { doTest(true); }
|
||||
public void testNew13() { doTest(true); }
|
||||
public void testNew14() { doTest(true); }
|
||||
public void testNew15() {
|
||||
withLevel(LanguageLevel.JDK_1_7,
|
||||
new Runnable() { public void run() { doTest(true); } });
|
||||
}
|
||||
|
||||
public void testExprList0() { doTest(true); }
|
||||
public void testExprList1() { doTest(true); }
|
||||
|
||||
+7
-3
@@ -40,6 +40,7 @@ public class ReferenceParserTest extends JavaParsingTestCase {
|
||||
withLevel(LanguageLevel.JDK_1_7,
|
||||
new Runnable() { public void run() { doTypeParserTest("@English String @NonEmpty []", false); } });
|
||||
}
|
||||
public void testType7() { doTypeParserTest("Diamond<>", true); }
|
||||
|
||||
public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
|
||||
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
|
||||
@@ -53,15 +54,18 @@ public class ReferenceParserTest extends JavaParsingTestCase {
|
||||
private void doRefParserTest(final String text, final boolean incomplete) {
|
||||
doParserTest(text, new TestParser() {
|
||||
public void parse(final PsiBuilder builder) {
|
||||
ReferenceParser.parseJavaCodeReference(builder, incomplete, false, false);
|
||||
ReferenceParser.parseJavaCodeReference(builder, incomplete, false, false, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doTypeParserTest(final String text, final boolean incomplete) {
|
||||
private void doTypeParserTest(final String text, final boolean diamonds) {
|
||||
doParserTest(text, new TestParser() {
|
||||
public void parse(final PsiBuilder builder) {
|
||||
ReferenceParser.parseTypeWithEllipsis(builder, incomplete, false);
|
||||
if (diamonds)
|
||||
ReferenceParser.parseType(builder, false, false, true);
|
||||
else
|
||||
ReferenceParser.parseTypeWithEllipsis(builder, false, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user