mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-57556 (blame C-style brackets after vararg parameter)
This commit is contained in:
@@ -357,9 +357,9 @@ public class DeclarationParser {
|
||||
|
||||
@NotNull
|
||||
private static PsiBuilder.Marker parseTypeNotNull(final PsiBuilder builder) {
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
|
||||
assert typeInfo != null : builder.getOriginalText();
|
||||
return typeInfo.marker;
|
||||
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
assert type != null : builder.getOriginalText();
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -399,14 +399,7 @@ public class DeclarationParser {
|
||||
final boolean anno, final boolean constructor) {
|
||||
parseParameterList(builder);
|
||||
|
||||
if (constructor && builder.getTokenType() == JavaTokenType.LBRACKET) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
eatBrackets(builder, false);
|
||||
marker.error(JavaErrorMessages.message("expected.semicolon"));
|
||||
}
|
||||
else {
|
||||
eatBrackets(builder, true);
|
||||
}
|
||||
eatBrackets(builder, constructor, JavaErrorMessages.message("expected.semicolon"));
|
||||
|
||||
if (areTypeAnnotationsSupported(builder)) {
|
||||
final PsiBuilder.Marker receiver = builder.mark();
|
||||
@@ -544,21 +537,23 @@ public class DeclarationParser {
|
||||
final PsiBuilder.Marker param = builder.mark();
|
||||
|
||||
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
|
||||
final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) :
|
||||
ReferenceParser.parseType(builder, true, true, false);
|
||||
|
||||
if (type == null && modListInfo.second) {
|
||||
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
|
||||
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags);
|
||||
|
||||
if (typeInfo == null && modListInfo.second) {
|
||||
param.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
if (typeInfo == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.type"));
|
||||
emptyElement(builder, JavaElementType.TYPE);
|
||||
}
|
||||
|
||||
if (expect(builder, JavaTokenType.IDENTIFIER)) {
|
||||
eatBrackets(builder, true);
|
||||
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
|
||||
done(param, JavaElementType.PARAMETER);
|
||||
return param;
|
||||
}
|
||||
@@ -593,7 +588,7 @@ public class DeclarationParser {
|
||||
while (true) {
|
||||
shouldRollback = true;
|
||||
|
||||
if (!eatBrackets(builder, true)) {
|
||||
if (!eatBrackets(builder, false, null)) {
|
||||
unclosed = true;
|
||||
}
|
||||
|
||||
@@ -655,14 +650,25 @@ public class DeclarationParser {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
private static boolean eatBrackets(final PsiBuilder builder, final boolean withError) {
|
||||
private static boolean eatBrackets(final PsiBuilder builder, final boolean isError, @Nullable final String error) {
|
||||
if (builder.getTokenType() != JavaTokenType.LBRACKET) return true;
|
||||
|
||||
final PsiBuilder.Marker marker = isError ? builder.mark() : null;
|
||||
|
||||
boolean result = true;
|
||||
while (expect(builder, JavaTokenType.LBRACKET)) {
|
||||
if (!expect(builder, JavaTokenType.RBRACKET)) {
|
||||
if (withError) error(builder, JavaErrorMessages.message("expected.rbracket"));
|
||||
return false;
|
||||
if (!isError) error(builder, JavaErrorMessages.message("expected.rbracket"));
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
if (marker != null) {
|
||||
marker.error(error);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -161,8 +161,7 @@ public class ExpressionParser {
|
||||
return parseUnary(builder);
|
||||
|
||||
case TYPE:
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
|
||||
return typeInfo != null ? typeInfo.marker : null;
|
||||
return ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
|
||||
default:
|
||||
assert false : "Unexpected type: " + type;
|
||||
@@ -255,7 +254,7 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker typeCast = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
|
||||
if (typeInfo == null || builder.getTokenType() != JavaTokenType.RPARENTH) {
|
||||
typeCast.rollbackTo();
|
||||
@@ -733,8 +732,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, false);
|
||||
if (type == null) {
|
||||
if (ReferenceParser.parseType(builder, 0) == null) {
|
||||
expr.drop();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,16 @@ import static com.intellij.lang.java.parser.JavaParserUtil.emptyElement;
|
||||
|
||||
|
||||
public class ReferenceParser {
|
||||
public static final int EAT_LAST_DOT = 0x01;
|
||||
public static final int ELLIPSIS = 0x02;
|
||||
public static final int WILDCARD = 0x04;
|
||||
public static final int DIAMONDS = 0x08;
|
||||
|
||||
public static class TypeInfo {
|
||||
public boolean isPrimitive = false;
|
||||
public boolean isParameterized = false;
|
||||
public boolean isArray = false;
|
||||
public boolean isVarArg = false;
|
||||
public boolean hasErrors = false;
|
||||
public PsiBuilder.Marker marker = null;
|
||||
}
|
||||
@@ -45,33 +51,19 @@ public class ReferenceParser {
|
||||
private ReferenceParser() { }
|
||||
|
||||
@Nullable
|
||||
public static TypeInfo parseType(final PsiBuilder builder) {
|
||||
return parseTypeWithInfo(builder, true, true, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
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);
|
||||
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final int flags) {
|
||||
final TypeInfo typeInfo = parseTypeInfo(builder, flags);
|
||||
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, false);
|
||||
if (typeInfo == null) return null;
|
||||
|
||||
PsiBuilder.Marker type = typeInfo.marker;
|
||||
if (builder.getTokenType() == JavaTokenType.ELLIPSIS) {
|
||||
type = typeInfo.marker.precede();
|
||||
builder.advanceLexer();
|
||||
type.done(JavaElementType.TYPE);
|
||||
}
|
||||
|
||||
return type;
|
||||
public static TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags) {
|
||||
return parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
|
||||
private static TypeInfo parseTypeInfo(final PsiBuilder builder,
|
||||
final boolean eatLastDot, final boolean wildcard, final boolean diamonds, final boolean ellipsis) {
|
||||
if (builder.getTokenType() == null) return null;
|
||||
|
||||
final TypeInfo typeInfo = new TypeInfo();
|
||||
@@ -126,18 +118,28 @@ public class ReferenceParser {
|
||||
type = type.precede();
|
||||
}
|
||||
|
||||
if (ellipsis && builder.getTokenType() == JavaTokenType.ELLIPSIS) {
|
||||
type = type.precede();
|
||||
builder.advanceLexer();
|
||||
type.done(JavaElementType.TYPE);
|
||||
typeInfo.isVarArg = true;
|
||||
}
|
||||
|
||||
typeInfo.marker = type;
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
private static boolean isSet(final int mask, final int flag) {
|
||||
return (mask & flag) != 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiBuilder.Marker parseWildcardType(final PsiBuilder builder) {
|
||||
final PsiBuilder.Marker type = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
if (expect(builder, WILDCARD_KEYWORD_SET)) {
|
||||
final PsiBuilder.Marker boundType = parseType(builder, true, false, false);
|
||||
if (boundType == null) {
|
||||
if (parseTypeInfo(builder, EAT_LAST_DOT) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.type"));
|
||||
}
|
||||
}
|
||||
@@ -248,8 +250,7 @@ public class ReferenceParser {
|
||||
|
||||
boolean isOk = true;
|
||||
while (true) {
|
||||
final PsiBuilder.Marker type = parseType(builder, true, wildcard, diamonds);
|
||||
if (type == null) {
|
||||
if (parseTypeInfo(builder, true, wildcard, diamonds, false) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,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, false);
|
||||
ReferenceParser.parseType(builder, 0);
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
done(declStatement, JavaElementType.DECLARATION_STATEMENT);
|
||||
|
||||
@@ -253,8 +253,8 @@ public interface JavaElementType {
|
||||
return JavaParserUtil.parseFragment(chameleon,
|
||||
new JavaParserUtil.ParserWrapper() {
|
||||
public void parse(final PsiBuilder builder) {
|
||||
ReferenceParser.parseType(builder);
|
||||
expect(builder, JavaTokenType.ELLIPSIS);
|
||||
ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
expect(builder, JavaTokenType.ELLIPSIS); // todo[r.sh] parse ellipsis and fix PsiTypeCodeFragmentImpl.getType()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
PsiJavaFile:VarArgBrackets.java
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiMethod:foo
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiTypeElement:void
|
||||
PsiKeyword:void('void')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:foo('foo')
|
||||
PsiParameterList:(int... x[])
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:x
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:int...
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiJavaToken:ELLIPSIS('...')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:x('x')
|
||||
PsiErrorElement:')' expected
|
||||
PsiJavaToken:LBRACKET('[')
|
||||
PsiJavaToken:RBRACKET(']')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+1
@@ -90,6 +90,7 @@ public class DeclarationParserTest extends JavaParsingTestCase {
|
||||
public void testUnclosed4() { doParserTest("{ void f(int a,, }", false, false); }
|
||||
public void testUnclosed5() { doParserTest("{ void f(int a,); }", false, false); }
|
||||
public void testConstructorBrackets() { doParserTest("{ A() [] { } }", false, false); }
|
||||
public void testVarArgBrackets() { doParserTest("{ void foo(int... x[]); }", false, false); }
|
||||
|
||||
public void testGenericMethod() { doParserTest("{ public static <E> test();\n" +
|
||||
" <E> void test1();\n" +
|
||||
|
||||
+10
-13
@@ -30,18 +30,18 @@ public class ReferenceParserTest extends JavaParsingTestCase {
|
||||
public void testReference1() { doRefParserTest("a.", true); }
|
||||
public void testReference2() { doRefParserTest("a.b", false); }
|
||||
|
||||
public void testType0() { doTypeParserTest("int", false); }
|
||||
public void testType1() { doTypeParserTest("a.b", false); }
|
||||
public void testType2() { doTypeParserTest("int[]", false); }
|
||||
public void testType3() { doTypeParserTest("int[][", false); }
|
||||
public void testType4() { doTypeParserTest("Map<String,List<String>>", false); }
|
||||
public void testType5() { doTypeParserTest("Object[]...", false); }
|
||||
public void testType0() { doTypeParserTest("int"); }
|
||||
public void testType1() { doTypeParserTest("a.b"); }
|
||||
public void testType2() { doTypeParserTest("int[]"); }
|
||||
public void testType3() { doTypeParserTest("int[]["); }
|
||||
public void testType4() { doTypeParserTest("Map<String,List<String>>"); }
|
||||
public void testType5() { doTypeParserTest("Object[]..."); }
|
||||
public void testType6() {
|
||||
withLevel(LanguageLevel.JDK_1_7,
|
||||
new Runnable() { @Override
|
||||
public void run() { doTypeParserTest("@English String @NonEmpty []", false); } });
|
||||
public void run() { doTypeParserTest("@English String @NonEmpty []"); } });
|
||||
}
|
||||
public void testType7() { doTypeParserTest("Diamond<>", true); }
|
||||
public void testType7() { doTypeParserTest("Diamond<>"); }
|
||||
|
||||
public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
|
||||
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
|
||||
@@ -61,14 +61,11 @@ public class ReferenceParserTest extends JavaParsingTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
private void doTypeParserTest(final String text, final boolean diamonds) {
|
||||
private void doTypeParserTest(final String text) {
|
||||
doParserTest(text, new TestParser() {
|
||||
@Override
|
||||
public void parse(final PsiBuilder builder) {
|
||||
if (diamonds)
|
||||
ReferenceParser.parseType(builder, false, false, true);
|
||||
else
|
||||
ReferenceParser.parseTypeWithEllipsis(builder, false, false);
|
||||
ReferenceParser.parseType(builder, ReferenceParser.DIAMONDS | ReferenceParser.ELLIPSIS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user