diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 0357b1e11cfe..63908d4e6e4c 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.lang.LighterASTNode; import com.intellij.lang.PsiBuilder; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import com.intellij.psi.JavaTokenType; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -190,7 +191,8 @@ public class DeclarationParser { final PsiBuilder.Marker declaration = builder.mark(); - final PsiBuilder.Marker modList = parseModifierList(builder); + final Pair modListInfo = parseModifierList(builder); + final PsiBuilder.Marker modList = modListInfo.first; if (expect(builder, JavaTokenType.AT)) { if (builder.getTokenType() == JavaTokenType.INTERFACE_KEYWORD) { @@ -255,15 +257,14 @@ public class DeclarationParser { } idPos.rollbackTo(); if (typeParams == null) { - emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST); + emptyElement(builder, JavaElementType.TYPE_PARAMETER_LIST); } builder.advanceLexer(); if (builder.getTokenType() != JavaTokenType.LPARENTH) { - declaration.drop(); + declaration.rollbackTo(); return null; } - parseMethodFromLeftParenth(builder, declaration, false); - return declaration; + return parseMethodFromLeftParenth(builder, declaration, false); } idPos.drop(); } @@ -297,7 +298,7 @@ public class DeclarationParser { } if (!expect(builder, JavaTokenType.IDENTIFIER)) { - if (context == Context.CODE_BLOCK /* todo: && modifierList.getFirstChildNode() == null */) { + if (context == Context.CODE_BLOCK && modListInfo.second) { declaration.rollbackTo(); return null; } @@ -316,8 +317,7 @@ public class DeclarationParser { if (typeParams == null) { emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST); } - parseMethodFromLeftParenth(builder, declaration, (context == Context.ANNOTATION_INTERFACE)); - return declaration; + return parseMethodFromLeftParenth(builder, declaration, (context == Context.ANNOTATION_INTERFACE)); } } @@ -335,14 +335,16 @@ public class DeclarationParser { } @NotNull - private static PsiBuilder.Marker parseModifierList(final PsiBuilder builder) { + private static Pair parseModifierList(final PsiBuilder builder) { final PsiBuilder.Marker modList = builder.mark(); + boolean isEmpty = true; while (true) { final IElementType tokenType = builder.getTokenType(); if (tokenType == null) break; if (ElementType.MODIFIER_BIT_SET.contains(tokenType)) { builder.advanceLexer(); + isEmpty = false; } else if (tokenType == JavaTokenType.AT) { final PsiBuilder.Marker pos = builder.mark(); @@ -353,6 +355,7 @@ public class DeclarationParser { break; } parseAnnotation(builder); + isEmpty = false; } else { break; @@ -360,12 +363,149 @@ public class DeclarationParser { } modList.done(JavaElementType.MODIFIER_LIST); - return modList; + return Pair.create(modList, isEmpty); } - private static void parseMethodFromLeftParenth(final PsiBuilder builder, final PsiBuilder.Marker declaration, final boolean anno) { - // todo: implement - throw new UnsupportedOperationException(builder.toString() + declaration + anno); + private static PsiBuilder.Marker parseMethodFromLeftParenth(final PsiBuilder builder, final PsiBuilder.Marker declaration, + final boolean anno) { + parseParameterList(builder); + + eatBrackets(builder); + + if (areTypeAnnotationsSupported(builder)) { + final PsiBuilder.Marker receiver = builder.mark(); + final PsiBuilder.Marker annotations = parseAnnotations(builder); + if (annotations != null) { + receiver.done(JavaElementType.METHOD_RECEIVER); + } + else { + receiver.drop(); + } + } + + ReferenceParser.parseReferenceList(builder, JavaTokenType.THROWS_KEYWORD, JavaElementType.THROWS_LIST, JavaTokenType.COMMA); + + if (anno && expect(builder, JavaTokenType.DEFAULT_KEYWORD)) { + parseAnnotationValue(builder); + } + + final IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.SEMICOLON) { + builder.advanceLexer(); + } + else if (tokenType == JavaTokenType.LBRACE) { + StatementParser.parseCodeBlock(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.lbrace.or.semicolon")); + // todo: special treatment - like in fields (DeclarationParserTest.testMultiLineUnclosed()) + } + + declaration.done(anno ? JavaElementType.ANNOTATION_METHOD : JavaElementType.METHOD); + return declaration; + } + + @NotNull + private static PsiBuilder.Marker parseParameterList(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType(); + final PsiBuilder.Marker paramList = builder.mark(); + builder.advanceLexer(); + + PsiBuilder.Marker invalidElements = null; + boolean commaExpected = false; + int paramCount = 0; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null || tokenType == JavaTokenType.RPARENTH) { + boolean noLastParam = !commaExpected && paramCount > 0; + if (noLastParam) { + error(builder, JavaErrorMessages.message("expected.identifier.or.type")); + } + if (!expect(builder, JavaTokenType.RPARENTH)) { + if (!noLastParam) { + error(builder, JavaErrorMessages.message("expected.rparen")); + } + } + break; + } + + if (commaExpected) { + if (builder.getTokenType() == JavaTokenType.COMMA) { + commaExpected = false; + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("expected.parameter")); + invalidElements = null; + } + builder.advanceLexer(); + continue; + } + } + else { + final PsiBuilder.Marker param = parseParameter(builder, true); + if (param != null) { + commaExpected = true; + if (invalidElements != null) { + invalidElements.errorBefore(JavaErrorMessages.message("expected.comma"), param); + invalidElements = null; + } + paramCount++; + continue; + } + } + + if (invalidElements == null) { + if (builder.getTokenType() == JavaTokenType.COMMA) { + error(builder, JavaErrorMessages.message("expected.parameter")); + builder.advanceLexer(); + continue; + } + else { + invalidElements = builder.mark(); + } + } + + // adding a reference, not simple tokens allows "Browse .." to work well + final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false); + if (ref == null && builder.getTokenType() != null) { + builder.advanceLexer(); + } + } + + if (invalidElements != null) { + invalidElements.error(commaExpected ? JavaErrorMessages.message("expected.comma") : JavaErrorMessages.message("expected.parameter")); + } + + paramList.done(JavaElementType.PARAMETER_LIST); + return paramList; + } + + @Nullable + private static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis) { + final PsiBuilder.Marker param = builder.mark(); + + final Pair modListInfo = parseModifierList(builder); + final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) : + ReferenceParser.parseType(builder, true, true); + + if (type == null && modListInfo.second) { + param.rollbackTo(); + return null; + } + + if (type == null) { + error(builder, JavaErrorMessages.message("expected.type")); + emptyElement(builder, JavaElementType.TYPE); + } + + if (expect(builder, JavaTokenType.IDENTIFIER)) { + eatBrackets(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + + param.done(JavaElementType.PARAMETER); + return param; } @Nullable @@ -389,12 +529,8 @@ public class DeclarationParser { boolean eatSemicolon = true; boolean expectSemicolon = true; while (true) { - while (expect(builder, JavaTokenType.LBRACKET)) { - if (!expect(builder, JavaTokenType.RBRACKET)) { - error(builder, JavaErrorMessages.message("expected.rbracket")); - expectSemicolon = false; - break; - } + if (!eatBrackets(builder)) { + expectSemicolon = false; } if (expect(builder, JavaTokenType.EQ)) { @@ -438,6 +574,16 @@ public class DeclarationParser { return declaration; } + private static boolean eatBrackets(final PsiBuilder builder) { + while (expect(builder, JavaTokenType.LBRACKET)) { + if (!expect(builder, JavaTokenType.RBRACKET)) { + error(builder, JavaErrorMessages.message("expected.rbracket")); + return false; + } + } + return true; + } + @Nullable public static PsiBuilder.Marker parseAnnotations(final PsiBuilder builder) { PsiBuilder.Marker firstAnno = null; @@ -452,6 +598,7 @@ public class DeclarationParser { @NotNull private static PsiBuilder.Marker parseAnnotation(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.AT : builder.getTokenType(); final PsiBuilder.Marker anno = builder.mark(); builder.advanceLexer(); @@ -570,6 +717,7 @@ public class DeclarationParser { @NotNull private static PsiBuilder.Marker parseAnnotationArrayInitializer(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.LBRACE : builder.getTokenType(); final PsiBuilder.Marker annoArray = builder.mark(); builder.advanceLexer(); diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java index 89ed2e5c7fa5..6a3597e5f897 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java @@ -44,7 +44,7 @@ public class JavaParserUtil { @NotNull private static LanguageLevel getLanguageLevel(final PsiBuilder builder) { final LanguageLevel level = builder.getUserData(LANG_LEVEL_KEY); - assert level != null; + assert level != null : builder; return level; } @@ -75,7 +75,7 @@ public class JavaParserUtil { } public static void emptyElement(final PsiBuilder.Marker before, final IElementType type) { - before.precede().done(type); + before.precede().doneBefore(type, before); } public static PsiBuilder braceMatchingBuilder(final PsiBuilder builder) { diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 62fa6078d640..da8be88afb9e 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -278,28 +278,26 @@ public class ReferenceParser { return null; } - if (expect(builder, JavaTokenType.EXTENDS_KEYWORD)) { - parseReferenceList(builder, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND); - } - else { - emptyElement(builder, JavaElementType.EXTENDS_BOUND_LIST); - } + parseReferenceList(builder, JavaTokenType.EXTENDS_KEYWORD, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND); param.done(JavaElementType.TYPE_PARAMETER); return param; } @NotNull - private static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType type, final IElementType delimiter) { + public static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType start, + final IElementType type, final IElementType delimiter) { final PsiBuilder.Marker element = builder.mark(); - while (true) { - final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true); - if (classReference == null) { - error(builder, JavaErrorMessages.message("expected.identifier")); - } - if (!expect(builder, delimiter)) { - break; + if (expect(builder, start)) { + while (true) { + final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true); + if (classReference == null) { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + if (!expect(builder, delimiter)) { + break; + } } } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java index 06d8532bd20d..d08d0ff88324 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -16,6 +16,8 @@ package com.intellij.lang.java.parser; import com.intellij.lang.PsiBuilder; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.impl.source.tree.JavaElementType; import org.jetbrains.annotations.Nullable; @@ -24,6 +26,18 @@ public class StatementParser { @Nullable public static PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) { + if (builder.getTokenType() != JavaTokenType.LBRACE) return null; + + final PsiBuilder.Marker codeBlock = builder.mark(); + builder.advanceLexer(); + + // temp + if (builder.getTokenType() == JavaTokenType.RBRACE) { + builder.advanceLexer(); + codeBlock.done(JavaElementType.CODE_BLOCK); + return codeBlock; + } + // todo: implement throw new UnsupportedOperationException(builder.toString()); } diff --git a/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt new file mode 100644 index 000000000000..7b9cfccf79de --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt @@ -0,0 +1,33 @@ +PsiJavaFile:CompletionHack0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:s + PsiModifierList: + + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:X + PsiIdentifier:X('X') + PsiElement(EXTENDS_BOUND_LIST) + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected identifier + PsiIdentifier:IntelliJIdeaRulezz('IntelliJIdeaRulezz') + PsiJavaToken:GT('>') + PsiWhiteSpace('\n ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:s('s') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:"" + PsiJavaToken:STRING_LITERAL('""') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt new file mode 100644 index 000000000000..127827743962 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt @@ -0,0 +1,31 @@ +PsiJavaFile:CompletionHack1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:s + PsiModifierList: + + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:X + PsiIdentifier:X('X') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace('\n ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:s('s') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:"" + PsiJavaToken:STRING_LITERAL('""') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Errors.txt b/java/java-tests/testData/psi/parser-partial/declarations/Errors.txt new file mode 100644 index 000000000000..609379fee3fa --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Errors.txt @@ -0,0 +1,45 @@ +PsiJavaFile:Errors.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiModifierList:public static + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:static('static') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:error + PsiIdentifier:error('error') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace(' ') + PsiTypeElement:descr + PsiJavaCodeReferenceElement:descr + PsiIdentifier:descr('descr') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiErrorElement:Unexpected token + PsiJavaToken:EQ('=') + PsiJavaToken:STRING_LITERAL('"2"') + PsiJavaToken:GT('>') + PsiField:f1 + PsiModifierList:protected + PsiKeyword:protected('protected') + PsiWhiteSpace(' ') + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:f1('f1') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt new file mode 100644 index 000000000000..7504f3612d97 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt @@ -0,0 +1,91 @@ +PsiJavaFile:GenericMethod.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:test + PsiModifierList:public static + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:static('static') + PsiWhiteSpace(' ') + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:E + PsiIdentifier:E('E') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:test('test') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n ') + PsiMethod:test1 + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:E + PsiIdentifier:E('E') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:test1('test1') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n ') + PsiMethod:test2 + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:E1 + PsiIdentifier:E1('E1') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:Integer + PsiIdentifier:Integer('Integer') + PsiReferenceParameterList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiTypeParameter:E2 + PsiIdentifier:E2('E2') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:Runnable + PsiIdentifier:Runnable('Runnable') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:test2('test2') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt new file mode 100644 index 000000000000..5be504737907 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt @@ -0,0 +1,43 @@ +PsiJavaFile:GenericMethodErrors.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiModifierList: + + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:Error + PsiIdentifier:Error('Error') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace(' ') + PsiTypeElement:sss + PsiJavaCodeReferenceElement:sss + PsiIdentifier:sss('sss') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected token + PsiJavaToken:DIV('/') + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:test + PsiIdentifier:test('test') + PsiWhiteSpace(' ') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:error + PsiJavaCodeReferenceElement:error + PsiIdentifier:error('error') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt new file mode 100644 index 000000000000..f2383f5aaae4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt @@ -0,0 +1,24 @@ +PsiJavaFile:MethodNormal0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt new file mode 100644 index 000000000000..b146b9b578d8 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt @@ -0,0 +1,20 @@ +PsiJavaFile:MethodNormal1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt new file mode 100644 index 000000000000..9353f05c8052 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt @@ -0,0 +1,21 @@ +PsiJavaFile:Unclosed0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt new file mode 100644 index 000000000000..c7b4159c5357 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt @@ -0,0 +1,22 @@ +PsiJavaFile:Unclosed1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:( + PsiJavaToken:LPARENTH('(') + PsiErrorElement:')' expected + + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt new file mode 100644 index 000000000000..b2a0dfe174c4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt @@ -0,0 +1,37 @@ +PsiJavaFile:Unclosed2.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace('\n ') + PsiMethod:g + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:g('g') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt new file mode 100644 index 000000000000..82caa1cf199e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt @@ -0,0 +1,29 @@ +PsiJavaFile:Unclosed3.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:(int a + PsiJavaToken:LPARENTH('(') + PsiParameter:a + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:a('a') + PsiErrorElement:')' expected + + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt new file mode 100644 index 000000000000..d7ffeea84e44 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt @@ -0,0 +1,33 @@ +PsiJavaFile:Unclosed4.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:(int a,, + PsiJavaToken:LPARENTH('(') + PsiParameter:a + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:a('a') + PsiJavaToken:COMMA(',') + PsiErrorElement:Parameter expected + + PsiJavaToken:COMMA(',') + PsiErrorElement:Identifier or type expected + + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt new file mode 100644 index 000000000000..a0166d829e10 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt @@ -0,0 +1,30 @@ +PsiJavaFile:Unclosed5.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:(int a,) + PsiJavaToken:LPARENTH('(') + PsiParameter:a + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:a('a') + PsiJavaToken:COMMA(',') + PsiErrorElement:Identifier or type expected + + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt b/java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt new file mode 100644 index 000000000000..b433896f20bb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt @@ -0,0 +1,55 @@ +PsiJavaFile:WildcardParsing.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:x + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:List + PsiJavaCodeReferenceElement:List + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:? extends B + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiTypeElement:B + PsiJavaCodeReferenceElement:B + PsiIdentifier:B('B') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiParameterList:(Collection x) + PsiJavaToken:LPARENTH('(') + PsiParameter:x + PsiModifierList: + + PsiTypeElement:Collection + PsiJavaCodeReferenceElement:Collection + PsiIdentifier:Collection('Collection') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:? super B + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiKeyword:super('super') + PsiWhiteSpace(' ') + PsiTypeElement:B + PsiJavaCodeReferenceElement:B + PsiIdentifier:B('B') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt index 51d776e6a39e..a7329da61f08 100644 --- a/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt @@ -4,9 +4,9 @@ PsiJavaFile:TypeParams5.java PsiTypeParameter:T PsiIdentifier:T('T') PsiWhiteSpace(' ') - PsiKeyword:extends('extends') - PsiWhiteSpace(' ') PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') PsiJavaCodeReferenceElement:X PsiIdentifier:X('X') PsiReferenceParameterList diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt index f3cf0196d19a..aaea7b8c3d5d 100644 --- a/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt @@ -4,9 +4,9 @@ PsiJavaFile:TypeParams7.java PsiTypeParameter:T PsiIdentifier:T('T') PsiWhiteSpace(' ') - PsiKeyword:extends('extends') - PsiWhiteSpace(' ') PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') PsiJavaCodeReferenceElement:X PsiIdentifier:X('X') PsiReferenceParameterList diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java index 7d516c955c89..577e74a93c53 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java @@ -44,6 +44,23 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testMissingInitializerExpression() { doParserTest("{ int field=; }", false, false); } //public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } // todo: implement + //public void testMethodNormal0() { doParserTest("{ void f() { } }", false, false); } // todo: parse code block correctly + public void testMethodNormal1() { doParserTest("{ void f(); }", false, false); } + public void testUnclosed0() { doParserTest("{ void f() }", false, false); } + public void testUnclosed1() { doParserTest("{ void f( }", false, false); } + public void testUnclosed2() { doParserTest("{ void f()\n void g(); }", false, false); } + public void testUnclosed3() { doParserTest("{ void f(int a }", false, false); } + public void testUnclosed4() { doParserTest("{ void f(int a,, }", false, false); } + public void testUnclosed5() { doParserTest("{ void f(int a,); }", false, false); } + public void testGenericMethod() { doParserTest("{ public static test();\n" + + " void test1();\n" + + " String test2(); }", false, false); } + public void testGenericMethodErrors() { doParserTest("{ test (); }", false, false); } + public void testErrors() { doParserTest("{ public static protected int f1 = 0; }", false, false); } + public void testCompletionHack0() { doParserTest("{ \n String s = \"\"; }", false, false); } + public void testCompletionHack1() { doParserTest("{ x(Collection x); }", false, false); } + private void doParserTest(final String text, final boolean isAnnotation, final boolean isEnum) { doParserTest(text, new Parser() { public void parse(final PsiBuilder builder) {