From 310e1ffc64a34b47e8966ae6b459a586c9b7fdc9 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 22 Jul 2010 16:16:46 +0400 Subject: [PATCH 1/7] New Java parser (work in progress) --- .../lang/java/parser/DeclarationParser.java | 437 +++++++++ .../lang/java/parser/ExpressionParser.java | 852 ++++++++++++++++++ .../intellij/lang/java/parser/JavaParser.java | 45 + .../lang/java/parser/JavaParserUtil.java | 63 ++ .../lang/java/parser/ReferenceParser.java | 294 ++++++ .../JavaClassReferenceListElementType.java | 2 +- .../impl/java/stubs/JavaStubElementType.java | 12 + .../psi/impl/source/tree/JavaElementType.java | 4 +- java/java-tests/java-tests.iml | 2 +- .../psi/parser-partial/annotations/Array.txt | 20 + .../parser-partial/annotations/Complex.txt | 22 + .../annotations/FirstNameMissed.txt | 26 + .../psi/parser-partial/annotations/Marker.txt | 9 + .../parser-partial/annotations/Multiple.txt | 26 + .../psi/parser-partial/annotations/Nested.txt | 32 + .../annotations/ParameterizedAnnotation.txt | 13 + .../annotations/QualifiedAnnotation.txt | 24 + .../parser-partial/annotations/Simple0.txt | 13 + .../parser-partial/annotations/Simple1.txt | 15 + .../expressions/ArrayInitializer0.txt | 5 + .../expressions/ArrayInitializer1.txt | 8 + .../expressions/ArrayInitializer2.txt | 9 + .../expressions/ArrayInitializer3.txt | 11 + .../expressions/ArrayInitializer4.txt | 13 + .../expressions/ArrayInitializer5.txt | 12 + .../expressions/ArrayInitializer6.txt | 7 + .../expressions/ArrayInitializer7.txt | 16 + .../expressions/Assignment0.txt | 11 + .../expressions/Assignment1.txt | 10 + .../psi/parser-partial/expressions/Cast.txt | 13 + .../psi/parser-partial/expressions/Cond0.txt | 16 + .../psi/parser-partial/expressions/Cond1.txt | 10 + .../psi/parser-partial/expressions/Cond2.txt | 13 + .../psi/parser-partial/expressions/Cond3.txt | 15 + .../parser-partial/expressions/CondOr0.txt | 21 + .../parser-partial/expressions/CondOr1.txt | 10 + .../parser-partial/expressions/ExprList0.txt | 14 + .../parser-partial/expressions/ExprList1.txt | 10 + .../parser-partial/expressions/ExprList2.txt | 12 + .../parser-partial/expressions/ExprList3.txt | 17 + .../parser-partial/expressions/ExprList4.txt | 16 + .../parser-partial/expressions/ExprList5.txt | 19 + .../parser-partial/expressions/ExprList6.txt | 16 + .../psi/parser-partial/expressions/GE.txt | 17 + .../expressions/IllegalWildcard.txt | 24 + .../expressions/IncompleteCast.txt | 26 + .../expressions/InstanceOf0.txt | 14 + .../expressions/InstanceOf1.txt | 10 + .../psi/parser-partial/expressions/New0.txt | 13 + .../psi/parser-partial/expressions/New1.txt | 16 + .../psi/parser-partial/expressions/New10.txt | 12 + .../psi/parser-partial/expressions/New11.txt | 15 + .../psi/parser-partial/expressions/New12.txt | 15 + .../psi/parser-partial/expressions/New13.txt | 19 + .../psi/parser-partial/expressions/New14.txt | 18 + .../psi/parser-partial/expressions/New2.txt | 14 + .../psi/parser-partial/expressions/New3.txt | 18 + .../psi/parser-partial/expressions/New4.txt | 19 + .../psi/parser-partial/expressions/New5.txt | 18 + .../psi/parser-partial/expressions/New6.txt | 7 + .../psi/parser-partial/expressions/New7.txt | 12 + .../psi/parser-partial/expressions/New8.txt | 13 + .../psi/parser-partial/expressions/New9.txt | 9 + .../expressions/NewInExprList.txt | 15 + .../psi/parser-partial/expressions/Not0.txt | 9 + .../psi/parser-partial/expressions/Not1.txt | 5 + .../psi/parser-partial/expressions/Or0.txt | 21 + .../psi/parser-partial/expressions/Or1.txt | 10 + .../parser-partial/expressions/Parenth0.txt | 8 + .../parser-partial/expressions/Parenth1.txt | 15 + .../PinesInReferenceExpression0.txt | 22 + .../PinesInReferenceExpression1.txt | 22 + .../PrimitiveClassObjectAccess.txt | 6 + .../expressions/QualifiedSuperMethodCall0.txt | 22 + .../expressions/QualifiedSuperMethodCall1.txt | 14 + .../parser-partial/expressions/ShiftRight.txt | 11 + .../SuperMethodCallTypeParameterList.txt | 9 + .../parser-partial/references/Reference0.txt | 5 + .../parser-partial/references/Reference1.txt | 9 + .../parser-partial/references/Reference2.txt | 10 + .../psi/parser-partial/references/Type0.txt | 3 + .../psi/parser-partial/references/Type1.txt | 11 + .../psi/parser-partial/references/Type2.txt | 6 + .../psi/parser-partial/references/Type3.txt | 9 + .../psi/parser-partial/references/Type4.txt | 24 + .../parser-partial/references/TypeParams0.txt | 8 + .../parser-partial/references/TypeParams1.txt | 14 + .../parser-partial/references/TypeParams2.txt | 9 + .../parser-partial/references/TypeParams3.txt | 11 + .../parser-partial/references/TypeParams4.txt | 12 + .../parser-partial/references/TypeParams5.txt | 27 + .../parser-partial/references/TypeParams6.txt | 15 + .../parser-partial/references/TypeParams7.txt | 20 + .../testSrc/com/intellij/JavaTestUtil.java | 14 + .../lang/java/parser/JavaParsingTestCase.java | 66 ++ .../parser/partial/AnnotationParserTest.java | 47 + .../parser/partial/ExpressionParserTest.java | 110 +++ .../parser/partial/ReferenceParserTest.java | 70 ++ .../psi/tree/java/IJavaElementType.java | 12 + .../src/com/intellij/lang/PsiBuilderUtil.java | 120 +++ 100 files changed, 3341 insertions(+), 4 deletions(-) create mode 100644 java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java create mode 100644 java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java create mode 100644 java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java create mode 100644 java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java create mode 100644 java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Array.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Complex.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/FirstNameMissed.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Marker.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Multiple.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Nested.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/ParameterizedAnnotation.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/QualifiedAnnotation.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Simple0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/annotations/Simple1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer5.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer6.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer7.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Assignment0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Assignment1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Cast.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Cond0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Cond1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Cond2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Cond3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/CondOr0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/CondOr1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList5.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ExprList6.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/GE.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/IncompleteCast.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/InstanceOf0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/InstanceOf1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New10.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New11.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New12.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New13.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New14.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New5.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New6.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New7.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New8.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/New9.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/NewInExprList.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Not0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Not1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Or0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Or1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Parenth0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/Parenth1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/PrimitiveClassObjectAccess.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/ShiftRight.txt create mode 100644 java/java-tests/testData/psi/parser-partial/expressions/SuperMethodCallTypeParameterList.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Reference0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Reference1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Reference2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Type0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Type1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Type2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Type3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/Type4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams6.txt create mode 100644 java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt create mode 100644 java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java create mode 100644 java/java-tests/testSrc/com/intellij/lang/java/parser/partial/AnnotationParserTest.java create mode 100644 java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java create mode 100644 java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java create mode 100644 platform/lang-api/src/com/intellij/lang/PsiBuilderUtil.java 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 new file mode 100644 index 000000000000..268e9c2fd5ac --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -0,0 +1,437 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +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.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.psi.tree.ILazyParseableElementType; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.intellij.lang.PsiBuilderUtil.expect; +import static com.intellij.lang.java.parser.JavaParserUtil.*; + + +public class DeclarationParser { + public enum Context { + FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE + } + + private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD); + + 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(); + builder.advanceLexer(); + + if (isEnum) { + parseEnumConstants(builder); + } + parseClassBodyDeclarations(builder, 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); + } + + private static void parseEnumConstants(final PsiBuilder builder) { + while (builder.getTokenType() != null) { + if (expect(builder, JavaTokenType.SEMICOLON)) { + return; + } + + if (builder.getTokenType() == JavaTokenType.PRIVATE_KEYWORD || builder.getTokenType() == JavaTokenType.PROTECTED_KEYWORD) { + error(builder, JavaErrorMessages.message("expected.semicolon")); + return; + } + + final PsiBuilder.Marker enumConstant = parseEnumConstant(builder); + if (enumConstant == null) { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + + if (!expect(builder, JavaTokenType.COMMA)) { + if (builder.getTokenType() != null && builder.getTokenType() != JavaTokenType.SEMICOLON) { + error(builder, JavaErrorMessages.message("expected.comma.or.semicolon")); + } + } + } + } + + @Nullable + private static PsiBuilder.Marker parseEnumConstant(final PsiBuilder builder) { + final PsiBuilder.Marker constant = builder.mark(); + + parseModifierList(builder); + + if (expect(builder, JavaTokenType.IDENTIFIER)) { + if (builder.getTokenType() == JavaTokenType.LPARENTH) { + ExpressionParser.parseArgumentList(builder); + } + else { + emptyElement(builder, JavaElementType.EXPRESSION_LIST); + } + + if (builder.getTokenType() == JavaTokenType.LBRACE) { + final PsiBuilder.Marker constantInit = builder.mark(); + parseClassBodyWithBraces(builder, false, false); + constantInit.done(JavaElementType.ENUM_CONSTANT_INITIALIZER); + } + + constant.done(JavaElementType.ENUM_CONSTANT); + return constant; + } + else { + constant.rollbackTo(); + return null; + } + } + + private static void parseClassBodyDeclarations(final PsiBuilder builder, final boolean isAnnotation) { + final Context context = isAnnotation ? Context.ANNOTATION_INTERFACE : Context.CLASS; + + PsiBuilder.Marker invalidElements = null; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null || tokenType == JavaTokenType.RBRACE) break; + + if (tokenType == JavaTokenType.SEMICOLON) { + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("unexpected.token")); + invalidElements = null; + } + builder.advanceLexer(); + continue; + } + + final PsiBuilder.Marker declaration = parseDeclaration(builder, context); + if (declaration != null) { + if (invalidElements != null) { + invalidElements.errorBefore(JavaErrorMessages.message("unexpected.token"), declaration); + invalidElements = null; + } + continue; + } + + if (invalidElements == null) { + 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.advanceLexer(); + } + } + + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("unexpected.token")); + } + } + + @Nullable + private static PsiBuilder.Marker parseDeclaration(final PsiBuilder builder, final Context context) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null) return null; + + if (tokenType == JavaTokenType.LBRACE) { + if (context == Context.FILE || context == Context.CODE_BLOCK) return null; + } + else if (tokenType == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) { + if (context == Context.FILE) return null; + } + else if (tokenType instanceof ILazyParseableElementType) { + final PsiBuilder.Marker declaration = builder.mark(); + declaration.drop(); + builder.advanceLexer(); + return declaration; + } + else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) && + !ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) && + tokenType != JavaTokenType.AT && + (context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) { + return null; + } + + final PsiBuilder.Marker declaration = builder.mark(); + + final PsiBuilder.Marker modList = parseModifierList(builder); + + if (expect(builder, JavaTokenType.AT)) { + if (tokenType == JavaTokenType.INTERFACE_KEYWORD) { + return parseClassFromKeyword(builder, declaration, true); + } + else { + declaration.rollbackTo(); + return null; + } + } + else if (ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType)) { + final PsiBuilder.Marker root = parseClassFromKeyword(builder, declaration, false); + + if (context == Context.FILE) { + // todo: append following declarations to root + boolean declarationsAfterEnd = false; + + while (builder.getTokenType() != null && builder.getTokenType() != JavaTokenType.RBRACE) { + final PsiBuilder.Marker position = builder.mark(); + final PsiBuilder.Marker element = parseDeclaration(builder, Context.CLASS); + if (element != null && AFTER_END_DECLARATION_SET.contains(((LighterASTNode)element).getTokenType())) { + if (!declarationsAfterEnd) { + element.precede().error(JavaErrorMessages.message("expected.class.or.interface")); + } + declarationsAfterEnd = true; + position.drop(); + } + else { + position.rollbackTo(); + break; + } + } + + if (declarationsAfterEnd) { + expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace")); + } + } + return root; + } + + PsiBuilder.Marker typeParams = null; + if (builder.getTokenType() == JavaTokenType.LT) { + typeParams = ReferenceParser.parseTypeParameters(builder); + } + + if (context == Context.FILE) { + if (typeParams == null) { + error(builder, JavaErrorMessages.message("expected.class.or.interface")); + } + else { + typeParams.precede().errorBefore(JavaErrorMessages.message("expected.class.or.interface"), typeParams); + } + declaration.drop(); + return modList; + } + + // todo: implement + throw new UnsupportedOperationException(builder.toString() + context); + } + + @NotNull + private static PsiBuilder.Marker parseModifierList(final PsiBuilder builder) { + final PsiBuilder.Marker modList = builder.mark(); + + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null) break; + if (ElementType.MODIFIER_BIT_SET.contains(tokenType)) { + builder.advanceLexer(); + } + 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)) { + break; + } + parseAnnotation(builder); + } + else { + break; + } + } + + modList.done(JavaElementType.MODIFIER_LIST); + return modList; + } + + @Nullable + public static PsiBuilder.Marker parseAnnotations(final PsiBuilder builder) { + PsiBuilder.Marker firstAnno = null; + + while (builder.getTokenType() == JavaTokenType.AT) { + final PsiBuilder.Marker anno = parseAnnotation(builder); + if (firstAnno == null) firstAnno = anno; + } + + return firstAnno; + } + + @NotNull + private static PsiBuilder.Marker parseAnnotation(final PsiBuilder builder) { + final PsiBuilder.Marker anno = builder.mark(); + builder.advanceLexer(); + + final PsiBuilder.Marker classRef = ReferenceParser.parseJavaCodeReference(builder, true, false, false); + if (classRef == null) { + error(builder, JavaErrorMessages.message("expected.class.reference")); + } + + parseAnnotationParameterList(builder); + + anno.done(JavaElementType.ANNOTATION); + return anno; + } + + @NotNull + private static PsiBuilder.Marker parseAnnotationParameterList(final PsiBuilder builder) { + PsiBuilder.Marker list = builder.mark(); + + if (!expect(builder, JavaTokenType.LPARENTH)) { + list.done(JavaElementType.ANNOTATION_PARAMETER_LIST); + return list; + } + + if (expect(builder, JavaTokenType.RPARENTH)) { + list.done(JavaElementType.ANNOTATION_PARAMETER_LIST); + return list; + } + + final boolean isFirstParamNamed = parseAnnotationParameter(builder, true); + boolean isFirstParamWarned = false; + + boolean afterBad = false; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null) { + error(builder, JavaErrorMessages.message("expected.parameter")); + break; + } + else if (expect(builder, JavaTokenType.RPARENTH)) { + break; + } + else if (tokenType == JavaTokenType.COMMA) { + final PsiBuilder.Marker errorStart = builder.mark(); + final PsiBuilder.Marker errorEnd = builder.mark(); + builder.advanceLexer(); + final boolean hasParamName = parseAnnotationParameter(builder, false); + if (!isFirstParamNamed && hasParamName && !isFirstParamWarned) { + errorStart.errorBefore(JavaErrorMessages.message("annotation.name.is.missing"), errorEnd); + isFirstParamWarned = true; + } + else { + errorStart.drop(); + } + errorEnd.drop(); + } + else if (!afterBad) { + error(builder, JavaErrorMessages.message("expected.comma.or.rparen")); + builder.advanceLexer(); + afterBad = true; + } + else { + afterBad = false; + parseAnnotationParameter(builder, false); + } + } + + list.done(JavaElementType.ANNOTATION_PARAMETER_LIST); + return list; + } + + private static boolean parseAnnotationParameter(final PsiBuilder builder, final boolean mayBeSimple) { + PsiBuilder.Marker pair = builder.mark(); + + if (mayBeSimple) { + final PsiBuilder.Marker value = parseAnnotationValue(builder); + if (value != null && builder.getTokenType() != JavaTokenType.EQ) { + pair.done(JavaElementType.NAME_VALUE_PAIR); + return false; + } + + pair.rollbackTo(); + pair = builder.mark(); + } + + final boolean hasName = expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier")); + + expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq")); + + parseAnnotationValue(builder); + + pair.done(JavaElementType.NAME_VALUE_PAIR); + + return hasName; + } + + @Nullable + private static PsiBuilder.Marker parseAnnotationValue(final PsiBuilder builder) { + final PsiBuilder.Marker result; + + final IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.AT) { + result = parseAnnotation(builder); + } + else if (tokenType == JavaTokenType.LBRACE) { + result = parseAnnotationArrayInitializer(builder); + } + else { + result = ExpressionParser.parseConditional(builder); + } + + if (result == null) { + error(builder, JavaErrorMessages.message("expected.value")); + } + return result; + } + + @NotNull + private static PsiBuilder.Marker parseAnnotationArrayInitializer(final PsiBuilder builder) { + final PsiBuilder.Marker annoArray = builder.mark(); + builder.advanceLexer(); + + if (expect(builder, JavaTokenType.RBRACE)) { + annoArray.done(JavaElementType.ANNOTATION_ARRAY_INITIALIZER); + return annoArray; + } + + parseAnnotationValue(builder); + + while (true) { + if (expect(builder, JavaTokenType.RBRACE)) { + break; + } + else if (expect(builder, JavaTokenType.COMMA)) { + parseAnnotationValue(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.rbrace")); + break; + } + } + + annoArray.done(JavaElementType.ANNOTATION_ARRAY_INITIALIZER); + return annoArray; + } +} 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 new file mode 100644 index 000000000000..b649997a7b72 --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java @@ -0,0 +1,852 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser; + +import com.intellij.codeInsight.daemon.JavaErrorMessages; +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.PsiBuilderUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.TokenType; +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.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.intellij.lang.java.parser.JavaParserUtil.areTypeAnnotationsSupported; +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 + } + + private static final TokenSet ASSIGNMENT_OPS = TokenSet.create( + JavaTokenType.EQ, JavaTokenType.ASTERISKEQ, JavaTokenType.DIVEQ, JavaTokenType.PERCEQ, JavaTokenType.PLUSEQ, JavaTokenType.MINUSEQ, + JavaTokenType.LTLTEQ, JavaTokenType.GTGTEQ, JavaTokenType.GTGTGTEQ, JavaTokenType.ANDEQ, JavaTokenType.OREQ, JavaTokenType.XOREQ); + private static final TokenSet RELATIONAL_OPS = TokenSet.create(JavaTokenType.LT, JavaTokenType.GT, JavaTokenType.LE, JavaTokenType.GE); + private static final TokenSet POSTFIX_OPS = TokenSet.create(JavaTokenType.PLUSPLUS, JavaTokenType.MINUSMINUS); + private static final TokenSet PREF_ARITHMETIC_OPS = TokenSet.orSet(POSTFIX_OPS, TokenSet.create(JavaTokenType.PLUS, JavaTokenType.MINUS)); + private static final TokenSet PREFIX_OPS = TokenSet.orSet(PREF_ARITHMETIC_OPS, TokenSet.create(JavaTokenType.TILDE, JavaTokenType.EXCL)); + private static final TokenSet LITERALS = TokenSet.create( + JavaTokenType.TRUE_KEYWORD, JavaTokenType.FALSE_KEYWORD, JavaTokenType.NULL_KEYWORD, JavaTokenType.INTEGER_LITERAL, + JavaTokenType.LONG_LITERAL, JavaTokenType.FLOAT_LITERAL, JavaTokenType.DOUBLE_LITERAL, JavaTokenType.CHARACTER_LITERAL, + JavaTokenType.STRING_LITERAL); + private static final TokenSet CONDITIONAL_OR_OPS = TokenSet.create(JavaTokenType.OROR); + private static final TokenSet CONDITIONAL_AND_OPS = TokenSet.create(JavaTokenType.ANDAND); + private static final TokenSet OR_OPS = TokenSet.create(JavaTokenType.OR); + private static final TokenSet XOR_OPS = TokenSet.create(JavaTokenType.XOR); + private static final TokenSet AND_OPS = TokenSet.create(JavaTokenType.AND); + private static final TokenSet EQUALITY_OPS = TokenSet.create(JavaTokenType.EQEQ, JavaTokenType.NE); + private static final TokenSet SHIFT_OPS = TokenSet.create(JavaTokenType.LTLT, JavaTokenType.GTGT, JavaTokenType.GTGTGT); + private static final TokenSet ADDITIVE_OPS = TokenSet.create(JavaTokenType.PLUS, JavaTokenType.MINUS); + private static final TokenSet MULTIPLICATIVE_OPS = TokenSet.create(JavaTokenType.ASTERISK, JavaTokenType.DIV, JavaTokenType.PERC); + private static final TokenSet ARGS_LIST_END = TokenSet.create(JavaTokenType.RPARENTH, JavaTokenType.RBRACE, JavaTokenType.RBRACKET); + private static final TokenSet ARGS_LIST_CONTINUE = TokenSet.create( + JavaTokenType.IDENTIFIER, TokenType.BAD_CHARACTER, JavaTokenType.COMMA, JavaTokenType.INTEGER_LITERAL, JavaTokenType.STRING_LITERAL); + + private ExpressionParser() { } + + @Nullable + public static PsiBuilder.Marker parse(final PsiBuilder builder) { + return parseAssignment(builder); + } + + @Nullable + private static PsiBuilder.Marker parseAssignment(final PsiBuilder builder) { + final PsiBuilder.Marker left = parseConditional(builder); + if (left == null) return null; + + final IElementType tokenType = getGtTokenType(builder); + if (ASSIGNMENT_OPS.contains(tokenType)) { + final PsiBuilder.Marker assignment = left.precede(); + advanceGtToken(builder, tokenType); + + final PsiBuilder.Marker right = parse(builder); + if (right == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + } + + assignment.done(JavaElementType.ASSIGNMENT_EXPRESSION); + return assignment; + } + + return left; + } + + @Nullable + public static PsiBuilder.Marker parseConditional(final PsiBuilder builder) { + final PsiBuilder.Marker condition = parseExpression(builder, ExprType.CONDITIONAL_OR); + if (condition == null) return null; + + if (builder.getTokenType() != JavaTokenType.QUEST) return condition; + final PsiBuilder.Marker ternary = condition.precede(); + builder.advanceLexer(); + + final PsiBuilder.Marker truePart = parse(builder); + if (truePart == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + ternary.done(JavaElementType.CONDITIONAL_EXPRESSION); + return ternary; + } + + if (builder.getTokenType() != JavaTokenType.COLON) { + error(builder, JavaErrorMessages.message("expected.colon")); + ternary.done(JavaElementType.CONDITIONAL_EXPRESSION); + return ternary; + } + builder.advanceLexer(); + + final PsiBuilder.Marker falsePart = parseConditional(builder); + if (falsePart == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + ternary.done(JavaElementType.CONDITIONAL_EXPRESSION); + return ternary; + } + + ternary.done(JavaElementType.CONDITIONAL_EXPRESSION); + return ternary; + } + + @Nullable + private static PsiBuilder.Marker parseExpression(final PsiBuilder builder, final ExprType type) { + switch (type) { + case CONDITIONAL_OR: + return parseBinary(builder, ExprType.CONDITIONAL_AND, CONDITIONAL_OR_OPS); + + case CONDITIONAL_AND: + return parseBinary(builder, ExprType.OR, CONDITIONAL_AND_OPS); + + case OR: + return parseBinary(builder, ExprType.XOR, OR_OPS); + + case XOR: + return parseBinary(builder, ExprType.AND, XOR_OPS); + + case AND: + return parseBinary(builder, ExprType.EQUALITY, AND_OPS); + + case EQUALITY: + return parseBinary(builder, ExprType.RELATIONAL, EQUALITY_OPS); + + case RELATIONAL: + return parseRelational(builder); + + case SHIFT: + return parseBinary(builder, ExprType.ADDITIVE, SHIFT_OPS); + + case ADDITIVE: + return parseBinary(builder, ExprType.MULTIPLICATIVE, ADDITIVE_OPS); + + case MULTIPLICATIVE: + return parseBinary(builder, ExprType.UNARY, MULTIPLICATIVE_OPS); + + case UNARY: + return parseUnary(builder); + + case TYPE: + final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder); + return typeInfo != null ? typeInfo.marker : null; + + default: + LOG.error("Unexpected type: " + type); + return null; + } + } + + @Nullable + private static PsiBuilder.Marker parseBinary(final PsiBuilder builder, final ExprType type, final TokenSet ops) { + PsiBuilder.Marker left = parseExpression(builder, type); + if (left == null) return null; + + while (true) { + final IElementType tokenType = getGtTokenType(builder); + if (tokenType == null || !ops.contains(tokenType)) break; + + final PsiBuilder.Marker binary = left.precede(); + advanceGtToken(builder, tokenType); + + final PsiBuilder.Marker right = parseExpression(builder, type); + if (right == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + binary.done(JavaElementType.BINARY_EXPRESSION); + return binary; + } + + binary.done(JavaElementType.BINARY_EXPRESSION); + left = binary; + } + + return left; + } + + @Nullable + private static PsiBuilder.Marker parseRelational(final PsiBuilder builder) { + PsiBuilder.Marker left = parseExpression(builder, ExprType.SHIFT); + if (left == null) return null; + + while (true) { + final IElementType toCreate; + final ExprType toParse; + final IElementType tokenType = getGtTokenType(builder); + if (RELATIONAL_OPS.contains(tokenType)) { + toCreate = JavaElementType.BINARY_EXPRESSION; + toParse = ExprType.SHIFT; + } + else if (tokenType == JavaTokenType.INSTANCEOF_KEYWORD) { + toCreate = JavaElementType.INSTANCE_OF_EXPRESSION; + toParse = ExprType.TYPE; + } + else { + break; + } + + final PsiBuilder.Marker expression = left.precede(); + builder.advanceLexer(); + + final PsiBuilder.Marker right = parseExpression(builder, toParse); + if (right == null) { + error(builder, toParse == ExprType.TYPE ? + JavaErrorMessages.message("expected.type") : JavaErrorMessages.message("expected.expression")); + expression.done(toCreate); + return expression; + } + + expression.done(toCreate); + left = expression; + } + + return left; + } + + @Nullable + private static PsiBuilder.Marker parseUnary(final PsiBuilder builder) { + final IElementType tokenType = builder.getTokenType(); + + if (PREFIX_OPS.contains(tokenType)) { + final PsiBuilder.Marker unary = builder.mark(); + builder.advanceLexer(); + + final PsiBuilder.Marker operand = parseUnary(builder); + if (operand == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + } + + unary.done(JavaElementType.PREFIX_EXPRESSION); + return unary; + } + else if (tokenType == JavaTokenType.LPARENTH) { + final PsiBuilder.Marker typeCast = builder.mark(); + builder.advanceLexer(); + + final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder); + + if (typeInfo == null || builder.getTokenType() != JavaTokenType.RPARENTH) { + typeCast.rollbackTo(); + return parsePostfix(builder); + } + builder.advanceLexer(); + + if (PREF_ARITHMETIC_OPS.contains(builder.getTokenType())) { + if (!typeInfo.isPrimitive) { + typeCast.rollbackTo(); + return parsePostfix(builder); + } + } + + final PsiBuilder.Marker expr = parseUnary(builder); + if (expr == null) { + if (!typeInfo.isParameterized) { + typeCast.rollbackTo(); + return parsePostfix(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.expression")); + } + } + + typeCast.done(JavaElementType.TYPE_CAST_EXPRESSION); + return typeCast; + } + else { + return parsePostfix(builder); + } + } + + @Nullable + private static PsiBuilder.Marker parsePostfix(final PsiBuilder builder) { + PsiBuilder.Marker operand = parsePrimary(builder, false); + if (operand == null) return null; + + while (POSTFIX_OPS.contains(builder.getTokenType())) { + final PsiBuilder.Marker postfix = operand.precede(); + builder.advanceLexer(); + postfix.done(JavaElementType.POSTFIX_EXPRESSION); + operand = postfix; + } + + return operand; + } + + @Nullable + private static PsiBuilder.Marker parsePrimary(final PsiBuilder builder, final boolean planB) { + PsiBuilder.Marker startMarker = builder.mark(); + + final Pair exprTypePair = parsePrimaryExpressionStart(builder); + if (exprTypePair == null) { + startMarker.drop(); + return null; + } + + PsiBuilder.Marker expr = exprTypePair.first; + IElementType exprType = exprTypePair.second; + + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.DOT) { + final PsiBuilder.Marker dotPos = builder.mark(); + builder.advanceLexer(); + + final IElementType dotTokenType = builder.getTokenType(); + if (dotTokenType == JavaTokenType.CLASS_KEYWORD && exprType == JavaElementType.REFERENCE_EXPRESSION) { + if (planB) { + error(builder, JavaErrorMessages.message("expected.identifier")); + PsiBuilderUtil.drop(startMarker, dotPos); + return expr; + } + + final PsiBuilder.Marker copy = startMarker.precede(); + startMarker.rollbackTo(); + + final PsiBuilder.Marker classObjAccess = parseClassObjectAccess(builder); + if (classObjAccess == null) { + copy.rollbackTo(); + return parsePrimary(builder, true); + } + + startMarker = copy; + expr = classObjAccess; + exprType = JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION; + } + else if (dotTokenType == JavaTokenType.NEW_KEYWORD) { + dotPos.drop(); + expr = parseNew(builder, expr); + exprType = JavaElementType.NEW_EXPRESSION; + } + else if ((dotTokenType == JavaTokenType.THIS_KEYWORD || dotTokenType == JavaTokenType.SUPER_KEYWORD) && + exprType == JavaElementType.REFERENCE_EXPRESSION) { + if (planB) { + dotPos.rollbackTo(); + startMarker.drop(); + return expr; + } + + final PsiBuilder.Marker copy = startMarker.precede(); + startMarker.rollbackTo(); + + final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, false, true, false); + if (ref == null || builder.getTokenType() != JavaTokenType.DOT) { + copy.rollbackTo(); + return parsePrimary(builder, true); + } + builder.advanceLexer(); + + if (builder.getTokenType() != dotTokenType) { + copy.rollbackTo(); + return parsePrimary(builder, true); + } + builder.advanceLexer(); + + startMarker = copy; + exprType = dotTokenType == JavaTokenType.THIS_KEYWORD ? JavaElementType.THIS_EXPRESSION : JavaElementType.SUPER_EXPRESSION; + expr = ref.precede(); + expr.done(exprType); + } + else if (dotTokenType == JavaTokenType.SUPER_KEYWORD) { + dotPos.drop(); + final PsiBuilder.Marker refExpr = expr.precede(); + builder.advanceLexer(); + refExpr.done(exprType = JavaElementType.REFERENCE_EXPRESSION); + expr = refExpr; + } + else { + dotPos.drop(); + final PsiBuilder.Marker refExpr = expr.precede(); + ReferenceParser.parseReferenceParameterList(builder, false); + + if (!JavaParserUtil.expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier"))) { + refExpr.done(JavaElementType.REFERENCE_EXPRESSION); + startMarker.drop(); + return refExpr; + } + + refExpr.done(exprType = JavaElementType.REFERENCE_EXPRESSION); + expr = refExpr; + } + } + else if (tokenType == JavaTokenType.LPARENTH) { + if (exprType != JavaElementType.REFERENCE_EXPRESSION) { + if (exprType == JavaElementType.SUPER_EXPRESSION) { + if (planB) { + startMarker.drop(); + return expr; + } + + final PsiBuilder.Marker copy = startMarker.precede(); + startMarker.rollbackTo(); + + final Pair qualifier = parsePrimaryExpressionStart(builder); + if (qualifier != null) { + final PsiBuilder.Marker refExpr = qualifier.first.precede(); + if (builder.getTokenType() == JavaTokenType.DOT) { + builder.advanceLexer(); + if (builder.getTokenType() == JavaTokenType.SUPER_KEYWORD) { + builder.advanceLexer(); + refExpr.done(exprType = JavaElementType.REFERENCE_EXPRESSION); + expr = refExpr; + startMarker = copy; + continue; + } + } + } + + copy.rollbackTo(); + return parsePrimary(builder, true); + } + else { + startMarker.drop(); + return expr; + } + } + + final PsiBuilder.Marker callExpr = expr.precede(); + parseArgumentList(builder); + callExpr.done(exprType = JavaElementType.METHOD_CALL_EXPRESSION); + expr = callExpr; + } + else if (tokenType == JavaTokenType.LBRACKET) { + if (planB) { + startMarker.drop(); + return expr; + } + + builder.advanceLexer(); + + if (builder.getTokenType() == JavaTokenType.RBRACKET && exprType == JavaElementType.REFERENCE_EXPRESSION) { + final PsiBuilder.Marker copy = startMarker.precede(); + startMarker.rollbackTo(); + + final PsiBuilder.Marker classObjAccess = parseClassObjectAccess(builder); + if (classObjAccess == null) { + copy.rollbackTo(); + return parsePrimary(builder, true); + } + + startMarker = copy; + expr = classObjAccess; + exprType = JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION; + } + else { + final PsiBuilder.Marker arrayAccess = expr.precede(); + + final PsiBuilder.Marker index = parse(builder); + if (index == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION); + startMarker.drop(); + return arrayAccess; + } + + if (builder.getTokenType() != JavaTokenType.RBRACKET) { + error(builder, JavaErrorMessages.message("expected.rbracket")); + arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION); + startMarker.drop(); + return arrayAccess; + } + builder.advanceLexer(); + + arrayAccess.done(exprType = JavaElementType.ARRAY_ACCESS_EXPRESSION); + expr = arrayAccess; + } + } + else { + startMarker.drop(); + return expr; + } + } + } + + @Nullable + private static Pair parsePrimaryExpressionStart(final PsiBuilder builder) { + IElementType tokenType = builder.getTokenType(); + + if (LITERALS.contains(tokenType)) { + final PsiBuilder.Marker literal = builder.mark(); + builder.advanceLexer(); + literal.done(JavaElementType.LITERAL_EXPRESSION); + return Pair.create(literal, JavaElementType.LITERAL_EXPRESSION); + } + if (tokenType == JavaTokenType.LPARENTH) { + final PsiBuilder.Marker parenth = builder.mark(); + builder.advanceLexer(); + + final PsiBuilder.Marker inner = parse(builder); + if (inner == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + } + + JavaParserUtil.expectOrError(builder, JavaTokenType.RPARENTH, JavaErrorMessages.message("expected.rparen")); + + parenth.done(JavaElementType.PARENTH_EXPRESSION); + return Pair.create(parenth, JavaElementType.PARENTH_EXPRESSION); + } + if (tokenType == JavaTokenType.LBRACE) { + final PsiBuilder.Marker arrayInit = parseArrayInitializer(builder); + return arrayInit != null ? Pair.create(arrayInit, JavaElementType.ARRAY_INITIALIZER_EXPRESSION) : null; + } + + PsiBuilder.Marker annotation = null; + final PsiBuilder.Marker beforeAnnotation = builder.mark(); + if (tokenType == JavaTokenType.AT) { + annotation = DeclarationParser.parseAnnotations(builder); + tokenType = builder.getTokenType(); + } + + if (tokenType == JavaTokenType.IDENTIFIER) { + final PsiBuilder.Marker refExpr; + if (annotation != null) { + final PsiBuilder.Marker refParam = annotation.precede(); + refParam.doneBefore(JavaElementType.REFERENCE_PARAMETER_LIST, annotation); + refExpr = refParam.precede(); + } + else { + refExpr = builder.mark(); + builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); + } + + builder.advanceLexer(); + refExpr.done(JavaElementType.REFERENCE_EXPRESSION); + beforeAnnotation.drop(); + return Pair.create(refExpr, JavaElementType.REFERENCE_EXPRESSION); + } + + if (annotation != null) { + beforeAnnotation.rollbackTo(); + tokenType = builder.getTokenType(); + } + else { + beforeAnnotation.drop(); + } + + if (tokenType == JavaTokenType.THIS_KEYWORD) { + final PsiBuilder.Marker expr = builder.mark(); + builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); + builder.advanceLexer(); + final IElementType type = builder.getTokenType() != JavaTokenType.LPARENTH ? + JavaElementType.THIS_EXPRESSION : JavaElementType.REFERENCE_EXPRESSION; + expr.done(type); + return Pair.create(expr, type); + } + if (tokenType == JavaTokenType.SUPER_KEYWORD) { + final PsiBuilder.Marker expr = builder.mark(); + builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); + builder.advanceLexer(); + final IElementType type = builder.getTokenType() != JavaTokenType.LPARENTH ? + JavaElementType.SUPER_EXPRESSION : JavaElementType.REFERENCE_EXPRESSION; + expr.done(type); + return Pair.create(expr, type); + } + if (tokenType == JavaTokenType.NEW_KEYWORD) { + final PsiBuilder.Marker newExpr = parseNew(builder, null); + return Pair.create(newExpr, JavaElementType.NEW_EXPRESSION); + } + if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) { + final PsiBuilder.Marker classObjAccess = parseClassObjectAccess(builder); + return classObjAccess != null ? Pair.create(classObjAccess, JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION) : null; + } + + return null; + } + + @Nullable + private static PsiBuilder.Marker parseArrayInitializer(final PsiBuilder builder) { + if (builder.getTokenType() != JavaTokenType.LBRACE) return null; + + final PsiBuilder.Marker arrayInit = builder.mark(); + builder.advanceLexer(); + + boolean expressionMissed = false; + PsiBuilder.Marker lastComma = null; + while (true) { + if (builder.getTokenType() == JavaTokenType.RBRACE) { + builder.advanceLexer(); + break; + } + + if (builder.getTokenType() == null) { + error(builder, JavaErrorMessages.message("expected.rbrace")); + break; + } + + if (expressionMissed && lastComma != null) { + // before comma must be an expression + lastComma.precede().errorBefore(JavaErrorMessages.message("expected.expression"), lastComma); + lastComma.drop(); + lastComma = null; + } + + final PsiBuilder.Marker arg = parse(builder); + if (arg == null) { + if (builder.getTokenType() == JavaTokenType.COMMA) { + expressionMissed = true; + lastComma = builder.mark(); + } + else { + error(builder, JavaErrorMessages.message("expected.rbrace")); + break; + } + } + + final IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.COMMA) { + builder.advanceLexer(); + } + else if (tokenType != JavaTokenType.RBRACE) { + error(builder, JavaErrorMessages.message("expected.comma")); + } + } + + if (lastComma != null) { + lastComma.drop(); + } + + arrayInit.done(JavaElementType.ARRAY_INITIALIZER_EXPRESSION); + return arrayInit; + } + + @NotNull + private static PsiBuilder.Marker parseNew(final PsiBuilder builder, final PsiBuilder.Marker start) { + final PsiBuilder.Marker newExpr = (start != null ? start.precede() : builder.mark()); + builder.advanceLexer(); + + ReferenceParser.parseReferenceParameterList(builder, false); + + final PsiBuilder.Marker refOrType; + final boolean parseAnnotations = areTypeAnnotationsSupported(builder) && builder.getTokenType() == JavaTokenType.AT; + + final IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.IDENTIFIER || parseAnnotations) { + refOrType = ReferenceParser.parseJavaCodeReference(builder, true, true, parseAnnotations); + if (refOrType == null) { + error(builder, JavaErrorMessages.message("expected.identifier")); + newExpr.done(JavaElementType.NEW_EXPRESSION); + return newExpr; + } + } + else if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) { + refOrType = null; + builder.advanceLexer(); + } + else { + error(builder, JavaErrorMessages.message("expected.identifier")); + newExpr.done(JavaElementType.NEW_EXPRESSION); + return newExpr; + } + + if (refOrType != null && builder.getTokenType() == JavaTokenType.LPARENTH) { + parseArgumentList(builder); + if (builder.getTokenType() == JavaTokenType.LBRACE) { + final PsiBuilder.Marker classElement = refOrType.precede(); + DeclarationParser.parseClassBodyWithBraces(builder, false, false); + classElement.done(JavaElementType.ANONYMOUS_CLASS); + } + } + else { + if (builder.getTokenType() != JavaTokenType.LBRACKET) { + error(builder, refOrType == null ? + JavaErrorMessages.message("expected.lbracket") : JavaErrorMessages.message("expected.lparen.or.lbracket")); + newExpr.done(JavaElementType.NEW_EXPRESSION); + return newExpr; + } + + int bracketCount = 0; + int dimCount = 0; + while (true) { + if (builder.getTokenType() != JavaTokenType.LBRACKET) break; + builder.advanceLexer(); + + if (bracketCount == dimCount) { + final PsiBuilder.Marker dimExpr = parse(builder); + if (dimExpr != null) { + dimCount++; + } + } + bracketCount++; + + if (!JavaParserUtil.expectOrError(builder, JavaTokenType.RBRACKET, JavaErrorMessages.message("expected.rbracket"))) { + newExpr.done(JavaElementType.NEW_EXPRESSION); + return newExpr; + } + } + + if (dimCount == 0) { + if (builder.getTokenType() == JavaTokenType.LBRACE) { + parseArrayInitializer(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.array.initializer")); + } + } + } + + newExpr.done(JavaElementType.NEW_EXPRESSION); + return newExpr; + } + + @Nullable + private static PsiBuilder.Marker parseClassObjectAccess(final PsiBuilder builder) { + final PsiBuilder.Marker expr = builder.mark(); + + final PsiBuilder.Marker type = ReferenceParser.parseType(builder, false, false); + if (type == null) { + expr.drop(); + return null; + } + + if (builder.getTokenType() != JavaTokenType.DOT) { + expr.rollbackTo(); + return null; + } + builder.advanceLexer(); + + if (builder.getTokenType() != JavaTokenType.CLASS_KEYWORD) { + expr.rollbackTo(); + return null; + } + builder.advanceLexer(); + + expr.done(JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION); + return expr; + } + + @NotNull + public static PsiBuilder.Marker parseArgumentList(final PsiBuilder builder) { + final PsiBuilder.Marker list = builder.mark(); + builder.advanceLexer(); + + boolean first = true; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (first && (ARGS_LIST_END.contains(tokenType) || builder.eof())) break; + if (!first && !ARGS_LIST_CONTINUE.contains(tokenType)) break; + + boolean hasError = false; + if (!first) { + if (builder.getTokenType() == JavaTokenType.COMMA) { + builder.advanceLexer(); + } + else { + hasError = true; + error(builder, JavaErrorMessages.message("expected.comma.or.rparen")); + emptyExpression(builder); + } + } + first = false; + + final PsiBuilder.Marker arg = parse(builder); + if (arg == null) { + if (!hasError) { + error(builder, JavaErrorMessages.message("expected.expression")); + emptyExpression(builder); + } + if (!ARGS_LIST_CONTINUE.contains(builder.getTokenType())) break; + if (builder.getTokenType() != JavaTokenType.COMMA && !builder.eof()) { + builder.advanceLexer(); + } + } + } + + JavaParserUtil.expectOrError(builder, JavaTokenType.RPARENTH, JavaErrorMessages.message("expected.rparen")); + + list.done(JavaElementType.EXPRESSION_LIST); + return list; + } + + private static void emptyExpression(final PsiBuilder builder) { + builder.mark().done(JavaElementType.EMPTY_EXPRESSION); + } + + @Nullable + private static IElementType getGtTokenType(final PsiBuilder builder) { + final PsiBuilder.Marker sp = builder.mark(); + + IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.GT) { + builder.advanceLexer(); + if (builder.getTokenType() == JavaTokenType.GT) { + builder.advanceLexer(); + if (builder.getTokenType() == JavaTokenType.GT) { + builder.advanceLexer(); + if (builder.getTokenType() == JavaTokenType.EQ) { + tokenType = JavaTokenType.GTGTGTEQ; + } + else { + tokenType = JavaTokenType.GTGTGT; + } + } + else if (builder.getTokenType() == JavaTokenType.EQ) { + tokenType = JavaTokenType.GTGTEQ; + } + else { + tokenType = JavaTokenType.GTGT; + } + } + } + + sp.rollbackTo(); + return tokenType; + } + + private static void advanceGtToken(final PsiBuilder builder, final IElementType type) { + final PsiBuilder.Marker gtToken = builder.mark(); + + if (type == JavaTokenType.GTGTGTEQ) { + PsiBuilderUtil.advance(builder, 4); + } + else if (type == JavaTokenType.GTGTGT) { + PsiBuilderUtil.advance(builder, 3); + } + else if (type == JavaTokenType.GTGTEQ) { + PsiBuilderUtil.advance(builder, 3); + } + else if (type == JavaTokenType.GTGT) { + PsiBuilderUtil.advance(builder, 2); + } + else { + gtToken.drop(); + builder.advanceLexer(); + return; + } + + gtToken.collapse(type); + } +} diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java new file mode 100644 index 000000000000..b06bf223d085 --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.PsiParser; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.lang.java.parser.JavaParserUtil.setLanguageLevel; + + +public class JavaParser implements PsiParser { + private final LanguageLevel myLanguageLevel; + + public JavaParser(final LanguageLevel languageLevel) { + myLanguageLevel = languageLevel; + } + + @NotNull + public ASTNode parse(final IElementType rootType, final PsiBuilder builder) { + final PsiBuilder.Marker root = builder.mark(); + setLanguageLevel(builder, myLanguageLevel); + + // parse + + root.done(rootType); + return builder.getTreeBuilt(); + } +} 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 new file mode 100644 index 000000000000..73937f311f81 --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.PsiBuilderUtil; +import com.intellij.openapi.util.Key; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; + + +public class JavaParserUtil { + private static final Key LANG_LEVEL_KEY = Key.create("JavaParserUtil.LanguageLevel"); + + private JavaParserUtil() { } + + public static void setLanguageLevel(final PsiBuilder builder, final LanguageLevel level) { + builder.putUserData(LANG_LEVEL_KEY, level); + } + + public static boolean areTypeAnnotationsSupported(final PsiBuilder builder) { + final LanguageLevel level = getLanguageLevel(builder); + return level.isAtLeast(LanguageLevel.JDK_1_7); + } + + @NotNull + private static LanguageLevel getLanguageLevel(final PsiBuilder builder) { + final LanguageLevel level = builder.getUserData(LANG_LEVEL_KEY); + assert level != null; + return level; + } + + // used instead of PsiBuilder.error() as it drops all but first subsequent error messages + public static void error(final PsiBuilder builder, final String message) { + builder.mark().error(message); + } + + public static boolean expectOrError(final PsiBuilder builder, final IElementType expectedType, final String errorMessage) { + if (!PsiBuilderUtil.expect(builder, expectedType)) { + error(builder, errorMessage); + return false; + } + return true; + } + + public static void emptyElement(final PsiBuilder builder, final IElementType type) { + builder.mark().done(type); + } +} 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 new file mode 100644 index 000000000000..8831468fabe3 --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -0,0 +1,294 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser; + +import com.intellij.codeInsight.daemon.JavaErrorMessages; +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.psi.tree.TokenSet; +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.*; + + +public class ReferenceParser { + public static class TypeInfo { + public boolean isPrimitive = false; + public boolean isParameterized = false; + public boolean isArray = false; + public PsiBuilder.Marker marker = null; + } + + private static final TokenSet WILDCARD_KEYWORD_SET = TokenSet.create(JavaTokenType.EXTENDS_KEYWORD, JavaTokenType.SUPER_KEYWORD); + + private ReferenceParser() { } + + @Nullable + public static TypeInfo parseType(final PsiBuilder builder) { + return parseTypeWithInfo(builder, true, true); + } + + @Nullable + public static PsiBuilder.Marker parseType(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) { + final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard); + return typeInfo != null ? typeInfo.marker : null; + } + + @Nullable + private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) { + if (builder.getTokenType() == null) return null; + + final TypeInfo typeInfo = new TypeInfo(); + + final boolean annotationsSupported = areTypeAnnotationsSupported(builder); + PsiBuilder.Marker type = builder.mark(); + if (annotationsSupported) { + DeclarationParser.parseAnnotations(builder); + } + + final IElementType tokenType = builder.getTokenType(); + if (expect(builder, ElementType.PRIMITIVE_TYPE_BIT_SET)) { + typeInfo.isPrimitive = true; + } + else if (tokenType == JavaTokenType.IDENTIFIER) { + parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, typeInfo); + } + else if (wildcard && tokenType == JavaTokenType.QUEST) { + type.drop(); + typeInfo.marker = parseWildcardType(builder); + return typeInfo.marker != null ? typeInfo : null; + } + else { + type.drop(); + return null; + } + + while (true) { + if (annotationsSupported) { + DeclarationParser.parseAnnotations(builder); + } + type.done(JavaElementType.TYPE); + + if (!expect(builder, JavaTokenType.LBRACKET)) { + break; + } + typeInfo.isArray = true; + if (!expectOrError(builder, JavaTokenType.RBRACKET, JavaErrorMessages.message("expected.rbracket"))) { + break; + } + + type = type.precede(); + } + + typeInfo.marker = type; + return typeInfo; + } + + @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); + if (boundType == null) { + error(builder, JavaErrorMessages.message("expected.type")); + } + } + + type.done(JavaElementType.TYPE); + return type; + } + + @Nullable + public static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot, + final boolean parameterList, final boolean annotations) { + return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, new TypeInfo()); + } + + @Nullable + private static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot, + final boolean parameterList, final boolean annotations, + final TypeInfo typeInfo) { + PsiBuilder.Marker refElement = builder.mark(); + + if (annotations) { + DeclarationParser.parseAnnotations(builder); + } + + if (!expect(builder, JavaTokenType.IDENTIFIER)) { + refElement.rollbackTo(); + return null; + } + + if (parameterList) { + typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT); + parseReferenceParameterList(builder, true); + } + else { + emptyElement(builder, JavaElementType.REFERENCE_PARAMETER_LIST); + } + + boolean hasIdentifier; + while (builder.getTokenType() == JavaTokenType.DOT) { + refElement.done(JavaElementType.JAVA_CODE_REFERENCE); + + final PsiBuilder.Marker dotPos = builder.mark(); + builder.advanceLexer(); + + if (expect(builder, JavaTokenType.IDENTIFIER)) { + hasIdentifier = true; + } + else { + if (!eatLastDot) { + dotPos.rollbackTo(); + return refElement; + } + hasIdentifier = false; + } + dotPos.drop(); + + refElement = refElement.precede(); + + if (!hasIdentifier) { + error(builder, JavaErrorMessages.message("expected.identifier")); + break; + } + + if (parameterList) { + typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT); + parseReferenceParameterList(builder, true); + } + else { + emptyElement(builder, JavaElementType.REFERENCE_PARAMETER_LIST); + } + } + + refElement.done(JavaElementType.JAVA_CODE_REFERENCE); + return refElement; + } + + @NotNull + public static PsiBuilder.Marker parseReferenceParameterList(final PsiBuilder builder, final boolean wildcard) { + final PsiBuilder.Marker list = builder.mark(); + if (!expect(builder, JavaTokenType.LT)) { + list.done(JavaElementType.REFERENCE_PARAMETER_LIST); + return list; + } + + while (true) { + final PsiBuilder.Marker type = parseType(builder, true, wildcard); + if (type == null) { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + + if (expect(builder, JavaTokenType.GT)) { + break; + } + else if (!expectOrError(builder, JavaTokenType.COMMA, JavaErrorMessages.message("expected.gt.or.comma"))) { + break; + } + } + + list.done(JavaElementType.REFERENCE_PARAMETER_LIST); + return list; + } + + @NotNull + public static PsiBuilder.Marker parseTypeParameters(final PsiBuilder builder) { + final PsiBuilder.Marker list = builder.mark(); + if (!expect(builder, JavaTokenType.LT)) { + list.done(JavaElementType.TYPE_PARAMETER_LIST); + return list; + } + + while (true) { + final PsiBuilder.Marker param = parseTypeParameter(builder); + if (param == null) { + error(builder, JavaErrorMessages.message("expected.type.parameter")); + } + if (!expect(builder, JavaTokenType.COMMA)) { + break; + } + } + + if (!expect(builder, JavaTokenType.GT)) { + // hack for completion + if (builder.getTokenType() == JavaTokenType.IDENTIFIER) { + if (nextTokenType(builder) == JavaTokenType.GT) { + final PsiBuilder.Marker errorElement = builder.mark(); + builder.advanceLexer(); + errorElement.error(JavaErrorMessages.message("unexpected.identifier")); + builder.advanceLexer(); + } + else { + error(builder, JavaErrorMessages.message("expected.gt")); + } + } + else { + error(builder, JavaErrorMessages.message("expected.gt")); + } + } + + list.done(JavaElementType.TYPE_PARAMETER_LIST); + return list; + } + + @Nullable + private static PsiBuilder.Marker parseTypeParameter(final PsiBuilder builder) { + final PsiBuilder.Marker param = builder.mark(); + + DeclarationParser.parseAnnotations(builder); + if (!expect(builder, JavaTokenType.IDENTIFIER)) { + param.rollbackTo(); + return null; + } + + if (expect(builder, JavaTokenType.EXTENDS_KEYWORD)) { + parseReferenceList(builder, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND); + } + else { + emptyElement(builder, JavaElementType.EXTENDS_BOUND_LIST); + } + + param.done(JavaElementType.TYPE_PARAMETER); + return param; + } + + @NotNull + private static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, 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; + } + } + + element.done(type); + return element; + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaClassReferenceListElementType.java b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaClassReferenceListElementType.java index c349bef30c79..058f529610ff 100644 --- a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaClassReferenceListElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaClassReferenceListElementType.java @@ -42,7 +42,7 @@ import java.io.IOException; public class JavaClassReferenceListElementType extends JavaStubElementType { public JavaClassReferenceListElementType(@NotNull @NonNls String id) { - super(id); + super(id, true); } public PsiReferenceList createPsi(final PsiClassReferenceListStub stub) { diff --git a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaStubElementType.java b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaStubElementType.java index 9bcab4f8d55b..bcf07816f068 100644 --- a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaStubElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaStubElementType.java @@ -29,8 +29,15 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public abstract class JavaStubElementType extends IStubElementType { + private final boolean myLeftBound; + protected JavaStubElementType(@NotNull @NonNls final String debugName) { + this(debugName, false); + } + + protected JavaStubElementType(@NotNull @NonNls final String debugName, final boolean leftBound) { super(debugName, StdFileTypes.JAVA != null ? StdFileTypes.JAVA.getLanguage() : null); + myLeftBound = leftBound; } public String getExternalId() { @@ -47,4 +54,9 @@ public abstract class JavaStubElementType - + diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Array.txt b/java/java-tests/testData/psi/parser-partial/annotations/Array.txt new file mode 100644 index 000000000000..55252134c2fc --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Array.txt @@ -0,0 +1,20 @@ +PsiJavaFile:Array.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Endorsers + PsiIdentifier:Endorsers('Endorsers') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiArrayInitializerMemberValue:{"Children", "Unscrupulous dentists"} + PsiJavaToken:LBRACE('{') + PsiLiteralExpression:"Children" + PsiJavaToken:STRING_LITERAL('"Children"') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiLiteralExpression:"Unscrupulous dentists" + PsiJavaToken:STRING_LITERAL('"Unscrupulous dentists"') + PsiJavaToken:RBRACE('}') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Complex.txt b/java/java-tests/testData/psi/parser-partial/annotations/Complex.txt new file mode 100644 index 000000000000..5211c0a10ec1 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Complex.txt @@ -0,0 +1,22 @@ +PsiJavaFile:Complex.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Author + PsiIdentifier:Author('Author') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiIdentifier:first('first') + PsiJavaToken:EQ('=') + PsiLiteralExpression:"Eugene" + PsiJavaToken:STRING_LITERAL('"Eugene"') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiNameValuePair + PsiIdentifier:second('second') + PsiJavaToken:EQ('=') + PsiLiteralExpression:"Wampirchik" + PsiJavaToken:STRING_LITERAL('"Wampirchik"') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/annotations/FirstNameMissed.txt b/java/java-tests/testData/psi/parser-partial/annotations/FirstNameMissed.txt new file mode 100644 index 000000000000..711c2fa63385 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/FirstNameMissed.txt @@ -0,0 +1,26 @@ +PsiJavaFile:FirstNameMissed.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Anno + PsiIdentifier:Anno('Anno') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiReferenceExpression:value1 + PsiReferenceParameterList + + PsiIdentifier:value1('value1') + PsiErrorElement:Annotation attribute must be of the form 'name=value' + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiNameValuePair + PsiIdentifier:param2('param2') + PsiJavaToken:EQ('=') + PsiReferenceExpression:value2 + PsiReferenceParameterList + + PsiIdentifier:value2('value2') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Marker.txt b/java/java-tests/testData/psi/parser-partial/annotations/Marker.txt new file mode 100644 index 000000000000..ca28bc4eb311 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Marker.txt @@ -0,0 +1,9 @@ +PsiJavaFile:Marker.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Preliminary + PsiIdentifier:Preliminary('Preliminary') + PsiReferenceParameterList + + PsiAnnotationParameterList + diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Multiple.txt b/java/java-tests/testData/psi/parser-partial/annotations/Multiple.txt new file mode 100644 index 000000000000..5ef2baf465b6 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Multiple.txt @@ -0,0 +1,26 @@ +PsiJavaFile:Multiple.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Preliminary + PsiIdentifier:Preliminary('Preliminary') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Other + PsiIdentifier:Other('Other') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiIdentifier:name('name') + PsiJavaToken:EQ('=') + PsiReferenceExpression:value + PsiReferenceParameterList + + PsiIdentifier:value('value') + PsiJavaToken:RPARENTH(')') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Nested.txt b/java/java-tests/testData/psi/parser-partial/annotations/Nested.txt new file mode 100644 index 000000000000..e8cfe4480a70 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Nested.txt @@ -0,0 +1,32 @@ +PsiJavaFile:Nested.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Author + PsiIdentifier:Author('Author') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Name + PsiIdentifier:Name('Name') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiIdentifier:first('first') + PsiJavaToken:EQ('=') + PsiLiteralExpression:"Eugene" + PsiJavaToken:STRING_LITERAL('"Eugene"') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiNameValuePair + PsiIdentifier:second('second') + PsiJavaToken:EQ('=') + PsiLiteralExpression:"Wampirchik" + PsiJavaToken:STRING_LITERAL('"Wampirchik"') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/annotations/ParameterizedAnnotation.txt b/java/java-tests/testData/psi/parser-partial/annotations/ParameterizedAnnotation.txt new file mode 100644 index 000000000000..a1843135e0fa --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/ParameterizedAnnotation.txt @@ -0,0 +1,13 @@ +PsiJavaFile:ParameterizedAnnotation.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Nullable + PsiIdentifier:Nullable('Nullable') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiErrorElement:Unparsed tokens + PsiJavaToken:LT('<') + PsiIdentifier:T('T') + PsiJavaToken:GT('>') diff --git a/java/java-tests/testData/psi/parser-partial/annotations/QualifiedAnnotation.txt b/java/java-tests/testData/psi/parser-partial/annotations/QualifiedAnnotation.txt new file mode 100644 index 000000000000..d73ddfe716ef --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/QualifiedAnnotation.txt @@ -0,0 +1,24 @@ +PsiJavaFile:QualifiedAnnotation.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:org.jetbrains.annotations.Nullable + PsiJavaCodeReferenceElement:org.jetbrains.annotations + PsiJavaCodeReferenceElement:org.jetbrains + PsiJavaCodeReferenceElement:org + PsiIdentifier:org('org') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:jetbrains('jetbrains') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:annotations('annotations') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:Nullable('Nullable') + PsiReferenceParameterList + + PsiAnnotationParameterList + diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Simple0.txt b/java/java-tests/testData/psi/parser-partial/annotations/Simple0.txt new file mode 100644 index 000000000000..486549bf98a5 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Simple0.txt @@ -0,0 +1,13 @@ +PsiJavaFile:Simple0.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Copyright + PsiIdentifier:Copyright('Copyright') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiLiteralExpression:"bla-bla-bla" + PsiJavaToken:STRING_LITERAL('"bla-bla-bla"') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/annotations/Simple1.txt b/java/java-tests/testData/psi/parser-partial/annotations/Simple1.txt new file mode 100644 index 000000000000..078d0698e0a5 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/annotations/Simple1.txt @@ -0,0 +1,15 @@ +PsiJavaFile:Simple1.java + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Copyright + PsiIdentifier:Copyright('Copyright') + PsiReferenceParameterList + + PsiAnnotationParameterList + PsiJavaToken:LPARENTH('(') + PsiNameValuePair + PsiReferenceExpression:treatedAsValue + PsiReferenceParameterList + + PsiIdentifier:treatedAsValue('treatedAsValue') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer0.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer0.txt new file mode 100644 index 000000000000..508d0daa897e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer0.txt @@ -0,0 +1,5 @@ +PsiJavaFile:ArrayInitializer0.java + PsiArrayInitializerExpression:{ } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer1.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer1.txt new file mode 100644 index 000000000000..23a7143df03d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer1.txt @@ -0,0 +1,8 @@ +PsiJavaFile:ArrayInitializer1.java + PsiArrayInitializerExpression:{ 1 } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer2.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer2.txt new file mode 100644 index 000000000000..35a40adbfcfe --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer2.txt @@ -0,0 +1,9 @@ +PsiJavaFile:ArrayInitializer2.java + PsiArrayInitializerExpression:{ 1, } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer3.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer3.txt new file mode 100644 index 000000000000..71af49d3934a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer3.txt @@ -0,0 +1,11 @@ +PsiJavaFile:ArrayInitializer3.java + PsiArrayInitializerExpression:{ 1,2 } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer4.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer4.txt new file mode 100644 index 000000000000..e8b34ebf48cc --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer4.txt @@ -0,0 +1,13 @@ +PsiJavaFile:ArrayInitializer4.java + PsiArrayInitializerExpression:{ 1 2 } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiErrorElement:',' expected + + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer5.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer5.txt new file mode 100644 index 000000000000..4613ecc1968b --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer5.txt @@ -0,0 +1,12 @@ +PsiJavaFile:ArrayInitializer5.java + PsiArrayInitializerExpression:{ { } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiArrayInitializerExpression:{ } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiErrorElement:',' expected + + PsiErrorElement:'}' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer6.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer6.txt new file mode 100644 index 000000000000..6dba1a6ae959 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer6.txt @@ -0,0 +1,7 @@ +PsiJavaFile:ArrayInitializer6.java + PsiArrayInitializerExpression:{ , } + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer7.txt b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer7.txt new file mode 100644 index 000000000000..c33132bf2ac7 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ArrayInitializer7.txt @@ -0,0 +1,16 @@ +PsiJavaFile:ArrayInitializer7.java + PsiArrayInitializerExpression:{ , , 7 } + PsiJavaToken:LBRACE('{') + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:COMMA(',') + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiLiteralExpression:7 + PsiJavaToken:INTEGER_LITERAL('7') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Assignment0.txt b/java/java-tests/testData/psi/parser-partial/expressions/Assignment0.txt new file mode 100644 index 000000000000..92a8e7022745 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Assignment0.txt @@ -0,0 +1,11 @@ +PsiJavaFile:Assignment0.java + PsiAssignmentExpression:a = 0 + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Assignment1.txt b/java/java-tests/testData/psi/parser-partial/expressions/Assignment1.txt new file mode 100644 index 000000000000..be4001ee9b29 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Assignment1.txt @@ -0,0 +1,10 @@ +PsiJavaFile:Assignment1.java + PsiAssignmentExpression:a = + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiErrorElement:Expression expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Cast.txt b/java/java-tests/testData/psi/parser-partial/expressions/Cast.txt new file mode 100644 index 000000000000..8bcbe793d8b5 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Cast.txt @@ -0,0 +1,13 @@ +PsiJavaFile:Cast.java + PsiTypeCastExpression:(Type)var + PsiJavaToken:LPARENTH('(') + PsiTypeElement:Type + PsiJavaCodeReferenceElement:Type + PsiIdentifier:Type('Type') + PsiReferenceParameterList + + PsiJavaToken:RPARENTH(')') + PsiReferenceExpression:var + PsiReferenceParameterList + + PsiIdentifier:var('var') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Cond0.txt b/java/java-tests/testData/psi/parser-partial/expressions/Cond0.txt new file mode 100644 index 000000000000..291ac315d46f --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Cond0.txt @@ -0,0 +1,16 @@ +PsiJavaFile:Cond0.java + PsiConditionalExpression:cond ? true : false + PsiReferenceExpression:cond + PsiReferenceParameterList + + PsiIdentifier:cond('cond') + PsiWhiteSpace(' ') + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiLiteralExpression:true + PsiJavaToken:TRUE_KEYWORD('true') + PsiWhiteSpace(' ') + PsiJavaToken:COLON(':') + PsiWhiteSpace(' ') + PsiLiteralExpression:false + PsiJavaToken:FALSE_KEYWORD('false') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Cond1.txt b/java/java-tests/testData/psi/parser-partial/expressions/Cond1.txt new file mode 100644 index 000000000000..544ddceb3a99 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Cond1.txt @@ -0,0 +1,10 @@ +PsiJavaFile:Cond1.java + PsiConditionalExpression:cond ? + PsiReferenceExpression:cond + PsiReferenceParameterList + + PsiIdentifier:cond('cond') + PsiWhiteSpace(' ') + PsiJavaToken:QUEST('?') + PsiErrorElement:Expression expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Cond2.txt b/java/java-tests/testData/psi/parser-partial/expressions/Cond2.txt new file mode 100644 index 000000000000..95e7e6891135 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Cond2.txt @@ -0,0 +1,13 @@ +PsiJavaFile:Cond2.java + PsiConditionalExpression:cond ? true + PsiReferenceExpression:cond + PsiReferenceParameterList + + PsiIdentifier:cond('cond') + PsiWhiteSpace(' ') + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiLiteralExpression:true + PsiJavaToken:TRUE_KEYWORD('true') + PsiErrorElement:':' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Cond3.txt b/java/java-tests/testData/psi/parser-partial/expressions/Cond3.txt new file mode 100644 index 000000000000..50f9d82cb193 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Cond3.txt @@ -0,0 +1,15 @@ +PsiJavaFile:Cond3.java + PsiConditionalExpression:cond ? true : + PsiReferenceExpression:cond + PsiReferenceParameterList + + PsiIdentifier:cond('cond') + PsiWhiteSpace(' ') + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiLiteralExpression:true + PsiJavaToken:TRUE_KEYWORD('true') + PsiWhiteSpace(' ') + PsiJavaToken:COLON(':') + PsiErrorElement:Expression expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/CondOr0.txt b/java/java-tests/testData/psi/parser-partial/expressions/CondOr0.txt new file mode 100644 index 000000000000..a2405e24d608 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/CondOr0.txt @@ -0,0 +1,21 @@ +PsiJavaFile:CondOr0.java + PsiBinaryExpression:a || b || c + PsiBinaryExpression:a || b + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiJavaToken:OROR('||') + PsiWhiteSpace(' ') + PsiReferenceExpression:b + PsiReferenceParameterList + + PsiIdentifier:b('b') + PsiWhiteSpace(' ') + PsiJavaToken:OROR('||') + PsiWhiteSpace(' ') + PsiReferenceExpression:c + PsiReferenceParameterList + + PsiIdentifier:c('c') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/CondOr1.txt b/java/java-tests/testData/psi/parser-partial/expressions/CondOr1.txt new file mode 100644 index 000000000000..fd17bd9fa03a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/CondOr1.txt @@ -0,0 +1,10 @@ +PsiJavaFile:CondOr1.java + PsiBinaryExpression:a || + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiJavaToken:OROR('||') + PsiErrorElement:Expression expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList0.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList0.txt new file mode 100644 index 000000000000..19dfe39e0c56 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList0.txt @@ -0,0 +1,14 @@ +PsiJavaFile:ExprList0.java + PsiMethodCallExpression:f(1,2) + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList1.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList1.txt new file mode 100644 index 000000000000..1b2716586119 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList1.txt @@ -0,0 +1,10 @@ +PsiJavaFile:ExprList1.java + PsiMethodCallExpression:f( + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiErrorElement:')' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList2.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList2.txt new file mode 100644 index 000000000000..ac5a13b7d835 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList2.txt @@ -0,0 +1,12 @@ +PsiJavaFile:ExprList2.java + PsiMethodCallExpression:f(1 + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiErrorElement:')' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList3.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList3.txt new file mode 100644 index 000000000000..8ab3cbda9229 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList3.txt @@ -0,0 +1,17 @@ +PsiJavaFile:ExprList3.java + PsiMethodCallExpression:f(1, + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiErrorElement:Expression expected + + PsiExpression(empty) + + PsiErrorElement:')' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList4.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList4.txt new file mode 100644 index 000000000000..0f1d533fe7ca --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList4.txt @@ -0,0 +1,16 @@ +PsiJavaFile:ExprList4.java + PsiMethodCallExpression:f(1,) + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiErrorElement:Expression expected + + PsiExpression(empty) + + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList5.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList5.txt new file mode 100644 index 000000000000..79db76b38550 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList5.txt @@ -0,0 +1,19 @@ +PsiJavaFile:ExprList5.java + PsiMethodCallExpression:f(1,,2) + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiErrorElement:Expression expected + + PsiExpression(empty) + + PsiJavaToken:COMMA(',') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ExprList6.txt b/java/java-tests/testData/psi/parser-partial/expressions/ExprList6.txt new file mode 100644 index 000000000000..4afa08249043 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ExprList6.txt @@ -0,0 +1,16 @@ +PsiJavaFile:ExprList6.java + PsiMethodCallExpression:f(,2) + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiErrorElement:Expression expected + + PsiExpression(empty) + + PsiJavaToken:COMMA(',') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/GE.txt b/java/java-tests/testData/psi/parser-partial/expressions/GE.txt new file mode 100644 index 000000000000..08e3dce501a2 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/GE.txt @@ -0,0 +1,17 @@ +PsiJavaFile:GE.java + PsiAssignmentExpression:x >>>= 8 >> 2 + PsiReferenceExpression:x + PsiReferenceParameterList + + PsiIdentifier:x('x') + PsiWhiteSpace(' ') + PsiJavaToken:GTGTGTEQ('>>>=') + PsiWhiteSpace(' ') + PsiBinaryExpression:8 >> 2 + PsiLiteralExpression:8 + PsiJavaToken:INTEGER_LITERAL('8') + PsiWhiteSpace(' ') + PsiJavaToken:GTGT('>>') + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt b/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt new file mode 100644 index 000000000000..563280a61046 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/IllegalWildcard.txt @@ -0,0 +1,24 @@ +PsiJavaFile:IllegalWildcard.java + PsiConditionalExpression:this. + PsiKeyword:this('this') + 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(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/IncompleteCast.txt b/java/java-tests/testData/psi/parser-partial/expressions/IncompleteCast.txt new file mode 100644 index 000000000000..5346de194a8e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/IncompleteCast.txt @@ -0,0 +1,26 @@ +PsiJavaFile:IncompleteCast.java + PsiMethodCallExpression:f((ArrayList) ) + PsiReferenceExpression:f + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiTypeCastExpression:(ArrayList) + PsiJavaToken:LPARENTH('(') + PsiTypeElement:ArrayList + PsiJavaCodeReferenceElement:ArrayList + PsiIdentifier:ArrayList('ArrayList') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:RPARENTH(')') + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/InstanceOf0.txt b/java/java-tests/testData/psi/parser-partial/expressions/InstanceOf0.txt new file mode 100644 index 000000000000..02bbba151d3d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/InstanceOf0.txt @@ -0,0 +1,14 @@ +PsiJavaFile:InstanceOf0.java + PsiInstanceofExpression:a instanceof String + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiKeyword:instanceof('instanceof') + PsiWhiteSpace(' ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/InstanceOf1.txt b/java/java-tests/testData/psi/parser-partial/expressions/InstanceOf1.txt new file mode 100644 index 000000000000..42ac3f17063c --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/InstanceOf1.txt @@ -0,0 +1,10 @@ +PsiJavaFile:InstanceOf1.java + PsiInstanceofExpression:a instanceof + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiKeyword:instanceof('instanceof') + PsiErrorElement:Type expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New0.txt b/java/java-tests/testData/psi/parser-partial/expressions/New0.txt new file mode 100644 index 000000000000..cef9e9cb681a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New0.txt @@ -0,0 +1,13 @@ +PsiJavaFile:New0.java + PsiNewExpression:new A() + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New1.txt b/java/java-tests/testData/psi/parser-partial/expressions/New1.txt new file mode 100644 index 000000000000..76aa9b7b6953 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New1.txt @@ -0,0 +1,16 @@ +PsiJavaFile:New1.java + PsiNewExpression:new A[1][] + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New10.txt b/java/java-tests/testData/psi/parser-partial/expressions/New10.txt new file mode 100644 index 000000000000..b7206584e9b9 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New10.txt @@ -0,0 +1,12 @@ +PsiJavaFile:New10.java + PsiNewExpression:new int + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiKeyword:int('int') + PsiErrorElement:'[' expected + + PsiErrorElement:Unparsed tokens + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New11.txt b/java/java-tests/testData/psi/parser-partial/expressions/New11.txt new file mode 100644 index 000000000000..59a4685b1156 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New11.txt @@ -0,0 +1,15 @@ +PsiJavaFile:New11.java + PsiNewExpression:new String[0 + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiErrorElement:']' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New12.txt b/java/java-tests/testData/psi/parser-partial/expressions/New12.txt new file mode 100644 index 000000000000..b0e669acdf98 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New12.txt @@ -0,0 +1,15 @@ +PsiJavaFile:New12.java + PsiNewExpression:new int[1][2] + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiKeyword:int('int') + PsiJavaToken:LBRACKET('[') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:RBRACKET(']') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New13.txt b/java/java-tests/testData/psi/parser-partial/expressions/New13.txt new file mode 100644 index 000000000000..c00cca26dbbe --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New13.txt @@ -0,0 +1,19 @@ +PsiJavaFile:New13.java + PsiNewExpression:new int[1][][ + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiKeyword:int('int') + PsiJavaToken:LBRACKET('[') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiErrorElement:']' expected + + PsiErrorElement:Unparsed tokens + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:RBRACKET(']') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New14.txt b/java/java-tests/testData/psi/parser-partial/expressions/New14.txt new file mode 100644 index 000000000000..9761d7930429 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New14.txt @@ -0,0 +1,18 @@ +PsiJavaFile:New14.java + PsiNewExpression:Q.new A() + PsiReferenceExpression:Q + PsiReferenceParameterList + + PsiIdentifier:Q('Q') + PsiJavaToken:DOT('.') + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New2.txt b/java/java-tests/testData/psi/parser-partial/expressions/New2.txt new file mode 100644 index 000000000000..f5b075df64ec --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New2.txt @@ -0,0 +1,14 @@ +PsiJavaFile:New2.java + PsiNewExpression:new A[] + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiErrorElement:Array initializer expected + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New3.txt b/java/java-tests/testData/psi/parser-partial/expressions/New3.txt new file mode 100644 index 000000000000..e545cdb78495 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New3.txt @@ -0,0 +1,18 @@ +PsiJavaFile:New3.java + PsiNewExpression:new A[][ + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiErrorElement:']' expected + + PsiErrorElement:Unparsed tokens + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:RBRACKET(']') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New4.txt b/java/java-tests/testData/psi/parser-partial/expressions/New4.txt new file mode 100644 index 000000000000..a2ff51e5f8a4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New4.txt @@ -0,0 +1,19 @@ +PsiJavaFile:New4.java + PsiNewExpression:new A[][]{null} + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiArrayInitializerExpression:{null} + PsiJavaToken:LBRACE('{') + PsiLiteralExpression:null + PsiJavaToken:NULL_KEYWORD('null') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New5.txt b/java/java-tests/testData/psi/parser-partial/expressions/New5.txt new file mode 100644 index 000000000000..3770613b5644 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New5.txt @@ -0,0 +1,18 @@ +PsiJavaFile:New5.java + PsiNewExpression:new A[1] + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:RBRACKET(']') + PsiErrorElement:Unparsed tokens + PsiJavaToken:LBRACE('{') + PsiJavaToken:NULL_KEYWORD('null') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New6.txt b/java/java-tests/testData/psi/parser-partial/expressions/New6.txt new file mode 100644 index 000000000000..d767c9089df7 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New6.txt @@ -0,0 +1,7 @@ +PsiJavaFile:New6.java + PsiNewExpression:new + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New7.txt b/java/java-tests/testData/psi/parser-partial/expressions/New7.txt new file mode 100644 index 000000000000..85e4bb39e591 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New7.txt @@ -0,0 +1,12 @@ +PsiJavaFile:New7.java + PsiNewExpression:new A + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiErrorElement:'(' or '[' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New8.txt b/java/java-tests/testData/psi/parser-partial/expressions/New8.txt new file mode 100644 index 000000000000..2a02fd4587b6 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New8.txt @@ -0,0 +1,13 @@ +PsiJavaFile:New8.java + PsiNewExpression:new A[ + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiErrorElement:']' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/New9.txt b/java/java-tests/testData/psi/parser-partial/expressions/New9.txt new file mode 100644 index 000000000000..58ede5bb3fb3 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/New9.txt @@ -0,0 +1,9 @@ +PsiJavaFile:New9.java + PsiNewExpression:new int + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiKeyword:int('int') + PsiErrorElement:'[' expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/NewInExprList.txt b/java/java-tests/testData/psi/parser-partial/expressions/NewInExprList.txt new file mode 100644 index 000000000000..49b9fb676bfb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/NewInExprList.txt @@ -0,0 +1,15 @@ +PsiJavaFile:NewInExprList.java + PsiMethodCallExpression:call(new) + PsiReferenceExpression:call + PsiReferenceParameterList + + PsiIdentifier:call('call') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiNewExpression:new + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Not0.txt b/java/java-tests/testData/psi/parser-partial/expressions/Not0.txt new file mode 100644 index 000000000000..6c6b6ca75c0a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Not0.txt @@ -0,0 +1,9 @@ +PsiJavaFile:Not0.java + PsiPrefixExpression:!!a + PsiJavaToken:EXCL('!') + PsiPrefixExpression:!a + PsiJavaToken:EXCL('!') + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Not1.txt b/java/java-tests/testData/psi/parser-partial/expressions/Not1.txt new file mode 100644 index 000000000000..cad5dba7b8f8 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Not1.txt @@ -0,0 +1,5 @@ +PsiJavaFile:Not1.java + PsiPrefixExpression:! + PsiJavaToken:EXCL('!') + PsiErrorElement:Expression expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Or0.txt b/java/java-tests/testData/psi/parser-partial/expressions/Or0.txt new file mode 100644 index 000000000000..20bd74839bdd --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Or0.txt @@ -0,0 +1,21 @@ +PsiJavaFile:Or0.java + PsiBinaryExpression:a | b | c + PsiBinaryExpression:a | b + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiJavaToken:OR('|') + PsiWhiteSpace(' ') + PsiReferenceExpression:b + PsiReferenceParameterList + + PsiIdentifier:b('b') + PsiWhiteSpace(' ') + PsiJavaToken:OR('|') + PsiWhiteSpace(' ') + PsiReferenceExpression:c + PsiReferenceParameterList + + PsiIdentifier:c('c') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Or1.txt b/java/java-tests/testData/psi/parser-partial/expressions/Or1.txt new file mode 100644 index 000000000000..68894eaa8560 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Or1.txt @@ -0,0 +1,10 @@ +PsiJavaFile:Or1.java + PsiBinaryExpression:a | + PsiReferenceExpression:a + PsiReferenceParameterList + + PsiIdentifier:a('a') + PsiWhiteSpace(' ') + PsiJavaToken:OR('|') + PsiErrorElement:Expression expected + diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Parenth0.txt b/java/java-tests/testData/psi/parser-partial/expressions/Parenth0.txt new file mode 100644 index 000000000000..33befc6c50dc --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Parenth0.txt @@ -0,0 +1,8 @@ +PsiJavaFile:Parenth0.java + PsiParenthesizedExpression:(c) + PsiJavaToken:LPARENTH('(') + PsiReferenceExpression:c + PsiReferenceParameterList + + PsiIdentifier:c('c') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/Parenth1.txt b/java/java-tests/testData/psi/parser-partial/expressions/Parenth1.txt new file mode 100644 index 000000000000..ceefc93b0d70 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/Parenth1.txt @@ -0,0 +1,15 @@ +PsiJavaFile:Parenth1.java + PsiPostfixExpression:(this).f-- + PsiReferenceExpression:(this).f + PsiParenthesizedExpression:(this) + PsiJavaToken:LPARENTH('(') + PsiThisExpression:this + PsiReferenceParameterList + + PsiKeyword:this('this') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:DOT('.') + PsiReferenceParameterList + + PsiIdentifier:f('f') + PsiJavaToken:MINUSMINUS('--') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression0.txt b/java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression0.txt new file mode 100644 index 000000000000..b824ee1429f6 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression0.txt @@ -0,0 +1,22 @@ +PsiJavaFile:PinesInReferenceExpression0.java + PsiMethodCallExpression:Collections.sort(null) + PsiReferenceExpression:Collections.sort + PsiReferenceExpression:Collections + PsiReferenceParameterList + + PsiIdentifier:Collections('Collections') + PsiJavaToken:DOT('.') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiIdentifier:sort('sort') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:null + PsiJavaToken:NULL_KEYWORD('null') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression1.txt b/java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression1.txt new file mode 100644 index 000000000000..5b821fd2d44e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/PinesInReferenceExpression1.txt @@ -0,0 +1,22 @@ +PsiJavaFile:PinesInReferenceExpression1.java + PsiMethodCallExpression:this.sort(null) + PsiReferenceExpression:this.sort + PsiThisExpression:this + PsiReferenceParameterList + + PsiKeyword:this('this') + PsiJavaToken:DOT('.') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiIdentifier:sort('sort') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:null + PsiJavaToken:NULL_KEYWORD('null') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/PrimitiveClassObjectAccess.txt b/java/java-tests/testData/psi/parser-partial/expressions/PrimitiveClassObjectAccess.txt new file mode 100644 index 000000000000..d8bdbaffa257 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/PrimitiveClassObjectAccess.txt @@ -0,0 +1,6 @@ +PsiJavaFile:PrimitiveClassObjectAccess.java + PsiClassObjectAccessExpression:int.class + PsiTypeElement:int + PsiKeyword:int('int') + PsiJavaToken:DOT('.') + PsiKeyword:class('class') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall0.txt b/java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall0.txt new file mode 100644 index 000000000000..6b22700580b1 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall0.txt @@ -0,0 +1,22 @@ +PsiJavaFile:QualifiedSuperMethodCall0.java + PsiMethodCallExpression:new D().super(0) + PsiReferenceExpression:new D().super + PsiNewExpression:new D() + PsiKeyword:new('new') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:D + PsiIdentifier:D('D') + PsiReferenceParameterList + + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:DOT('.') + PsiKeyword:super('super') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall1.txt b/java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall1.txt new file mode 100644 index 000000000000..c08eb71cc220 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/QualifiedSuperMethodCall1.txt @@ -0,0 +1,14 @@ +PsiJavaFile:QualifiedSuperMethodCall1.java + PsiMethodCallExpression:d.super(0) + PsiReferenceExpression:d.super + PsiReferenceExpression:d + PsiReferenceParameterList + + PsiIdentifier:d('d') + PsiJavaToken:DOT('.') + PsiKeyword:super('super') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ShiftRight.txt b/java/java-tests/testData/psi/parser-partial/expressions/ShiftRight.txt new file mode 100644 index 000000000000..86d9fc6857f3 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ShiftRight.txt @@ -0,0 +1,11 @@ +PsiJavaFile:ShiftRight.java + PsiAssignmentExpression:x >>= 2 + PsiReferenceExpression:x + PsiReferenceParameterList + + PsiIdentifier:x('x') + PsiWhiteSpace(' ') + PsiJavaToken:GTGTEQ('>>=') + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') diff --git a/java/java-tests/testData/psi/parser-partial/expressions/SuperMethodCallTypeParameterList.txt b/java/java-tests/testData/psi/parser-partial/expressions/SuperMethodCallTypeParameterList.txt new file mode 100644 index 000000000000..b17a757f1144 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/SuperMethodCallTypeParameterList.txt @@ -0,0 +1,9 @@ +PsiJavaFile:SuperMethodCallTypeParameterList.java + PsiMethodCallExpression:super() + PsiReferenceExpression:super + PsiReferenceParameterList + + PsiKeyword:super('super') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') diff --git a/java/java-tests/testData/psi/parser-partial/references/Reference0.txt b/java/java-tests/testData/psi/parser-partial/references/Reference0.txt new file mode 100644 index 000000000000..3768b9f7922e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Reference0.txt @@ -0,0 +1,5 @@ +PsiJavaFile:Reference0.java + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + diff --git a/java/java-tests/testData/psi/parser-partial/references/Reference1.txt b/java/java-tests/testData/psi/parser-partial/references/Reference1.txt new file mode 100644 index 000000000000..9e9dbbe0ec86 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Reference1.txt @@ -0,0 +1,9 @@ +PsiJavaFile:Reference1.java + PsiJavaCodeReferenceElement:a. + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiErrorElement:Identifier expected + diff --git a/java/java-tests/testData/psi/parser-partial/references/Reference2.txt b/java/java-tests/testData/psi/parser-partial/references/Reference2.txt new file mode 100644 index 000000000000..d32c5bc64609 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Reference2.txt @@ -0,0 +1,10 @@ +PsiJavaFile:Reference2.java + PsiJavaCodeReferenceElement:a.b + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:b('b') + PsiReferenceParameterList + diff --git a/java/java-tests/testData/psi/parser-partial/references/Type0.txt b/java/java-tests/testData/psi/parser-partial/references/Type0.txt new file mode 100644 index 000000000000..a9b9e8bde2ca --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Type0.txt @@ -0,0 +1,3 @@ +PsiJavaFile:Type0.java + PsiTypeElement:int + PsiKeyword:int('int') diff --git a/java/java-tests/testData/psi/parser-partial/references/Type1.txt b/java/java-tests/testData/psi/parser-partial/references/Type1.txt new file mode 100644 index 000000000000..286e9f1dfcc2 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Type1.txt @@ -0,0 +1,11 @@ +PsiJavaFile:Type1.java + PsiTypeElement:a.b + PsiJavaCodeReferenceElement:a.b + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:b('b') + PsiReferenceParameterList + diff --git a/java/java-tests/testData/psi/parser-partial/references/Type2.txt b/java/java-tests/testData/psi/parser-partial/references/Type2.txt new file mode 100644 index 000000000000..7234dbb0b59a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Type2.txt @@ -0,0 +1,6 @@ +PsiJavaFile:Type2.java + PsiTypeElement:int[] + PsiTypeElement:int + PsiKeyword:int('int') + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') diff --git a/java/java-tests/testData/psi/parser-partial/references/Type3.txt b/java/java-tests/testData/psi/parser-partial/references/Type3.txt new file mode 100644 index 000000000000..8f4c284f0e5f --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Type3.txt @@ -0,0 +1,9 @@ +PsiJavaFile:Type3.java + PsiTypeElement:int[] + PsiTypeElement:int + PsiKeyword:int('int') + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:LBRACKET('[') + PsiErrorElement:']' expected + diff --git a/java/java-tests/testData/psi/parser-partial/references/Type4.txt b/java/java-tests/testData/psi/parser-partial/references/Type4.txt new file mode 100644 index 000000000000..5159f57cc668 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Type4.txt @@ -0,0 +1,24 @@ +PsiJavaFile:Type4.java + PsiTypeElement:Map> + PsiJavaCodeReferenceElement:Map> + PsiIdentifier:Map('Map') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:COMMA(',') + PsiTypeElement:List + PsiJavaCodeReferenceElement:List + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:GT('>') diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams0.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams0.txt new file mode 100644 index 000000000000..508d8cd3fbae --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams0.txt @@ -0,0 +1,8 @@ +PsiJavaFile:TypeParams0.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams1.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams1.txt new file mode 100644 index 000000000000..0dd4209d39f4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams1.txt @@ -0,0 +1,14 @@ +PsiJavaFile:TypeParams1.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiTypeParameter:U + PsiIdentifier:U('U') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams2.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams2.txt new file mode 100644 index 000000000000..16ac8bead2bf --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams2.txt @@ -0,0 +1,9 @@ +PsiJavaFile:TypeParams2.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams3.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams3.txt new file mode 100644 index 000000000000..b24e3661f7eb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams3.txt @@ -0,0 +1,11 @@ +PsiJavaFile:TypeParams3.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected identifier + PsiIdentifier:hack('hack') + PsiJavaToken:GT('>') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams4.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams4.txt new file mode 100644 index 000000000000..3f60da4b3fcb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams4.txt @@ -0,0 +1,12 @@ +PsiJavaFile:TypeParams4.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace(' ') + PsiErrorElement:Unparsed tokens + PsiIdentifier:hack('hack') \ 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 new file mode 100644 index 000000000000..51d776e6a39e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt @@ -0,0 +1,27 @@ +PsiJavaFile:TypeParams5.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiWhiteSpace(' ') + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiJavaCodeReferenceElement:X + PsiIdentifier:X('X') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiJavaToken:AND('&') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:Y + PsiIdentifier:Y('Y') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:Z + PsiJavaCodeReferenceElement:Z + PsiIdentifier:Z('Z') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:GT('>') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams6.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams6.txt new file mode 100644 index 000000000000..a5b46b98efd0 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams6.txt @@ -0,0 +1,15 @@ +PsiJavaFile:TypeParams6.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace(' ') + PsiErrorElement:Unparsed tokens + PsiIdentifier:supers('supers') + PsiWhiteSpace(' ') + PsiIdentifier:X('X') + PsiJavaToken:GT('>') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt new file mode 100644 index 000000000000..f3cf0196d19a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt @@ -0,0 +1,20 @@ +PsiJavaFile:TypeParams7.java + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiWhiteSpace(' ') + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiJavaCodeReferenceElement:X + PsiIdentifier:X('X') + PsiReferenceParameterList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiTypeParameter:Y + PsiIdentifier:Y('Y') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/JavaTestUtil.java b/java/java-tests/testSrc/com/intellij/JavaTestUtil.java index daf0b57289d8..7e9c239d60ab 100644 --- a/java/java-tests/testSrc/com/intellij/JavaTestUtil.java +++ b/java/java-tests/testSrc/com/intellij/JavaTestUtil.java @@ -1,6 +1,12 @@ package com.intellij; +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.impl.PsiBuilderImpl; +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 @@ -13,4 +19,12 @@ public class JavaTestUtil { public static String getJavaTestDataPath() { return PathManagerEx.getTestDataPath(); } + + public static PsiBuilder getJavaBuilder(final String 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); + JavaParserUtil.setLanguageLevel(builder, languageLevel); + return builder; + } } diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java new file mode 100644 index 000000000000..15874f8244e2 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser; + +import com.intellij.lang.PsiBuilder; +import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.testFramework.IdeaTestCase; +import com.intellij.testFramework.ParsingTestCase; +import org.jetbrains.annotations.NonNls; + +import java.io.IOException; + +import static com.intellij.JavaTestUtil.getJavaBuilder; + + +public abstract class JavaParsingTestCase extends ParsingTestCase { + @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"}) + public JavaParsingTestCase(@NonNls final String dataPath) { + super(dataPath, "java"); + IdeaTestCase.initPlatformPrefix(); + } + + protected interface Parser { + void parse(PsiBuilder builder); + } + + protected void doParserTest(final String text, final Parser parser) { + final String name = getTestName(false); + + final PsiBuilder builder = getJavaBuilder(text); + final PsiBuilder.Marker root = builder.mark(); + + parser.parse(builder); + + if (builder.getTokenType() != null) { + final PsiBuilder.Marker unparsed = builder.mark(); + while (builder.getTokenType() != null) builder.advanceLexer(); + unparsed.error("Unparsed tokens"); + } + + root.done(JavaElementType.JAVA_FILE); + + final String raw = DebugUtil.treeToString(builder.getTreeBuilt(), false); + final String tree = raw.replaceFirst("com.intellij.psi.util.PsiUtilBase\\S+", "PsiJavaFile:" + name + ".java"); + try { + checkResult(name + ".txt", tree); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/AnnotationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/AnnotationParserTest.java new file mode 100644 index 000000000000..f5dcb83f898c --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/AnnotationParserTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser.partial; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.java.parser.DeclarationParser; +import com.intellij.lang.java.parser.JavaParsingTestCase; + + +public class AnnotationParserTest extends JavaParsingTestCase { + public AnnotationParserTest() { + super("parser-partial/annotations"); + } + + public void testMarker() { doParserTest("@Preliminary"); } + public void testSimple0() { doParserTest("@Copyright(\"bla-bla-bla\")"); } + public void testSimple1() { doParserTest("@Copyright(treatedAsValue)"); } + public void testComplex() { doParserTest("@Author(first=\"Eugene\", second=\"Wampirchik\")"); } + public void testMultiple() { doParserTest("@Preliminary @Other(name=value)"); } + public void testArray() { doParserTest("@Endorsers({\"Children\", \"Unscrupulous dentists\"})"); } + public void testNested() { doParserTest("@Author(@Name(first=\"Eugene\", second=\"Wampirchik\"))"); } + public void testQualifiedAnnotation() { doParserTest("@org.jetbrains.annotations.Nullable"); } + + public void testParameterizedAnnotation () { doParserTest("@Nullable"); } + public void testFirstNameMissed() { doParserTest("@Anno(value1, param2=value2)"); } + + private void doParserTest(final String text) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + DeclarationParser.parseAnnotations(builder); + } + }); + } +} 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 new file mode 100644 index 000000000000..340c962ad87b --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser.partial; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.java.parser.ExpressionParser; +import com.intellij.lang.java.parser.JavaParsingTestCase; + + +public class ExpressionParserTest extends JavaParsingTestCase { + public ExpressionParserTest() { + super("parser-partial/expressions"); + } + + public void testAssignment0() { doParserTest("a = 0"); } + public void testAssignment1() { doParserTest("a ="); } + + public void testCond0() { doParserTest("cond ? true : false"); } + public void testCond1() { doParserTest("cond ?"); } + public void testCond2() { doParserTest("cond ? true"); } + public void testCond3() { doParserTest("cond ? true :"); } + + public void testCondOr0() { doParserTest("a || b || c"); } + public void testCondOr1() { doParserTest("a ||"); } + + public void testOr0() { doParserTest("a | b | c"); } + public void testOr1() { doParserTest("a |"); } + + public void testInstanceOf0() { doParserTest("a instanceof String"); } + public void testInstanceOf1() { doParserTest("a instanceof"); } + + public void testNot0() { doParserTest("!!a"); } + public void testNot1() { doParserTest("!"); } + + public void testCast() { doParserTest("(Type)var"); } + + public void testParenth0() { doParserTest("(c)"); } + public void testParenth1() { doParserTest("(this).f--"); } + + public void testNewInExprList() { doParserTest("call(new)"); } + + public void testNew0() { doParserTest("new A()"); } + public void testNew1() { doParserTest("new A[1][]"); } + public void testNew2() { doParserTest("new A[]"); } + public void testNew3() { doParserTest("new A[][1]"); } + public void testNew4() { doParserTest("new A[][]{null}"); } + public void testNew5() { doParserTest("new A[1]{null}"); } + public void testNew6() { doParserTest("new"); } + public void testNew7() { doParserTest("new A"); } + public void testNew8() { doParserTest("new A["); } + public void testNew9() { doParserTest("new int"); } + public void testNew10() { doParserTest("new int()"); } + public void testNew11() { doParserTest("new String[0"); } + public void testNew12() { doParserTest("new int[1][2]"); } + public void testNew13() { doParserTest("new int[1][][2]"); } + public void testNew14() { doParserTest("Q.new A()"); } + + public void testExprList0() { doParserTest("f(1,2)"); } + public void testExprList1() { doParserTest("f("); } + public void testExprList2() { doParserTest("f(1"); } + public void testExprList3() { doParserTest("f(1,"); } + public void testExprList4() { doParserTest("f(1,)"); } + public void testExprList5() { doParserTest("f(1,,2)"); } + public void testExprList6() { doParserTest("f(,2)"); } + + public void testArrayInitializer0() { doParserTest("{ }"); } + public void testArrayInitializer1() { doParserTest("{ 1 }"); } + public void testArrayInitializer2() { doParserTest("{ 1, }"); } + public void testArrayInitializer3() { doParserTest("{ 1,2 }"); } + public void testArrayInitializer4() { doParserTest("{ 1 2 }"); } + public void testArrayInitializer5() { doParserTest("{ { }"); } + public void testArrayInitializer6() { doParserTest("{ , }"); } + public void testArrayInitializer7() { doParserTest("{ , , 7 }"); } + + public void testPinesInReferenceExpression0() { doParserTest("Collections.sort(null)"); } + public void testPinesInReferenceExpression1() { doParserTest("this.sort(null)"); } + + public void testGE() { doParserTest("x >>>= 8 >> 2"); } + + public void testIncompleteCast() { doParserTest("f((ArrayList) )"); } + public void testShiftRight() { doParserTest("x >>= 2"); } + + public void testIllegalWildcard() { doParserTest("this.foo()"); } + + public void testQualifiedSuperMethodCall0() { doParserTest("new D().super(0)"); } + public void testQualifiedSuperMethodCall1() { doParserTest("d.super(0)"); } + public void testSuperMethodCallTypeParameterList() { doParserTest("super()"); } + public void testPrimitiveClassObjectAccess() { doParserTest("int.class"); } + + private void doParserTest(final String text) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + ExpressionParser.parse(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 new file mode 100644 index 000000000000..da5651bf4eb9 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.java.parser.partial; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.java.parser.JavaParsingTestCase; +import com.intellij.lang.java.parser.ReferenceParser; + + +public class ReferenceParserTest extends JavaParsingTestCase { + public ReferenceParserTest() { + super("parser-partial/references"); + } + + public void testReference0() { doRefParserTest("a", false); } + 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>", false); } + + public void testTypeParams0() { doTypeParamsParserTest(""); } + public void testTypeParams1() { doTypeParamsParserTest(""); } + public void testTypeParams2() { doTypeParamsParserTest(""); } + public void testTypeParams4() { doTypeParamsParserTest(">"); } + public void testTypeParams6() { doTypeParamsParserTest(""); } + public void testTypeParams7() { doTypeParamsParserTest(""); } + + private void doRefParserTest(final String text, final boolean incomplete) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + ReferenceParser.parseJavaCodeReference(builder, incomplete, false, false); + } + }); + } + + private void doTypeParserTest(final String text, final boolean incomplete) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + ReferenceParser.parseType(builder, incomplete, false); + } + }); + } + + private void doTypeParamsParserTest(final String text) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + ReferenceParser.parseTypeParameters(builder); + } + }); + } +} diff --git a/java/openapi/src/com/intellij/psi/tree/java/IJavaElementType.java b/java/openapi/src/com/intellij/psi/tree/java/IJavaElementType.java index 7e2f0277cd7a..54e9d45167fb 100644 --- a/java/openapi/src/com/intellij/psi/tree/java/IJavaElementType.java +++ b/java/openapi/src/com/intellij/psi/tree/java/IJavaElementType.java @@ -20,7 +20,19 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NonNls; public class IJavaElementType extends IElementType { + private final boolean myLeftBound; + public IJavaElementType(@NonNls String debugName) { + this(debugName, false); + } + + public IJavaElementType(@NonNls final String debugName, final boolean leftBound) { super(debugName, StdFileTypes.JAVA != null ? StdFileTypes.JAVA.getLanguage() : null); + myLeftBound = leftBound; + } + + @Override + public boolean isLeftBound() { + return myLeftBound; } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/lang/PsiBuilderUtil.java b/platform/lang-api/src/com/intellij/lang/PsiBuilderUtil.java new file mode 100644 index 000000000000..279d061aee73 --- /dev/null +++ b/platform/lang-api/src/com/intellij/lang/PsiBuilderUtil.java @@ -0,0 +1,120 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang; + +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.Nullable; + + +public class PsiBuilderUtil { + private PsiBuilderUtil() { } + + /** + * Returns type of next token. + * + * @param builder PSI builder to operate on. + * @return type of next token or null, if the builder is at the end of token stream + */ + @Nullable + public static IElementType nextTokenType(final PsiBuilder builder) { + if (builder.getTokenType() == null) return null; + final PsiBuilder.Marker sp = builder.mark(); + builder.advanceLexer(); + final IElementType result = builder.getTokenType(); + sp.rollbackTo(); + return result; + } + + /** + * Checks if tokens in token stream form expected sequence. + * + * @param builder PSI builder to operate on. + * @param tokenTypes expected elements. + * @return true if tokens form expected sequence, false otherwise + */ + public static boolean lookAhead(final PsiBuilder builder, final IElementType... tokenTypes) { + if (tokenTypes.length == 0) return true; + + if (!tokenTypes[0].equals(builder.getTokenType())) return false; + + if (tokenTypes.length == 1) return true; + + final PsiBuilder.Marker rb = builder.mark(); + builder.advanceLexer(); + int i = 1; + while (!builder.eof() && i < tokenTypes.length && tokenTypes[i].equals(builder.getTokenType())) { + builder.advanceLexer(); + i++; + } + rb.rollbackTo(); + return i == tokenTypes.length; + } + + /** + * Advances lexer by given number of tokens (but not beyond the end of token stream). + * + * @param builder PSI builder to operate on. + * @param count number of tokens to skip. + */ + public static void advance(final PsiBuilder builder, final int count) { + for (int i=0; i Date: Thu, 22 Jul 2010 15:09:58 +0400 Subject: [PATCH 2/7] Read access missing. --- .../com/intellij/ide/PsiCopyPasteManager.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java index 799a6fb0a5b5..4c69bfccff8f 100644 --- a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java +++ b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java @@ -16,10 +16,12 @@ package com.intellij.ide; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -199,22 +201,31 @@ public class PsiCopyPasteManager { return getDataAsText(); } if (DataFlavor.javaFileListFlavor.equals(flavor)) { - return asFileList(myDataProxy.getElements()); + ApplicationManager.getApplication().runReadAction(new Computable>() { + @Override + public List compute() { + return asFileList(myDataProxy.getElements()); + } + }); } return null; } @Nullable private String getDataAsText() { - List names = new ArrayList(); - for (PsiElement element : myDataProxy.getElements()) { - if (element instanceof PsiNamedElement) { - String name = ((PsiNamedElement) element).getName(); - if (name != null) { - names.add(name); + final List names = new ArrayList(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + for (PsiElement element : myDataProxy.getElements()) { + if (element instanceof PsiNamedElement) { + String name = ((PsiNamedElement) element).getName(); + if (name != null) { + names.add(name); + } + } } } - } + }); if (names.isEmpty()) { return null; } From 8260714221cb857eb171deb7a0086f3fe6cc6e4a Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 22 Jul 2010 16:53:01 +0400 Subject: [PATCH 3/7] prepared IDEA X eap logo --- .../src/idea_community_about.png | Bin 31505 -> 31971 bytes .../src/idea_community_logo.png | Bin 48113 -> 48423 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/community-resources/src/idea_community_about.png b/community-resources/src/idea_community_about.png index caf2b6292be699df9961cbf58cd9b9141640aad3..af11f5f8ee3940faa1389fb318d9a1df943e216f 100644 GIT binary patch literal 31971 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 Y5c7}nt9gFBS`H;6p(tK0Y8?1~0UeR%wg3PC literal 31505 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 DZjnL|gd#Zoq&fJo!8s5O29sj;N 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 V4$~MxAkZ(MYkDTI_d1SG{{x!VLIVH* From fac9a231af6757bf3c8c45b969d938367ad75262 Mon Sep 17 00:00:00 2001 From: "Kirill.Safonov" Date: Thu, 22 Jul 2010 16:37:11 +0400 Subject: [PATCH 4/7] utility introduced that executes code with given (usually plugin) ClassLoader --- .../openapi/util/ClassLoaderUtil.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 platform/util/src/com/intellij/openapi/util/ClassLoaderUtil.java diff --git a/platform/util/src/com/intellij/openapi/util/ClassLoaderUtil.java b/platform/util/src/com/intellij/openapi/util/ClassLoaderUtil.java new file mode 100644 index 000000000000..73166f80a213 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/util/ClassLoaderUtil.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util; + +import com.intellij.util.ThrowableRunnable; + +public class ClassLoaderUtil { + private ClassLoaderUtil() { + } + + public static void runWithClassLoader(final ClassLoader classLoader, final Runnable runnable) { + final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + runnable.run(); + } + finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } + + public static T runWithClassLoader(final ClassLoader classLoader, final Computable computable) { + final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + return computable.compute(); + } + finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } + + public static void runWithClassLoader(final ClassLoader classLoader, final ThrowableRunnable runnable) + throws E { + final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + runnable.run(); + } + finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } + + public static T runWithClassLoader(final ClassLoader classLoader, final ThrowableComputable computable) + throws E { + final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + return computable.compute(); + } + finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } +} From 8d9dbb966e9c38c8485a519d6a9d27cc2d0b7a31 Mon Sep 17 00:00:00 2001 From: "Kirill.Safonov" Date: Thu, 22 Jul 2010 16:39:00 +0400 Subject: [PATCH 5/7] file template that has includes should be parsed using plugin classloader, otherwise included resource won't be found --- .../ide/fileTemplates/FileTemplateUtil.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 38d26627d5e8..e7d9109ff31e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -29,6 +29,8 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.ClassLoaderUtil; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; @@ -232,6 +234,14 @@ public class FileTemplateUtil{ @NonNls @Nullable final String fileName, @Nullable Properties props, @NotNull final PsiDirectory directory) throws Exception { + return createFromTemplate(template, fileName, props, directory, null); + } + + public static PsiElement createFromTemplate(@NotNull final FileTemplate template, + @NonNls @Nullable final String fileName, + @Nullable Properties props, + @NotNull final PsiDirectory directory, + @Nullable ClassLoader classLoader) throws Exception { @NotNull final Project project = directory.getProject(); if (props == null) { props = FileTemplateManager.getInstance().getDefaultProperties(); @@ -256,7 +266,15 @@ public class FileTemplateUtil{ props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME); } } - String mergedText = template.getText(props); + + final Properties props_ = props; + String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(), + new ThrowableComputable() { + @Override + public String compute() throws IOException { + return template.getText(props_); + } + }); final String templateText = StringUtil.convertLineSeparators(mergedText); final Exception[] commandException = new Exception[1]; final PsiElement[] result = new PsiElement[1]; From 4ab77acf4af2150b1aa6e079264726f6a620da15 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 22 Jul 2010 17:42:41 +0400 Subject: [PATCH 6/7] Hold formatting until import optimization finished --- .../refactoring/OptimizeImportsRefactoringHelper.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java b/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java index 08719452aab8..3a495b7816be 100644 --- a/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java +++ b/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java @@ -48,11 +48,16 @@ public class OptimizeImportsRefactoringHelper implements RefactoringHelper javaFiles) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { + PsiManager.getInstance(project).performActionWithFormatterDisabled(new Runnable() { public void run() { - PsiDocumentManager.getInstance(project).commitAllDocuments(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + PsiDocumentManager.getInstance(project).commitAllDocuments(); + } + }); } }); + final Set> redundants = new HashSet>(); final Runnable findRedundantImports = new Runnable() { public void run() { From f3932b9c9e66b57a81c51767b1d467414a91022f Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 22 Jul 2010 17:59:01 +0400 Subject: [PATCH 7/7] IDEA-56660 Allow to fold comment that goes before root tag --- .../com/intellij/lang/xml/XmlFoldingBuilder.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/xml/impl/src/com/intellij/lang/xml/XmlFoldingBuilder.java b/xml/impl/src/com/intellij/lang/xml/XmlFoldingBuilder.java index 2d1f11c38d73..32d44782ca7f 100644 --- a/xml/impl/src/com/intellij/lang/xml/XmlFoldingBuilder.java +++ b/xml/impl/src/com/intellij/lang/xml/XmlFoldingBuilder.java @@ -66,17 +66,7 @@ public class XmlFoldingBuilder implements FoldingBuilder, DumbAware { if (rootTag != null) { foldings = new ArrayList(); - if (rootTag instanceof XmlTag) { - addElementsToFold(foldings, rootTag, document); - - // HTML tags in JSP - for (PsiElement sibling = rootTag.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) { - if (sibling instanceof XmlTag) addElementsToFold(foldings, (XmlElement)sibling, document); - } - } - else { - doAddForChildren(xmlDocument, foldings, document); - } + doAddForChildren(xmlDocument, foldings, document); } return foldings != null ? foldings.toArray(new FoldingDescriptor[foldings.size()]):FoldingDescriptor.EMPTY; @@ -100,7 +90,7 @@ public class XmlFoldingBuilder implements FoldingBuilder, DumbAware { else if (child instanceof XmlComment) { addToFold(foldings, child, document); } - else if (child instanceof XmlText) { + else if (child instanceof XmlText || child instanceof XmlProlog) { final PsiElement[] grandChildren = child.getChildren(); for (PsiElement grandChild : grandChildren) {