From e737db6dcc31c3195b31848d6e719a3e7d91c9e7 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 2 Jul 2015 15:29:10 +0300 Subject: [PATCH] java: receiver parameter parsing --- .../intellij/psi/PsiReceiverParameter.java | 4 + .../lang/java/parser/DeclarationParser.java | 16 ++ .../impl/source/PsiReceiverParameterImpl.java | 13 +- .../parser-partial/declarations/Receiver.txt | 178 ++++++++++++++++++ .../parser/partial/DeclarationParserTest.java | 9 + .../com/intellij/psi/JavaStubBuilderTest.java | 2 +- 6 files changed, 213 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Receiver.txt diff --git a/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java b/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java index eb93e359f575..abbbb4fbd52c 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java @@ -15,10 +15,14 @@ */ package com.intellij.psi; +import org.jetbrains.annotations.NotNull; + /** * Represents a receiver parameter of a Java method (Java 8). * * @since 12.1 */ public interface PsiReceiverParameter extends PsiVariable { + @NotNull + PsiThisExpression getIdentifier(); } diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 634eda49bcdc..d916d1d1cf4a 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -608,6 +608,22 @@ public class DeclarationParser { } } + if (typed) { + IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.THIS_KEYWORD || tokenType == JavaTokenType.IDENTIFIER && builder.lookAhead(1) == JavaTokenType.DOT) { + PsiBuilder.Marker mark = builder.mark(); + + PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); + if (expr != null && exprType(expr) == JavaElementType.THIS_EXPRESSION) { + mark.drop(); + done(param, JavaElementType.RECEIVER_PARAMETER); + return param; + } + + mark.rollbackTo(); + } + } + if (expect(builder, JavaTokenType.IDENTIFIER)) { if (!resource) { eatBrackets(builder, typeInfo != null && typeInfo.isVarArg ? "expected.rparen" : null); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java index eb26691f059d..05cbfa82c136 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.impl.source; -import com.intellij.lang.ASTNode; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.CompositePsiElement; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -30,6 +29,11 @@ public class PsiReceiverParameterImpl extends CompositePsiElement implements Psi super(JavaElementType.RECEIVER_PARAMETER); } + @NotNull + public PsiThisExpression getIdentifier() { + return PsiTreeUtil.getRequiredChildOfType(this, PsiThisExpression.class); + } + @Nullable @Override public PsiModifierList getModifierList() { @@ -100,13 +104,6 @@ public class PsiReceiverParameterImpl extends CompositePsiElement implements Psi return getIdentifier().getTextOffset(); } - @NotNull - private PsiElement getIdentifier() { - ASTNode node = findChildByType(JavaTokenType.THIS_KEYWORD); - assert node != null : getChildren(); - return node.getPsi(); - } - @Override public String toString() { return "PsiReceiverParameter"; diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Receiver.txt b/java/java-tests/testData/psi/parser-partial/declarations/Receiver.txt new file mode 100644 index 000000000000..aa0e63c9ee3e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Receiver.txt @@ -0,0 +1,178 @@ +PsiJavaFile:Receiver.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:m1 + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:m1('m1') + PsiParameterList:(C this) + PsiJavaToken:LPARENTH('(') + PsiReceiverParameter + PsiModifierList: + + PsiTypeElement:C + PsiJavaCodeReferenceElement:C + PsiIdentifier:C('C') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiThisExpression:this + PsiReferenceParameterList + + PsiKeyword:this('this') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiMethod:m2 + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:m2('m2') + PsiParameterList:(T T.this) + PsiJavaToken:LPARENTH('(') + PsiReceiverParameter + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiThisExpression:T.this + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiKeyword:this('this') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiMethod:m3 + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:m3('m3') + PsiParameterList:(X Y.Z) + PsiJavaToken:LPARENTH('(') + PsiParameter:Y + PsiModifierList: + + PsiTypeElement:X + PsiJavaCodeReferenceElement:X + PsiIdentifier:X('X') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:Y('Y') + PsiErrorElement:',' expected + PsiJavaToken:DOT('.') + PsiJavaCodeReferenceElement:Z + PsiIdentifier:Z('Z') + PsiReferenceParameterList + + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiField:f1 + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:f1('f1') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLambdaExpression:(T this) -> { } + PsiParameterList:(T this) + PsiJavaToken:LPARENTH('(') + PsiReceiverParameter + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiThisExpression:this + PsiReferenceParameterList + + PsiKeyword:this('this') + PsiJavaToken:RPARENTH(')') + PsiWhiteSpace(' ') + PsiJavaToken:ARROW('->') + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiField:f2 + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:f2('f2') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLambdaExpression:(T T.this) -> { } + PsiParameterList:(T T.this) + PsiJavaToken:LPARENTH('(') + PsiReceiverParameter + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiThisExpression:T.this + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiKeyword:this('this') + PsiJavaToken:RPARENTH(')') + PsiWhiteSpace(' ') + PsiJavaToken:ARROW('->') + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java index 4f0ecb3d6e7a..4ed84741e8e8 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java @@ -72,6 +72,15 @@ public class DeclarationParserTest extends JavaParsingTestCase { " }\n} }"); } + public void testReceiver() { + doParserTest( + "{ void m1(C this);" + + " void m2(T T.this);" + + " void m3(X Y.Z);" + + " T f1 = (T this) -> { };" + + " T f2 = (T T.this) -> { }; }"); + } + public void testFieldSimple() { doParserTest("{ int field = 0; }"); } public void testFieldMulti() { doParserTest("{ int field1 = 0, field2; }"); } public void testUnclosedBracket() { doParserTest("{ int field[ }"); } diff --git a/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java index f9c585556f24..a11e941d31ec 100644 --- a/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java @@ -371,7 +371,7 @@ public class JavaStubBuilderTest extends LightIdeaTestCase { "\n" + "class C<@A T extends @A C> implements @A I<@A T> {\n" + " @TA T<@A T1, @A ? extends @A T2> f;\n" + - " @TA T m(/*@A C this,*/ @TA int p) throws @A E {\n" + + " @TA T m(@A C this, @TA int p) throws @A E {\n" + " o.<@A1 C>m();\n" + " new @A2 C();\n" + " C.@A3 B v = (@A4 C)v.new @A5 C();\n" +