mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-94506 (parser support for intersection types in casts)
This commit is contained in:
@@ -266,7 +266,7 @@ public class ExpressionParser {
|
||||
builder.advanceLexer();
|
||||
|
||||
final ReferenceParser.TypeInfo typeInfo =
|
||||
myParser.getReferenceParser().parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
myParser.getReferenceParser().parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD | ReferenceParser.CONJUNCTIONS);
|
||||
if (typeInfo == null || !expect(builder, JavaTokenType.RPARENTH)) {
|
||||
typeCast.rollbackTo();
|
||||
return parsePostfix(builder);
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import static com.intellij.lang.PsiBuilderUtil.expect;
|
||||
import static com.intellij.lang.java.parser.JavaParserUtil.*;
|
||||
import static com.intellij.util.BitUtil.isSet;
|
||||
import static com.intellij.util.BitUtil.notSet;
|
||||
import static com.intellij.util.BitUtil.set;
|
||||
|
||||
public class ReferenceParser {
|
||||
public static final int EAT_LAST_DOT = 0x01;
|
||||
@@ -35,6 +37,7 @@ public class ReferenceParser {
|
||||
public static final int WILDCARD = 0x04;
|
||||
public static final int DIAMONDS = 0x08;
|
||||
public static final int DISJUNCTIONS = 0x10;
|
||||
public static final int CONJUNCTIONS = 0x20;
|
||||
|
||||
public static class TypeInfo {
|
||||
public boolean isPrimitive = false;
|
||||
@@ -61,29 +64,32 @@ public class ReferenceParser {
|
||||
|
||||
@Nullable
|
||||
public TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags) {
|
||||
final TypeInfo typeInfo = parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), false, isSet(flags, DIAMONDS),
|
||||
isSet(flags, ELLIPSIS));
|
||||
final TypeInfo typeInfo = parseTypeInfo(builder, flags, false);
|
||||
|
||||
if (typeInfo != null && isSet(flags, DISJUNCTIONS) && builder.getTokenType() == JavaTokenType.OR) {
|
||||
typeInfo.marker = typeInfo.marker.precede();
|
||||
if (typeInfo != null) {
|
||||
assert notSet(flags, DISJUNCTIONS|CONJUNCTIONS) : "don't not set both flags simultaneously";
|
||||
final IElementType operator = isSet(flags, DISJUNCTIONS) ? JavaTokenType.OR : isSet(flags, CONJUNCTIONS) ? JavaTokenType.AND : null;
|
||||
|
||||
while (builder.getTokenType() == JavaTokenType.OR) {
|
||||
builder.advanceLexer();
|
||||
if (builder.getTokenType() != JavaTokenType.IDENTIFIER) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
if (operator != null && builder.getTokenType() == operator) {
|
||||
typeInfo.marker = typeInfo.marker.precede();
|
||||
|
||||
while (builder.getTokenType() == operator) {
|
||||
builder.advanceLexer();
|
||||
if (builder.getTokenType() != JavaTokenType.IDENTIFIER) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
parseTypeInfo(builder, flags, false);
|
||||
}
|
||||
parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), false, isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS));
|
||||
}
|
||||
|
||||
typeInfo.marker.done(JavaElementType.TYPE);
|
||||
typeInfo.marker.done(JavaElementType.TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TypeInfo parseTypeInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean badWildcard,
|
||||
final boolean diamonds, final boolean ellipsis) {
|
||||
private TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags, final boolean badWildcard) {
|
||||
if (builder.getTokenType() == null) return null;
|
||||
|
||||
final TypeInfo typeInfo = new TypeInfo();
|
||||
@@ -96,14 +102,14 @@ public class ReferenceParser {
|
||||
typeInfo.isPrimitive = true;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.IDENTIFIER) {
|
||||
parseJavaCodeReference(builder, eatLastDot, true, false, false, false, diamonds, typeInfo);
|
||||
parseJavaCodeReference(builder, isSet(flags, EAT_LAST_DOT), true, false, false, false, isSet(flags, DIAMONDS), typeInfo);
|
||||
}
|
||||
else if ((wildcard || badWildcard) && tokenType == JavaTokenType.QUEST) {
|
||||
else if ((isSet(flags, WILDCARD) || badWildcard) && tokenType == JavaTokenType.QUEST) {
|
||||
type.drop();
|
||||
typeInfo.marker = parseWildcardType(builder, wildcard);
|
||||
typeInfo.marker = parseWildcardType(builder, isSet(flags, WILDCARD));
|
||||
return typeInfo.marker != null ? typeInfo : null;
|
||||
}
|
||||
else if (diamonds && tokenType == JavaTokenType.GT) {
|
||||
else if (isSet(flags, DIAMONDS) && tokenType == JavaTokenType.GT) {
|
||||
emptyElement(builder, JavaElementType.DIAMOND_TYPE);
|
||||
type.done(JavaElementType.TYPE);
|
||||
typeInfo.marker = type;
|
||||
@@ -133,7 +139,7 @@ public class ReferenceParser {
|
||||
type = type.precede();
|
||||
}
|
||||
|
||||
if (ellipsis && builder.getTokenType() == JavaTokenType.ELLIPSIS) {
|
||||
if (isSet(flags, ELLIPSIS) && builder.getTokenType() == JavaTokenType.ELLIPSIS) {
|
||||
type = type.precede();
|
||||
builder.advanceLexer();
|
||||
type.done(JavaElementType.TYPE);
|
||||
@@ -263,9 +269,10 @@ public class ReferenceParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int flags = set(set(EAT_LAST_DOT, WILDCARD, wildcard), DIAMONDS, diamonds);
|
||||
boolean isOk = true;
|
||||
while (true) {
|
||||
if (parseTypeInfo(builder, true, wildcard, true, diamonds, false) == null) {
|
||||
if (parseTypeInfo(builder, flags, true) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
PsiJavaFile:LambdaExpression12.java
|
||||
PsiErrorElement:Unparsed tokens
|
||||
PsiJavaToken:LT('<')
|
||||
PsiIdentifier:T('T')
|
||||
PsiJavaToken:GT('>')
|
||||
PsiTypeCastExpression:(I1 & I2) () -> null
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiTypeElement:I1 & I2
|
||||
PsiTypeElement:I1
|
||||
PsiJavaCodeReferenceElement:I1
|
||||
PsiIdentifier:I1('I1')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:AND('&')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:I2
|
||||
PsiJavaCodeReferenceElement:I2
|
||||
PsiIdentifier:I2('I2')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:new('new')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:C('C')
|
||||
PsiJavaToken:LT('<')
|
||||
PsiIdentifier:T('T')
|
||||
PsiJavaToken:GT('>')
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiLambdaExpression:() -> null
|
||||
PsiParameterList:()
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:null
|
||||
PsiJavaToken:NULL_KEYWORD('null')
|
||||
@@ -1,10 +1,29 @@
|
||||
PsiJavaFile:LambdaExpression13.java
|
||||
PsiErrorElement:Unparsed tokens
|
||||
PsiJavaToken:LT('<')
|
||||
PsiIdentifier:T('T')
|
||||
PsiJavaToken:GT('>')
|
||||
PsiIdentifier:t('t')
|
||||
PsiTypeCastExpression:(I1 & I2) () -> {}
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiTypeElement:I1 & I2
|
||||
PsiTypeElement:I1
|
||||
PsiJavaCodeReferenceElement:I1
|
||||
PsiIdentifier:I1('I1')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:AND('&')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:I2
|
||||
PsiJavaCodeReferenceElement:I2
|
||||
PsiIdentifier:I2('I2')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:t('t')
|
||||
PsiLambdaExpression:() -> {}
|
||||
PsiParameterList:()
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+2
-3
@@ -134,15 +134,14 @@ public class ExpressionParserTest extends JavaParsingTestCase {
|
||||
public void testLambdaExpression9() { doParserTest("(I)p -> null"); }
|
||||
public void testLambdaExpression10() { doParserTest("(I)(p -> null)"); }
|
||||
public void testLambdaExpression11() { doParserTest("() -> { }"); }
|
||||
public void testLambdaExpression12() { doParserTest("<T>() -> new C<T>()"); } // these two expressions
|
||||
public void testLambdaExpression13() { doParserTest("<T>t -> t"); } // should no longer be parsed
|
||||
public void testLambdaExpression12() { doParserTest("(I1 & I2) () -> null"); }
|
||||
public void testLambdaExpression13() { doParserTest("(I1 & I2) () -> {}"); }
|
||||
public void testLambdaExpression14() { doParserTest("(String t) -> t"); }
|
||||
public void testLambdaExpression15() { doParserTest("(int a, int b) -> a + b"); }
|
||||
public void testLambdaExpression16() { doParserTest("(final int x) -> x"); }
|
||||
public void testLambdaExpression17() { doParserTest("(String s -> s"); }
|
||||
public void testLambdaExpression18() { doParserTest("(java.lang.String s, -> s"); }
|
||||
public void testLambdaExpression19() { doParserTest("(@A T t) -> (null)"); }
|
||||
|
||||
public void testAmbiguousLambdaExpression() { doParserTest("f( (x) < y , z > (w) -> v )"); }
|
||||
|
||||
private void doParserTest(@NonNls final String text) {
|
||||
|
||||
Reference in New Issue
Block a user