diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java index d48486858153..ee6cb3bac458 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ExpressionParser.java @@ -222,7 +222,7 @@ public class ExpressionParser { final PsiBuilder.Marker right = parseExpression(builder, toParse); if (right == null) { error(builder, toParse == ExprType.TYPE ? - JavaErrorMessages.message("expected.type") : JavaErrorMessages.message("expected.expression")); + JavaErrorMessages.message("expected.type") : JavaErrorMessages.message("expected.expression")); expression.done(toCreate); return expression; } @@ -319,6 +319,7 @@ public class ExpressionParser { final IElementType tokenType = builder.getTokenType(); if (tokenType == JavaTokenType.DOT) { final PsiBuilder.Marker dotPos = builder.mark(); + final int dotOffset = builder.getCurrentOffset(); builder.advanceLexer(); final IElementType dotTokenType = builder.getTokenType(); @@ -348,25 +349,26 @@ public class ExpressionParser { } else if ((dotTokenType == JavaTokenType.THIS_KEYWORD || dotTokenType == JavaTokenType.SUPER_KEYWORD) && exprType(expr) == JavaElementType.REFERENCE_EXPRESSION) { - if (breakPoint == BreakPoint.P2) { + if (breakPoint == BreakPoint.P2 && builder.getCurrentOffset() == breakOffset) { dotPos.rollbackTo(); startMarker.drop(); return expr; } final PsiBuilder.Marker copy = startMarker.precede(); + final int offset = builder.getCurrentOffset(); startMarker.rollbackTo(); final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, false, true, false, false, false); - if (ref == null || builder.getTokenType() != JavaTokenType.DOT) { + if (ref == null || builder.getTokenType() != JavaTokenType.DOT || builder.getCurrentOffset() != dotOffset) { copy.rollbackTo(); - return parsePrimary(builder, BreakPoint.P2, -1); + return parsePrimary(builder, BreakPoint.P2, offset); } builder.advanceLexer(); if (builder.getTokenType() != dotTokenType) { copy.rollbackTo(); - return parsePrimary(builder, BreakPoint.P2, -1); + return parsePrimary(builder, BreakPoint.P2, offset); } builder.advanceLexer(); @@ -689,7 +691,7 @@ public class ExpressionParser { else { if (builder.getTokenType() != JavaTokenType.LBRACKET) { error(builder, refOrType == null ? - JavaErrorMessages.message("expected.lbracket") : JavaErrorMessages.message("expected.lparen.or.lbracket")); + JavaErrorMessages.message("expected.lbracket") : JavaErrorMessages.message("expected.lparen.or.lbracket")); newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; } diff --git a/java/java-tests/testData/psi/parser-partial/expressions/ChainedThisObjectAccess.txt b/java/java-tests/testData/psi/parser-partial/expressions/ChainedThisObjectAccess.txt new file mode 100644 index 000000000000..bf6b560e1d41 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/expressions/ChainedThisObjectAccess.txt @@ -0,0 +1,16 @@ +PsiJavaFile:ChainedThisObjectAccess.java + PsiReferenceExpression:A.this.B + PsiThisExpression:A.this + PsiJavaCodeReferenceElement:A + PsiIdentifier:A('A') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiKeyword:this('this') + PsiJavaToken:DOT('.') + PsiReferenceParameterList + + PsiIdentifier:B('B') + PsiErrorElement:Unparsed tokens + PsiJavaToken:DOT('.') + PsiKeyword:this('this') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java index 10e367acd016..ec8531d4a16c 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ExpressionParserTest.java @@ -113,6 +113,7 @@ public class ExpressionParserTest extends JavaParsingTestCase { public void testSuperMethodCallTypeParameterList() { doParserTest("super()"); } public void testPrimitiveClassObjectAccess() { doParserTest("int.class"); } public void testChainedClassObjectAccess() { doParserTest("A.class.B.class"); } + public void testChainedThisObjectAccess() { doParserTest("A.this.B.this"); } private void doParserTest(final String text) { doParserTest(text, new TestParser() {