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 63908d4e6e4c..873de14dd69c 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 @@ -18,7 +18,6 @@ package com.intellij.lang.java.parser; 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; @@ -30,6 +29,7 @@ import org.jetbrains.annotations.NotNull; 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.*; @@ -38,18 +38,14 @@ public class DeclarationParser { FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE } - private static final Logger LOG = Logger.getInstance("#com.intellij.lang.java.parser.DeclarationParser"); - private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD); + private static final TokenSet BEFORE_LBRACE_ELEMENTS_SET = TokenSet.create( + JavaTokenType.IDENTIFIER, JavaTokenType.COMMA, JavaTokenType.EXTENDS_KEYWORD, JavaTokenType.IMPLEMENTS_KEYWORD); private DeclarationParser() { } - @Nullable - public static PsiBuilder.Marker parseClassBodyWithBraces(final PsiBuilder builder, final boolean isAnnotation, final boolean isEnum) { - if (builder.getTokenType() != JavaTokenType.LBRACE) return null; - - final PsiBuilder.Marker marker = builder.mark(); - marker.drop(); + public static void parseClassBodyWithBraces(final PsiBuilder builder, final boolean isAnnotation, final boolean isEnum) { + assert builder.getTokenType() == JavaTokenType.LBRACE : builder.getTokenType(); builder.advanceLexer(); final PsiBuilder builderWrapper = braceMatchingBuilder(builder); @@ -59,15 +55,38 @@ public class DeclarationParser { parseClassBodyDeclarations(builderWrapper, isAnnotation); expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace")); - - return marker; } - @Nullable - private static PsiBuilder.Marker parseClassFromKeyword(final PsiBuilder builder, final PsiBuilder.Marker start, - final boolean isAnnotation) { - // todo: implement - throw new UnsupportedOperationException(builder.toString() + start + isAnnotation); + @NotNull + private static PsiBuilder.Marker parseClassFromKeyword(final PsiBuilder builder, final PsiBuilder.Marker declaration, + final boolean isAnnotation) { + final IElementType keywordTokenType = builder.getTokenType(); + assert ElementType.CLASS_KEYWORD_BIT_SET.contains(keywordTokenType) : keywordTokenType; + builder.advanceLexer(); + final boolean isEnum = (keywordTokenType == JavaTokenType.ENUM_KEYWORD); + + if (!expect(builder, JavaTokenType.IDENTIFIER)) { + error(builder, JavaErrorMessages.message("expected.identifier")); + declaration.drop(); + return declaration; + } + + ReferenceParser.parseTypeParameters(builder); + ReferenceParser.parseReferenceList(builder, JavaTokenType.EXTENDS_KEYWORD, JavaElementType.EXTENDS_LIST, JavaTokenType.COMMA); + ReferenceParser.parseReferenceList(builder, JavaTokenType.IMPLEMENTS_KEYWORD, JavaElementType.IMPLEMENTS_LIST, JavaTokenType.COMMA); + + if (builder.getTokenType() != JavaTokenType.LBRACE) { + final PsiBuilder.Marker error = builder.mark(); + while (BEFORE_LBRACE_ELEMENTS_SET.contains(builder.getTokenType())) { + builder.advanceLexer(); + } + error.error(JavaErrorMessages.message("expected.lbrace")); + } + + parseClassBodyWithBraces(builder, isAnnotation, isEnum); + + declaration.done(JavaElementType.CLASS); + return declaration; } private static void parseEnumConstants(final PsiBuilder builder) { @@ -276,7 +295,7 @@ public class DeclarationParser { } final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder); - LOG.assertTrue(codeBlock != null); + assert codeBlock != null : builder.getOriginalText(); if (typeParams != null) { final PsiBuilder.Marker error = typeParams.precede(); @@ -294,6 +313,7 @@ public class DeclarationParser { error = builder.mark(); } error.error(JavaErrorMessages.message("expected.identifier.or.type")); + declaration.drop(); return modList; } @@ -347,11 +367,7 @@ public class DeclarationParser { isEmpty = false; } else if (tokenType == JavaTokenType.AT) { - final PsiBuilder.Marker pos = builder.mark(); - builder.advanceLexer(); - final IElementType nextTokenType = builder.getTokenType(); - pos.rollbackTo(); - if (ElementType.KEYWORD_BIT_SET.contains(nextTokenType)) { + if (ElementType.KEYWORD_BIT_SET.contains(nextTokenType(builder))) { break; } parseAnnotation(builder); @@ -519,8 +535,8 @@ public class DeclarationParser { varType = JavaElementType.LOCAL_VARIABLE; } else { - LOG.error("Unexpected context: " + context); declaration.drop(); + assert false : "Unexpected context: " + context; return null; } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java index b649997a7b72..294129d3b50a 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java @@ -34,8 +34,6 @@ import static com.intellij.lang.java.parser.JavaParserUtil.error; public class ExpressionParser { - private static final Logger LOG = Logger.getInstance("#com.intellij.lang.java.parser.ExpressionParser"); - private enum ExprType { CONDITIONAL_OR, CONDITIONAL_AND, OR, XOR, AND, EQUALITY, RELATIONAL, SHIFT, ADDITIVE, MULTIPLICATIVE, UNARY, TYPE } @@ -168,7 +166,7 @@ public class ExpressionParser { return typeInfo != null ? typeInfo.marker : null; default: - LOG.error("Unexpected type: " + type); + assert false : "Unexpected type: " + type; return null; } } 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 d08d0ff88324..bbf17fed22c6 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 @@ -17,28 +17,93 @@ package com.intellij.lang.java.parser; import com.intellij.lang.PsiBuilder; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.SmartList; import org.jetbrains.annotations.Nullable; +import java.util.List; + public class StatementParser { + private static final boolean DEEP_PARSE_BLOCKS_IN_STATEMENTS = true; // todo: reset after testing done + private StatementParser() { } @Nullable public static PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) { if (builder.getTokenType() != JavaTokenType.LBRACE) return null; + else if (DEEP_PARSE_BLOCKS_IN_STATEMENTS) return parseCodeBlockDeep(builder); + + final PsiBuilder.Marker codeBlock = builder.mark(); + builder.advanceLexer(); + + int braceCount = 1; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null) { + break; + } + if (tokenType == JavaTokenType.LBRACE) { + braceCount++; + } + else if (tokenType == JavaTokenType.RBRACE) { + braceCount--; + } + builder.advanceLexer(); + + if (braceCount == 0) { + break; + } + else if (braceCount == 1 && (tokenType == JavaTokenType.SEMICOLON || tokenType == JavaTokenType.RBRACE)) { + final PsiBuilder.Marker position = builder.mark(); + final List list = new SmartList(); + while (true) { + final IElementType type = builder.getTokenType(); + if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || ElementType.MODIFIER_BIT_SET.contains(type) || + type == JavaTokenType.IDENTIFIER || type == JavaTokenType.LT || type == JavaTokenType.GT || + type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type == JavaTokenType.COMMA || + type == JavaTokenType.DOT || type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) { + list.add(type); + builder.advanceLexer(); + } else { + break; + } + } + if (builder.getTokenType() == JavaTokenType.LPARENTH && list.size() >= 2) { + final IElementType last = list.get(list.size() - 1); + final IElementType prevLast = list.get(list.size() - 2); + if (last == JavaTokenType.IDENTIFIER && + (prevLast == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(prevLast))) { + position.rollbackTo(); + break; + } + } + position.drop(); + } + } + + codeBlock.collapse(JavaElementType.CODE_BLOCK); + return codeBlock; + } + + @Nullable + public static PsiBuilder.Marker parseCodeBlockDeep(final PsiBuilder builder) { + if (builder.getTokenType() != JavaTokenType.LBRACE) return null; final PsiBuilder.Marker codeBlock = builder.mark(); builder.advanceLexer(); // temp - if (builder.getTokenType() == JavaTokenType.RBRACE) { + if (builder.getTokenType() == JavaTokenType.RBRACE || builder.eof()) { builder.advanceLexer(); codeBlock.done(JavaElementType.CODE_BLOCK); return codeBlock; } // todo: implement + codeBlock.drop(); throw new UnsupportedOperationException(builder.toString()); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaTypeParameterListElementType.java b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaTypeParameterListElementType.java index ff3c51c360d1..b2717330ff06 100644 --- a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaTypeParameterListElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaTypeParameterListElementType.java @@ -26,15 +26,14 @@ import com.intellij.psi.impl.java.stubs.impl.PsiTypeParameterListStubImpl; import com.intellij.psi.impl.source.tree.java.PsiTypeParameterListImpl; import com.intellij.psi.stubs.IndexSink; import com.intellij.psi.stubs.StubElement; -import com.intellij.psi.stubs.StubOutputStream; import com.intellij.psi.stubs.StubInputStream; -import com.intellij.util.io.PersistentStringEnumerator; +import com.intellij.psi.stubs.StubOutputStream; import java.io.IOException; public class JavaTypeParameterListElementType extends JavaStubElementType { public JavaTypeParameterListElementType() { - super("TYPE_PARAMETER_LIST"); + super("TYPE_PARAMETER_LIST", true); } public PsiTypeParameterList createPsi(final PsiTypeParameterListStub stub) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java index 50b46e9f927f..dcd61fa4e1b9 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaASTFactory.java @@ -289,6 +289,10 @@ public class JavaASTFactory extends ASTFactory implements Constants { else if (type == METHOD_RECEIVER) { return new PsiMethodReceiverImpl(); } + else if (type == CODE_BLOCK) { + // deep code block parsing + return new PsiCodeBlockImpl(null); + } return new CompositePsiElement(type){}; } diff --git a/java/java-tests/testData/psi/parser-partial/declarations/ClassInit.txt b/java/java-tests/testData/psi/parser-partial/declarations/ClassInit.txt new file mode 100644 index 000000000000..443a3f440140 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/ClassInit.txt @@ -0,0 +1,14 @@ +PsiJavaFile:ClassInit.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiClassInitializer + PsiModifierList: + + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiComment(C_STYLE_COMMENT)('/*comment*/') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody2.txt b/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody2.txt new file mode 100644 index 000000000000..63a6641d28eb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody2.txt @@ -0,0 +1,16 @@ +PsiJavaFile:EmptyBody2.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiModifierList:@Null + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Null + PsiIdentifier:Null('Null') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiErrorElement:Identifier or type expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody6.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody6.txt new file mode 100644 index 000000000000..d0199d5c67b4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody6.txt @@ -0,0 +1,45 @@ +PsiJavaFile:EnumBody6.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:RED + PsiModifierList: + + PsiIdentifier:RED('RED') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:GREEN + PsiModifierList: + + PsiIdentifier:GREEN('GREEN') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:BLUE + PsiModifierList: + + PsiIdentifier:BLUE('BLUE') + PsiExpressionList + + PsiErrorElement:',' or ';' expected + + PsiWhiteSpace('\n ') + PsiMethod:OurEnum + PsiModifierList: + + PsiTypeParameterList + + PsiIdentifier:OurEnum('OurEnum') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumWithInitializedConstants.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumWithInitializedConstants.txt new file mode 100644 index 000000000000..287b552cfaca --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumWithInitializedConstants.txt @@ -0,0 +1,51 @@ +PsiJavaFile:EnumWithInitializedConstants.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:A + PsiModifierList: + + PsiIdentifier:A('A') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:10 + PsiJavaToken:INTEGER_LITERAL('10') + PsiJavaToken:RPARENTH(')') + PsiWhiteSpace(' ') + PsiAnonymousClass (PsiEnumConstantInitializerImpl)): + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiJavaToken:COMMA(',') + PsiWhiteSpace('\n ') + PsiEnumConstant:B + PsiModifierList: + + PsiIdentifier:B('B') + PsiExpressionList + + PsiWhiteSpace(' ') + PsiAnonymousClass (PsiEnumConstantInitializerImpl)): + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:method + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:method('method') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumWithoutConstants.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumWithoutConstants.txt new file mode 100644 index 000000000000..75b0a6624bd4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumWithoutConstants.txt @@ -0,0 +1,17 @@ +PsiJavaFile:EnumWithoutConstants.java + PsiJavaToken:LBRACE('{') + PsiErrorElement:';' expected + + PsiWhiteSpace(' ') + PsiModifierList:private + PsiKeyword:private('private') + PsiWhiteSpace(' ') + PsiTypeElement:A + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/ExtraSemicolon.txt b/java/java-tests/testData/psi/parser-partial/declarations/ExtraSemicolon.txt new file mode 100644 index 000000000000..b444db53a751 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/ExtraSemicolon.txt @@ -0,0 +1,22 @@ +PsiJavaFile:ExtraSemicolon.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiClass:C + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:C('C') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/IncompleteAnnotation.txt b/java/java-tests/testData/psi/parser-partial/declarations/IncompleteAnnotation.txt new file mode 100644 index 000000000000..4567aab462bb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/IncompleteAnnotation.txt @@ -0,0 +1,51 @@ +PsiJavaFile:IncompleteAnnotation.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiClass:Foo + PsiModifierList:public + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:Foo('Foo') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:testSomething + PsiModifierList:public + PsiKeyword:public('public') + PsiTypeParameterList + + PsiWhiteSpace(' ') + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:testSomething('testSomething') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiModifierList:@Null + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Null + PsiIdentifier:Null('Null') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiErrorElement:Identifier or type expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + 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 index f2383f5aaae4..c9f9ad5b179d 100644 --- a/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt +++ b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt @@ -18,7 +18,6 @@ PsiJavaFile:MethodNormal0.java 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/NoType.txt b/java/java-tests/testData/psi/parser-partial/declarations/NoType.txt new file mode 100644 index 000000000000..5507c36b57ee --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/NoType.txt @@ -0,0 +1,20 @@ +PsiJavaFile:NoType.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected token + PsiKeyword:new('new') + PsiWhiteSpace(' ') + PsiMethod:X + PsiModifierList: + + PsiTypeParameterList + + PsiIdentifier:X('X') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/ParameterizedClass.txt b/java/java-tests/testData/psi/parser-partial/declarations/ParameterizedClass.txt new file mode 100644 index 000000000000..262c0c8ce39d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/ParameterizedClass.txt @@ -0,0 +1,44 @@ +PsiJavaFile:ParameterizedClass.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiClass:A + PsiModifierList:public + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:A('A') + PsiWhiteSpace(' ') + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.util.List + PsiJavaCodeReferenceElement:java.util + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:util('util') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:List('List') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + 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/Pines.txt b/java/java-tests/testData/psi/parser-partial/declarations/Pines.txt new file mode 100644 index 000000000000..afbe40ee6412 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Pines.txt @@ -0,0 +1,56 @@ +PsiJavaFile:Pines.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiClass:A + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:A('A') + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:List + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiReferenceList + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:List> + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:List + PsiJavaCodeReferenceElement:List + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:Integer + PsiJavaCodeReferenceElement:Integer + PsiIdentifier:Integer('Integer') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:GT('>') + PsiReferenceList + + PsiWhiteSpace(' ') + 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/Semicolons.txt b/java/java-tests/testData/psi/parser-partial/declarations/Semicolons.txt new file mode 100644 index 000000000000..0327c01fd55b --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Semicolons.txt @@ -0,0 +1,44 @@ +PsiJavaFile:Semicolons.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('{') + PsiJavaToken:RBRACE('}') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiMethod:g + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:g('g') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testSrc/com/intellij/JavaTestUtil.java b/java/java-tests/testSrc/com/intellij/JavaTestUtil.java index 7e9c239d60ab..4ea7a14d3e37 100644 --- a/java/java-tests/testSrc/com/intellij/JavaTestUtil.java +++ b/java/java-tests/testSrc/com/intellij/JavaTestUtil.java @@ -1,12 +1,12 @@ package com.intellij; import com.intellij.lang.PsiBuilder; -import com.intellij.lang.impl.PsiBuilderImpl; +import com.intellij.lang.PsiBuilderFactory; +import com.intellij.lang.StdLanguages; import com.intellij.lang.java.parser.JavaParserUtil; import com.intellij.lexer.JavaLexer; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.JavaTokenType; /** * @author yole @@ -20,10 +20,11 @@ public class JavaTestUtil { return PathManagerEx.getTestDataPath(); } - public static PsiBuilder getJavaBuilder(final String source) { + public static PsiBuilder getJavaBuilder(final CharSequence source) { final LanguageLevel languageLevel = LanguageLevel.HIGHEST; final JavaLexer lexer = new JavaLexer(languageLevel); - final PsiBuilder builder = new PsiBuilderImpl(lexer, JavaTokenType.WHITESPACE_BIT_SET, JavaTokenType.COMMENT_BIT_SET, source); + final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(lexer, StdLanguages.JAVA, source); + builder.setDebugMode(true); JavaParserUtil.setLanguageLevel(builder, languageLevel); return builder; } 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 577e74a93c53..977c9d6ea852 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 @@ -20,6 +20,7 @@ import com.intellij.lang.java.parser.DeclarationParser; import com.intellij.lang.java.parser.JavaParsingTestCase; +// todo: fix parser and uncomment tests public class DeclarationParserTest extends JavaParsingTestCase { public DeclarationParserTest() { super("parser-partial/declarations"); @@ -27,6 +28,14 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testEmptyBody0() { doParserTest("{ }", false, false); } public void testEmptyBody1() { doParserTest("{ ", false, false); } + public void testEmptyBody2() { doParserTest("{ @Null }", false, false); } + + public void testNoType() { doParserTest("{ new X(); }", false, false); } + public void testExtraSemicolon() { doParserTest("{ class C { }; }", false, false); } + public void testParameterizedClass() { doParserTest("{ public class A { } }", false, false); } + public void testPines() { doParserTest("{ class A> extends List> { } }", false, false); } + public void testIncompleteAnnotation() { doParserTest("{ public class Foo { public void testSomething(); @Null } }", false, false); } + public void testClassInit() { doParserTest("{ { /*comment*/ } }", false, false); } public void testEnumBody0() { doParserTest("{ ; }", false, true); } public void testEnumBody1() { doParserTest("{ RED, GREEN, BLUE; }", false, true); } @@ -34,6 +43,9 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testEnumBody3() { doParserTest("{ RED, GREEN, BLUE, }", false, true); } public void testEnumBody4() { doParserTest("{ RED(0), GREEN(1), BLUE(2); }", false, true); } public void testEnumBody5() { doParserTest("{ @ANNOTATION A(10) }", false, true); } + //public void testEnumBody6() { doParserTest("{ RED, GREEN, BLUE\n OurEnum() {} }", false, true); } + public void testEnumWithInitializedConstants() { doParserTest("{ A(10) { },\n B { void method() {} } }", false, true); } + public void testEnumWithoutConstants() { doParserTest("{ private A }", false, true); } public void testFieldSimple() { doParserTest("{ int field = 0; }", false, false); } public void testFieldMulti() { doParserTest("{ int field1 = 0, field2; }", false, false); } @@ -42,10 +54,11 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testUnclosedComma() { doParserTest("{ int field, }", false, false); } public void testUnclosedSemicolon() { doParserTest("{ int field }", false, false); } public void testMissingInitializerExpression() { doParserTest("{ int field=; }", false, false); } - //public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } // todo: implement + //public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } - //public void testMethodNormal0() { doParserTest("{ void f() { } }", false, false); } // todo: parse code block correctly + public void testMethodNormal0() { doParserTest("{ void f() {} }", false, false); } public void testMethodNormal1() { doParserTest("{ void f(); }", false, false); } + public void testSemicolons() { doParserTest("{ void f() {}; void g() {}; }", 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); }