diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 72273f25b6e9..68fd2ff197e3 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,8 +68,7 @@ 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), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS)); + final TypeInfo typeInfo = parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), false, isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS)); if (typeInfo != null && isSet(flags, DISJUNCTIONS) && builder.getTokenType() == JavaTokenType.OR) { typeInfo.marker = typeInfo.marker.precede(); @@ -79,7 +78,7 @@ public class ReferenceParser { if (builder.getTokenType() != JavaTokenType.IDENTIFIER) { error(builder, JavaErrorMessages.message("expected.identifier")); } - parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS)); + parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), false, isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS)); } typeInfo.marker.done(JavaElementType.TYPE); @@ -90,7 +89,7 @@ public class ReferenceParser { @Nullable private TypeInfo parseTypeInfo(final PsiBuilder builder, - final boolean eatLastDot, final boolean wildcard, final boolean diamonds, final boolean ellipsis) { + final boolean eatLastDot, final boolean wildcard, final boolean badWildcard, final boolean diamonds, final boolean ellipsis) { if (builder.getTokenType() == null) return null; final TypeInfo typeInfo = new TypeInfo(); @@ -108,9 +107,9 @@ public class ReferenceParser { else if (tokenType == JavaTokenType.IDENTIFIER) { parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, false, false, false, diamonds, typeInfo); } - else if (wildcard && tokenType == JavaTokenType.QUEST) { + else if ((wildcard || badWildcard) && tokenType == JavaTokenType.QUEST) { type.drop(); - typeInfo.marker = parseWildcardType(builder); + typeInfo.marker = parseWildcardType(builder, wildcard); return typeInfo.marker != null ? typeInfo : null; } else if (diamonds && tokenType == JavaTokenType.GT) { @@ -157,7 +156,7 @@ public class ReferenceParser { } @NotNull - private PsiBuilder.Marker parseWildcardType(final PsiBuilder builder) { + private PsiBuilder.Marker parseWildcardType(final PsiBuilder builder, final boolean wildcard) { final PsiBuilder.Marker type = builder.mark(); builder.advanceLexer(); @@ -167,13 +166,18 @@ public class ReferenceParser { } } - type.done(JavaElementType.TYPE); + if (wildcard) { + type.done(JavaElementType.TYPE); + } + else { + type.error(JavaErrorMessages.message("wildcard.not.expected")); + } return type; } @Nullable public PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot, final boolean parameterList, - final boolean annotations, final boolean isNew, final boolean diamonds) { + final boolean annotations, final boolean isNew, final boolean diamonds) { return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, false, false, isNew, diamonds, new TypeInfo()); } @@ -185,8 +189,8 @@ public class ReferenceParser { @Nullable private PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot, final boolean parameterList, - final boolean annotations, final boolean isImport, final boolean isStaticImport, - final boolean isNew, final boolean diamonds, final TypeInfo typeInfo) { + final boolean annotations, final boolean isImport, final boolean isStaticImport, + final boolean isNew, final boolean diamonds, final TypeInfo typeInfo) { PsiBuilder.Marker refElement = builder.mark(); if (annotations) { @@ -276,9 +280,15 @@ public class ReferenceParser { boolean isOk = true; while (true) { - if (parseTypeInfo(builder, true, wildcard, diamonds, false) == null) { + if (parseTypeInfo(builder, true, wildcard, true, diamonds, false) == null) { error(builder, JavaErrorMessages.message("expected.identifier")); } + else { + final IElementType tokenType = builder.getTokenType(); + if (WILDCARD_KEYWORD_SET.contains(tokenType)) { + parseReferenceList(builder, tokenType, null, JavaTokenType.AND); + } + } if (expect(builder, JavaTokenType.GT)) { break; @@ -338,20 +348,27 @@ public class ReferenceParser { final PsiBuilder.Marker param = builder.mark(); myDeclarationParser.parseAnnotations(builder); - if (!expect(builder, JavaTokenType.IDENTIFIER)) { + + final boolean wild = expect(builder, JavaTokenType.QUEST); + if (!wild && !expect(builder, JavaTokenType.IDENTIFIER)) { param.rollbackTo(); return null; } parseReferenceList(builder, JavaTokenType.EXTENDS_KEYWORD, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND); - param.done(JavaElementType.TYPE_PARAMETER); + if (!wild) { + param.done(JavaElementType.TYPE_PARAMETER); + } + else { + param.error(JavaErrorMessages.message("wildcard.not.expected")); + } return param; } @NotNull public PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType start, - final IElementType type, final IElementType delimiter) { + @Nullable final IElementType type, final IElementType delimiter) { final PsiBuilder.Marker element = builder.mark(); if (expect(builder, start)) { @@ -366,7 +383,12 @@ public class ReferenceParser { } } - element.done(type); + if (type != null) { + element.done(type); + } + else { + element.error(JavaErrorMessages.message("bound.not.expected")); + } return element; } } diff --git a/java/java-tests/testData/psi/parser-full/expressionParsing/IllegalWildcard.txt b/java/java-tests/testData/psi/parser-full/expressionParsing/IllegalWildcard.txt index fe20e2113c6c..24e6d1e871ce 100644 --- a/java/java-tests/testData/psi/parser-full/expressionParsing/IllegalWildcard.txt +++ b/java/java-tests/testData/psi/parser-full/expressionParsing/IllegalWildcard.txt @@ -23,8 +23,8 @@ PsiJavaFile:IllegalWildcard.java PsiJavaToken:LBRACE('{') PsiWhiteSpace('\n ') PsiExpressionStatement - PsiConditionalExpression:this.foo() + PsiReferenceExpression:this.foo PsiThisExpression:this PsiReferenceParameterList @@ -32,24 +32,9 @@ PsiJavaFile:IllegalWildcard.java PsiJavaToken:DOT('.') PsiReferenceParameterList PsiJavaToken:LT('<') - PsiErrorElement:Identifier expected - - PsiErrorElement:'>' or ',' expected. - - PsiErrorElement:Identifier expected - - PsiJavaToken:QUEST('?') - PsiErrorElement:Expression expected - - PsiErrorElement:';' expected - - PsiErrorElement:Unexpected token - PsiJavaToken:GT('>') - PsiExpressionStatement - PsiMethodCallExpression:foo() - PsiReferenceExpression:foo - PsiReferenceParameterList - + PsiErrorElement:Unexpected wildcard + PsiJavaToken:QUEST('?') + PsiJavaToken:GT('>') PsiIdentifier:foo('foo') PsiExpressionList PsiJavaToken:LPARENTH('(') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/IllegalBound.txt b/java/java-tests/testData/psi/parser-partial/expressions/IllegalBound.txt new file mode 100644 index 000000000000..6799e3703a43 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/IllegalBound.txt @@ -0,0 +1,28 @@ +PsiJavaFile:IllegalBound.java + PsiMethodCallExpression:C.foo() + PsiReferenceExpression:C.foo + PsiReferenceExpression:C + PsiReferenceParameterList + + PsiIdentifier:C('C') + PsiJavaToken:DOT('.') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected bound + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:S + PsiIdentifier:S('S') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiIdentifier:foo('foo') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt b/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt index 563280a61046..6dc22072acf7 100644 --- a/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt +++ b/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt @@ -1,6 +1,6 @@ PsiJavaFile:IllegalWildcard.java - PsiConditionalExpression:this.foo() + PsiReferenceExpression:this.foo PsiThisExpression:this PsiReferenceParameterList @@ -8,17 +8,10 @@ PsiJavaFile:IllegalWildcard.java PsiJavaToken:DOT('.') PsiReferenceParameterList PsiJavaToken:LT('<') - PsiErrorElement:Identifier expected - - PsiErrorElement:'>' or ',' expected. - - PsiErrorElement:Identifier expected - - PsiJavaToken:QUEST('?') - PsiErrorElement:Expression expected - - PsiErrorElement:Unparsed tokens - PsiJavaToken:GT('>') - PsiIdentifier:foo('foo') - PsiJavaToken:LPARENTH('(') - PsiJavaToken:RPARENTH(')') + PsiErrorElement:Unexpected wildcard + PsiJavaToken:QUEST('?') + PsiJavaToken:GT('>') + PsiIdentifier:foo('foo') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams8.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams8.txt new file mode 100644 index 000000000000..9389898f2c15 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams8.txt @@ -0,0 +1,8 @@ +PsiJavaFile:TypeParams8.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiErrorElement:Unexpected wildcard + PsiJavaToken:QUEST('?') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java index c6f9f547d99a..fdc02ee9bf87 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -109,6 +109,7 @@ public class ExpressionParserTest extends JavaParsingTestCase { public void testShiftRight() { doParserTest("x >>= 2"); } public void testIllegalWildcard() { doParserTest("this.foo()"); } + public void testIllegalBound() { doParserTest("C.foo()"); } public void testQualifiedSuperMethodCall0() { doParserTest("new D().super(0)"); } public void testQualifiedSuperMethodCall1() { doParserTest("d.super(0)"); } @@ -120,7 +121,6 @@ public class ExpressionParserTest extends JavaParsingTestCase { private void doParserTest(@NonNls final String text) { doParserTest(text, new MyTestParser()); } - private static class MyTestParser implements TestParser { @Override public void parse(final PsiBuilder builder) { diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java index 996cefa17fa4..2d20e0801213 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,7 @@ public class ReferenceParserTest extends JavaParsingTestCase { public void testTypeParams5() { doTypeParamsParserTest(">"); } public void testTypeParams6() { doTypeParamsParserTest(""); } public void testTypeParams7() { doTypeParamsParserTest(""); } + public void testTypeParams8() { doTypeParamsParserTest(""); } private void doRefParserTest(final String text, final boolean incomplete) { doParserTest(text, new MyTestParser(incomplete)); @@ -84,7 +85,6 @@ public class ReferenceParserTest extends JavaParsingTestCase { private void doTypeParamsParserTest(final String text) { doParserTest(text, new MyTestParser3()); } - private static class MyTestParser3 implements TestParser { @Override public void parse(final PsiBuilder builder) { diff --git a/resources-en/src/messages/JavaErrorMessages.properties b/resources-en/src/messages/JavaErrorMessages.properties index 532c09c48473..317aeb1326bb 100644 --- a/resources-en/src/messages/JavaErrorMessages.properties +++ b/resources-en/src/messages/JavaErrorMessages.properties @@ -347,3 +347,5 @@ illegal.initializer=Illegal initializer for ''{0}'' class.cannot.inherit.from.its.type.parameter=Class cannot inherit from its type parameter cannot.resolve.package=Cannot resolve package {0} override.not.allowed.in.interfaces=@Override is not allowed when implementing interface method +wildcard.not.expected=Unexpected wildcard +bound.not.expected=Unexpected bound