mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Lambda expressions support: second round
- typed parameters - type parameter list - resolve inside lambda
This commit is contained in:
@@ -22,6 +22,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Represents a Java lambda expression.
|
||||
*/
|
||||
public interface PsiLambdaExpression extends PsiExpression {
|
||||
/**
|
||||
* Returns this lambda expression's type parameter list (if any).
|
||||
*
|
||||
* @return type parameter list or null.
|
||||
*/
|
||||
@Nullable
|
||||
PsiTypeParameterList getTypeParameterList();
|
||||
|
||||
/**
|
||||
* Returns this lambda expression's parameter list.
|
||||
*
|
||||
@@ -31,7 +39,8 @@ public interface PsiLambdaExpression extends PsiExpression {
|
||||
PsiParameterList getParameterList();
|
||||
|
||||
/**
|
||||
* Returns PSI element representing lambda expression body: {@link PsiCodeBlock}, {@link PsiExpression}, or null if none.
|
||||
* Returns PSI element representing lambda expression body: {@link PsiCodeBlock}, {@link PsiExpression},
|
||||
* or null if the expression is incomplete.
|
||||
*
|
||||
* @return lambda expression body.
|
||||
*/
|
||||
|
||||
@@ -163,7 +163,7 @@ public class ExpressionParser {
|
||||
return parseBinary(builder, ExprType.UNARY, MULTIPLICATIVE_OPS);
|
||||
|
||||
case UNARY:
|
||||
return parseUnary(builder);
|
||||
return parseUnary(builder, false);
|
||||
|
||||
case TYPE:
|
||||
return myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
@@ -246,14 +246,14 @@ public class ExpressionParser {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parseUnary(final PsiBuilder builder) {
|
||||
private PsiBuilder.Marker parseUnary(final PsiBuilder builder, final boolean afterCast) {
|
||||
final IElementType tokenType = builder.getTokenType();
|
||||
|
||||
if (PREFIX_OPS.contains(tokenType)) {
|
||||
final PsiBuilder.Marker unary = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
final PsiBuilder.Marker operand = parseUnary(builder);
|
||||
final PsiBuilder.Marker operand = parseUnary(builder, false);
|
||||
if (operand == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.expression"));
|
||||
}
|
||||
@@ -269,19 +269,19 @@ public class ExpressionParser {
|
||||
myParser.getReferenceParser().parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
if (typeInfo == null || !expect(builder, JavaTokenType.RPARENTH)) {
|
||||
typeCast.rollbackTo();
|
||||
return parsePostfix(builder);
|
||||
return parsePostfix(builder, false);
|
||||
}
|
||||
|
||||
if (PREF_ARITHMETIC_OPS.contains(builder.getTokenType()) && !typeInfo.isPrimitive) {
|
||||
typeCast.rollbackTo();
|
||||
return parsePostfix(builder);
|
||||
return parsePostfix(builder, false);
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker expr = parseUnary(builder);
|
||||
final PsiBuilder.Marker expr = parseUnary(builder, true);
|
||||
if (expr == null) {
|
||||
if (!typeInfo.isParameterized) { // cannot parse correct parenthesized expression after correct parameterized type
|
||||
typeCast.rollbackTo();
|
||||
return parsePostfix(builder);
|
||||
return parsePostfix(builder, false);
|
||||
}
|
||||
else {
|
||||
error(builder, JavaErrorMessages.message("expected.expression"));
|
||||
@@ -292,13 +292,13 @@ public class ExpressionParser {
|
||||
return typeCast;
|
||||
}
|
||||
else {
|
||||
return parsePostfix(builder);
|
||||
return parsePostfix(builder, afterCast);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parsePostfix(final PsiBuilder builder) {
|
||||
PsiBuilder.Marker operand = parsePrimary(builder, null, -1);
|
||||
private PsiBuilder.Marker parsePostfix(final PsiBuilder builder, final boolean afterCast) {
|
||||
PsiBuilder.Marker operand = parsePrimary(builder, null, -1, afterCast);
|
||||
if (operand == null) return null;
|
||||
|
||||
while (POSTFIX_OPS.contains(builder.getTokenType())) {
|
||||
@@ -315,10 +315,13 @@ public class ExpressionParser {
|
||||
|
||||
// todo[r.sh] make 'this', 'super' and 'class' reference expressions
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parsePrimary(final PsiBuilder builder, @Nullable final BreakPoint breakPoint, final int breakOffset) {
|
||||
private PsiBuilder.Marker parsePrimary(final PsiBuilder builder,
|
||||
@Nullable final BreakPoint breakPoint,
|
||||
final int breakOffset,
|
||||
final boolean afterCast) {
|
||||
PsiBuilder.Marker startMarker = builder.mark();
|
||||
|
||||
PsiBuilder.Marker expr = parsePrimaryExpressionStart(builder);
|
||||
PsiBuilder.Marker expr = parsePrimaryExpressionStart(builder, afterCast);
|
||||
if (expr == null) {
|
||||
startMarker.drop();
|
||||
return null;
|
||||
@@ -346,7 +349,7 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker classObjAccess = parseClassAccessOrMethodReference(builder);
|
||||
if (classObjAccess == null || builder.getCurrentOffset() < offset) {
|
||||
copy.rollbackTo();
|
||||
return parsePrimary(builder, BreakPoint.P1, offset);
|
||||
return parsePrimary(builder, BreakPoint.P1, offset, false);
|
||||
}
|
||||
|
||||
startMarker = copy;
|
||||
@@ -370,13 +373,13 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker ref = myParser.getReferenceParser().parseJavaCodeReference(builder, false, true, false, false, false);
|
||||
if (ref == null || builder.getTokenType() != JavaTokenType.DOT || builder.getCurrentOffset() != dotOffset) {
|
||||
copy.rollbackTo();
|
||||
return parsePrimary(builder, BreakPoint.P2, offset);
|
||||
return parsePrimary(builder, BreakPoint.P2, offset, false);
|
||||
}
|
||||
builder.advanceLexer();
|
||||
|
||||
if (builder.getTokenType() != dotTokenType) {
|
||||
copy.rollbackTo();
|
||||
return parsePrimary(builder, BreakPoint.P2, offset);
|
||||
return parsePrimary(builder, BreakPoint.P2, offset, false);
|
||||
}
|
||||
builder.advanceLexer();
|
||||
|
||||
@@ -417,7 +420,7 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker copy = startMarker.precede();
|
||||
startMarker.rollbackTo();
|
||||
|
||||
final PsiBuilder.Marker qualifier = parsePrimaryExpressionStart(builder);
|
||||
final PsiBuilder.Marker qualifier = parsePrimaryExpressionStart(builder, false);
|
||||
if (qualifier != null) {
|
||||
final PsiBuilder.Marker refExpr = qualifier.precede();
|
||||
if (builder.getTokenType() == JavaTokenType.DOT) {
|
||||
@@ -433,7 +436,7 @@ public class ExpressionParser {
|
||||
}
|
||||
|
||||
copy.rollbackTo();
|
||||
return parsePrimary(builder, BreakPoint.P3, -1);
|
||||
return parsePrimary(builder, BreakPoint.P3, -1, false);
|
||||
}
|
||||
else {
|
||||
startMarker.drop();
|
||||
@@ -462,7 +465,7 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker classObjAccess = parseClassAccessOrMethodReference(builder);
|
||||
if (classObjAccess == null || builder.getCurrentOffset() <= pos) {
|
||||
copy.rollbackTo();
|
||||
return parsePrimary(builder, BreakPoint.P4, -1);
|
||||
return parsePrimary(builder, BreakPoint.P4, -1, false);
|
||||
}
|
||||
|
||||
startMarker = copy;
|
||||
@@ -502,7 +505,7 @@ public class ExpressionParser {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parsePrimaryExpressionStart(final PsiBuilder builder) {
|
||||
private PsiBuilder.Marker parsePrimaryExpressionStart(final PsiBuilder builder, final boolean afterCast) {
|
||||
IElementType tokenType = builder.getTokenType();
|
||||
|
||||
if (LITERALS.contains(tokenType)) {
|
||||
@@ -512,21 +515,21 @@ public class ExpressionParser {
|
||||
return literal;
|
||||
}
|
||||
|
||||
if (tokenType == JavaTokenType.LBRACE) {
|
||||
return parseArrayInitializer(builder);
|
||||
}
|
||||
|
||||
if (tokenType == JavaTokenType.NEW_KEYWORD) {
|
||||
return parseNew(builder, null);
|
||||
}
|
||||
|
||||
if (tokenType == JavaTokenType.LPARENTH) {
|
||||
final PsiBuilder.Marker lambda = parseLambdaAfterParenth(builder, null);
|
||||
if (lambda != null) {
|
||||
return lambda;
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker parenth = builder.mark();
|
||||
|
||||
final IElementType nextToken1 = builder.lookAhead(1);
|
||||
final IElementType nextToken2 = builder.lookAhead(2);
|
||||
if (nextToken1 == JavaTokenType.IDENTIFIER) {
|
||||
if (nextToken2 == JavaTokenType.COMMA ||
|
||||
nextToken2 == JavaTokenType.RPARENTH && builder.lookAhead(3) == JavaTokenType.ARROW) {
|
||||
return parseLambdaExpression(builder, parenth, false);
|
||||
}
|
||||
}
|
||||
else if (nextToken1 == JavaTokenType.RPARENTH && nextToken2 == JavaTokenType.ARROW) {
|
||||
return parseLambdaExpression(builder, parenth, false);
|
||||
}
|
||||
|
||||
builder.advanceLexer();
|
||||
|
||||
final PsiBuilder.Marker inner = parse(builder);
|
||||
@@ -544,17 +547,15 @@ public class ExpressionParser {
|
||||
return parenth;
|
||||
}
|
||||
|
||||
if (tokenType == JavaTokenType.LBRACE) {
|
||||
return parseArrayInitializer(builder);
|
||||
}
|
||||
|
||||
if (TYPE_START.contains(tokenType)) {
|
||||
final PsiBuilder.Marker mark = builder.mark();
|
||||
|
||||
final ReferenceParser.TypeInfo typeInfo = myParser.getReferenceParser().parseTypeInfo(builder, 0);
|
||||
if (typeInfo != null && (typeInfo.isPrimitive || !typeInfo.hasErrors && typeInfo.isParameterized)) {
|
||||
final PsiBuilder.Marker result = continueClassAccessOrMethodReference(builder, mark, typeInfo.isPrimitive);
|
||||
if (result != null) return result;
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
mark.rollbackTo();
|
||||
@@ -568,7 +569,7 @@ public class ExpressionParser {
|
||||
|
||||
if (tokenType == JavaTokenType.IDENTIFIER) {
|
||||
if (builder.lookAhead(1) == JavaTokenType.ARROW) {
|
||||
return parseLambdaExpression(builder, builder.mark(), false);
|
||||
return parseLambdaExpression(builder, false, null);
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker refExpr;
|
||||
@@ -596,6 +597,29 @@ public class ExpressionParser {
|
||||
if (tokenType == JavaTokenType.LT) {
|
||||
expr = builder.mark();
|
||||
|
||||
if (!afterCast) {
|
||||
final PsiBuilder.Marker typeParams = myParser.getReferenceParser().parseTypeParameters(builder, true);
|
||||
|
||||
if (typeParams != null) {
|
||||
tokenType = builder.getTokenType();
|
||||
|
||||
PsiBuilder.Marker lambda = null;
|
||||
if (tokenType == JavaTokenType.LPARENTH) {
|
||||
lambda = parseLambdaAfterParenth(builder, typeParams);
|
||||
}
|
||||
else if (tokenType == JavaTokenType.IDENTIFIER && builder.lookAhead(1) == JavaTokenType.ARROW) {
|
||||
lambda = parseLambdaExpression(builder, false, typeParams);
|
||||
}
|
||||
if (lambda != null) {
|
||||
expr.drop();
|
||||
return lambda;
|
||||
}
|
||||
|
||||
expr.rollbackTo();
|
||||
expr = builder.mark();
|
||||
}
|
||||
}
|
||||
|
||||
if (!myParser.getReferenceParser().parseReferenceParameterList(builder, false, false)) {
|
||||
expr.rollbackTo();
|
||||
return null;
|
||||
@@ -622,10 +646,6 @@ public class ExpressionParser {
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (tokenType == JavaTokenType.NEW_KEYWORD) {
|
||||
return parseNew(builder, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -827,15 +847,75 @@ public class ExpressionParser {
|
||||
return start;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiBuilder.Marker parseLambdaExpression(final PsiBuilder builder, final PsiBuilder.Marker start, final boolean typed) {
|
||||
myParser.getDeclarationParser().parseLambdaParameterList(builder, typed);
|
||||
return parseLambdaExpressionFromArrow(builder, start);
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parseLambdaAfterParenth(final PsiBuilder builder, @Nullable final PsiBuilder.Marker typeList) {
|
||||
final boolean isLambda;
|
||||
final boolean isTyped;
|
||||
|
||||
final IElementType nextToken1 = builder.lookAhead(1);
|
||||
final IElementType nextToken2 = builder.lookAhead(2);
|
||||
if (nextToken1 == JavaTokenType.RPARENTH && nextToken2 == JavaTokenType.ARROW) {
|
||||
isLambda = true;
|
||||
isTyped = false;
|
||||
}
|
||||
else if (nextToken1 == JavaTokenType.AT ||
|
||||
ElementType.MODIFIER_BIT_SET.contains(nextToken1) || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(nextToken1)) {
|
||||
isLambda = true;
|
||||
isTyped = true;
|
||||
}
|
||||
else if (nextToken1 == JavaTokenType.IDENTIFIER) {
|
||||
if (nextToken2 == JavaTokenType.COMMA || nextToken2 == JavaTokenType.RPARENTH && builder.lookAhead(3) == JavaTokenType.ARROW) {
|
||||
isLambda = true;
|
||||
isTyped = false;
|
||||
}
|
||||
else if (nextToken2 == JavaTokenType.ARROW) {
|
||||
isLambda = false;
|
||||
isTyped = false;
|
||||
}
|
||||
else {
|
||||
boolean arrow = false;
|
||||
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
while (!builder.eof()) {
|
||||
builder.advanceLexer();
|
||||
final IElementType tokenType = builder.getTokenType();
|
||||
if (tokenType == JavaTokenType.ARROW) {
|
||||
arrow = true;
|
||||
break;
|
||||
}
|
||||
if (tokenType == JavaTokenType.RPARENTH) {
|
||||
arrow = builder.lookAhead(1) == JavaTokenType.ARROW;
|
||||
break;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.LPARENTH || tokenType == JavaTokenType.SEMICOLON ||
|
||||
tokenType == JavaTokenType.LBRACE || tokenType == JavaTokenType.RBRACE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
marker.rollbackTo();
|
||||
|
||||
isLambda = arrow;
|
||||
isTyped = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
isLambda = false;
|
||||
isTyped = false;
|
||||
}
|
||||
|
||||
return isLambda ? parseLambdaExpression(builder, isTyped, typeList) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiBuilder.Marker parseLambdaExpressionFromArrow(final PsiBuilder builder, final PsiBuilder.Marker start) {
|
||||
builder.advanceLexer();
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parseLambdaExpression(final PsiBuilder builder, final boolean typed, @Nullable final PsiBuilder.Marker typeList) {
|
||||
final PsiBuilder.Marker start = typeList != null ? typeList.precede() : builder.mark();
|
||||
|
||||
myParser.getDeclarationParser().parseLambdaParameterList(builder, typed);
|
||||
|
||||
if (!expect(builder, JavaTokenType.ARROW)) {
|
||||
start.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker body;
|
||||
if (builder.getTokenType() == JavaTokenType.LBRACE) {
|
||||
|
||||
@@ -297,6 +297,13 @@ public class ReferenceParser {
|
||||
|
||||
@NotNull
|
||||
public PsiBuilder.Marker parseTypeParameters(final PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = parseTypeParameters(builder, false);
|
||||
assert marker != null;
|
||||
return marker;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiBuilder.Marker parseTypeParameters(final PsiBuilder builder, final boolean stopOnErrors) {
|
||||
final PsiBuilder.Marker list = builder.mark();
|
||||
if (!expect(builder, JavaTokenType.LT)) {
|
||||
list.done(JavaElementType.TYPE_PARAMETER_LIST);
|
||||
@@ -306,6 +313,10 @@ public class ReferenceParser {
|
||||
while (true) {
|
||||
final PsiBuilder.Marker param = parseTypeParameter(builder);
|
||||
if (param == null) {
|
||||
if (stopOnErrors) {
|
||||
list.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
error(builder, JavaErrorMessages.message("expected.type.parameter"));
|
||||
}
|
||||
if (!expect(builder, JavaTokenType.COMMA)) {
|
||||
@@ -314,6 +325,11 @@ public class ReferenceParser {
|
||||
}
|
||||
|
||||
if (!expect(builder, JavaTokenType.GT)) {
|
||||
if (stopOnErrors) {
|
||||
list.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
// hack for completion
|
||||
if (builder.getTokenType() == JavaTokenType.IDENTIFIER) {
|
||||
if (builder.lookAhead(1) == JavaTokenType.GT) {
|
||||
|
||||
@@ -184,14 +184,39 @@ public class PsiImplUtil {
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent,
|
||||
@NotNull final PsiElement place) {
|
||||
final boolean fromBody = lastParent instanceof PsiCodeBlock;
|
||||
final PsiTypeParameterList typeParameterList = method.getTypeParameterList();
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
return processDeclarationsInMethodLike(method, processor, state, fromBody, place, typeParameterList, parameterList);
|
||||
}
|
||||
|
||||
public static boolean processDeclarationsInLambda(@NotNull final PsiLambdaExpression lambda,
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent,
|
||||
@NotNull final PsiElement place) {
|
||||
final boolean fromBody = lastParent != null && lastParent == lambda.getBody();
|
||||
final PsiTypeParameterList typeParameterList = lambda.getTypeParameterList();
|
||||
final PsiParameterList parameterList = lambda.getParameterList();
|
||||
return processDeclarationsInMethodLike(lambda, processor, state, fromBody, place, typeParameterList, parameterList);
|
||||
}
|
||||
|
||||
private static boolean processDeclarationsInMethodLike(@NotNull final PsiElement element,
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final boolean fromBody,
|
||||
@NotNull final PsiElement place,
|
||||
@Nullable final PsiTypeParameterList typeParameterList,
|
||||
@NotNull final PsiParameterList parameterList) {
|
||||
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, element);
|
||||
|
||||
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
|
||||
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, method);
|
||||
if (hint == null || hint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
|
||||
final PsiTypeParameterList list = method.getTypeParameterList();
|
||||
if (list != null && !list.processDeclarations(processor, state, null, place)) return false;
|
||||
if (typeParameterList != null && !typeParameterList.processDeclarations(processor, state, null, place)) return false;
|
||||
}
|
||||
if (lastParent instanceof PsiCodeBlock) {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
|
||||
if (fromBody) {
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!processor.execute(parameter, state)) return false;
|
||||
}
|
||||
|
||||
+18
-2
@@ -16,7 +16,9 @@
|
||||
package com.intellij.psi.impl.source.tree.java;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -25,16 +27,22 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
|
||||
super(JavaElementType.LAMBDA_EXPRESSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiTypeParameterList getTypeParameterList() {
|
||||
final PsiElement element = getFirstChild();
|
||||
return element instanceof PsiTypeParameterList ? (PsiTypeParameterList)element : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiParameterList getParameterList() {
|
||||
return PsiTreeUtil.getRequiredChildOfType(this, PsiParameterList.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public PsiElement getBody() {
|
||||
return PsiTreeUtil.getChildOfAnyType(this, PsiExpression.class, PsiCodeBlock.class);
|
||||
final PsiElement element = getLastChild();
|
||||
return element instanceof PsiExpression || element instanceof PsiCodeBlock ? element : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,6 +60,14 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDeclarations(@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent,
|
||||
@NotNull final PsiElement place) {
|
||||
return PsiImplUtil.processDeclarationsInLambda(this, processor, state, lastParent, place);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiLambdaExpression:" + getText();
|
||||
|
||||
+13
-1
@@ -14,15 +14,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class C {
|
||||
interface Simplest {
|
||||
void m();
|
||||
}
|
||||
void simplest() { }
|
||||
void use(Simplest s) { }
|
||||
|
||||
interface IntParser {
|
||||
int parse(String s);
|
||||
}
|
||||
|
||||
interface ListProducer<T> {
|
||||
List<T> produce();
|
||||
}
|
||||
|
||||
void test() {
|
||||
Simplest simplest = <weak_warning descr="Lambda expressions type check is not yet implemented">() -> { }</weak_warning>;
|
||||
use(<weak_warning descr="Lambda expressions type check is not yet implemented">() -> { }</weak_warning>);
|
||||
|
||||
IntParser intParser = <weak_warning descr="Lambda expressions type check is not yet implemented">(String s) -> Integer.parseInt(s)</weak_warning>;
|
||||
ListProducer<String> listProducer = <weak_warning descr="Lambda expressions type check is not yet implemented"><T>() -> new ArrayList<T>()</weak_warning>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
PsiJavaFile:LambdaExpression12.java
|
||||
PsiLambdaExpression:<T>() -> new C<T>()
|
||||
PsiTypeParameterList
|
||||
PsiJavaToken:LT('<')
|
||||
PsiTypeParameter:T
|
||||
PsiIdentifier:T('T')
|
||||
PsiElement(EXTENDS_BOUND_LIST)
|
||||
<empty list>
|
||||
PsiJavaToken:GT('>')
|
||||
PsiParameterList:()
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiNewExpression:new C<T>()
|
||||
PsiKeyword:new('new')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaCodeReferenceElement:C<T>
|
||||
PsiIdentifier:C('C')
|
||||
PsiReferenceParameterList
|
||||
PsiJavaToken:LT('<')
|
||||
PsiTypeElement:T
|
||||
PsiJavaCodeReferenceElement:T
|
||||
PsiIdentifier:T('T')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:GT('>')
|
||||
PsiExpressionList
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
@@ -0,0 +1,21 @@
|
||||
PsiJavaFile:LambdaExpression13.java
|
||||
PsiLambdaExpression:<T>t -> t
|
||||
PsiTypeParameterList
|
||||
PsiJavaToken:LT('<')
|
||||
PsiTypeParameter:T
|
||||
PsiIdentifier:T('T')
|
||||
PsiElement(EXTENDS_BOUND_LIST)
|
||||
<empty list>
|
||||
PsiJavaToken:GT('>')
|
||||
PsiParameterList:t
|
||||
PsiParameter:t
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiIdentifier:t('t')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiReferenceExpression:t
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:t('t')
|
||||
@@ -0,0 +1,22 @@
|
||||
PsiJavaFile:LambdaExpression14.java
|
||||
PsiLambdaExpression:(String t) -> t
|
||||
PsiParameterList:(String t)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:t
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:String
|
||||
PsiJavaCodeReferenceElement:String
|
||||
PsiIdentifier:String('String')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:t('t')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiReferenceExpression:t
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:t('t')
|
||||
@@ -0,0 +1,36 @@
|
||||
PsiJavaFile:LambdaExpression15.java
|
||||
PsiLambdaExpression:(int a, int b) -> a + b
|
||||
PsiParameterList:(int a, int b)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:a
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:a('a')
|
||||
PsiJavaToken:COMMA(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiParameter:b
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:b('b')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiBinaryExpression:a + b
|
||||
PsiReferenceExpression:a
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:a('a')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:PLUS('+')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiReferenceExpression:b
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:b('b')
|
||||
@@ -0,0 +1,20 @@
|
||||
PsiJavaFile:LambdaExpression16.java
|
||||
PsiLambdaExpression:(final int x) -> x
|
||||
PsiParameterList:(final int x)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:x
|
||||
PsiModifierList:final
|
||||
PsiKeyword:final('final')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:x('x')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiReferenceExpression:x
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:x('x')
|
||||
@@ -0,0 +1,23 @@
|
||||
PsiJavaFile:LambdaExpression17.java
|
||||
PsiLambdaExpression:(String s -> s
|
||||
PsiParameterList:(String s
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:s
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:String
|
||||
PsiJavaCodeReferenceElement:String
|
||||
PsiIdentifier:String('String')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:s('s')
|
||||
PsiErrorElement:')' expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiReferenceExpression:s
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:s('s')
|
||||
@@ -0,0 +1,34 @@
|
||||
PsiJavaFile:LambdaExpression18.java
|
||||
PsiLambdaExpression:(java.lang.String s, -> s
|
||||
PsiParameterList:(java.lang.String s,
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:s
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:java.lang.String
|
||||
PsiJavaCodeReferenceElement:java.lang.String
|
||||
PsiJavaCodeReferenceElement:java.lang
|
||||
PsiJavaCodeReferenceElement:java
|
||||
PsiIdentifier:java('java')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:DOT('.')
|
||||
PsiIdentifier:lang('lang')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:DOT('.')
|
||||
PsiIdentifier:String('String')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:s('s')
|
||||
PsiJavaToken:COMMA(',')
|
||||
PsiErrorElement:Parameter expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiReferenceExpression:s
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:s('s')
|
||||
@@ -0,0 +1,31 @@
|
||||
PsiJavaFile:LambdaExpression19.java
|
||||
PsiLambdaExpression:(@A T t) -> (null)
|
||||
PsiParameterList:(@A T t)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:t
|
||||
PsiModifierList:@A
|
||||
PsiAnnotation
|
||||
PsiJavaToken:AT('@')
|
||||
PsiJavaCodeReferenceElement:A
|
||||
PsiIdentifier:A('A')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiAnnotationParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:T
|
||||
PsiJavaCodeReferenceElement:T
|
||||
PsiIdentifier:T('T')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:t('t')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:ARROW('->')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiParenthesizedExpression:(null)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiLiteralExpression:null
|
||||
PsiJavaToken:NULL_KEYWORD('null')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
+8
@@ -134,6 +134,14 @@ public class ExpressionParserTest extends JavaParsingTestCase {
|
||||
public void testLambdaExpression9() { doParserTest("(I)p -> null"); }
|
||||
public void testLambdaExpression10() { doParserTest("(I)(p -> null)"); }
|
||||
public void testLambdaExpression11() { doParserTest("() -> { }"); }
|
||||
public void testLambdaExpression12() { doParserTest("<T>() -> new C<T>()"); }
|
||||
public void testLambdaExpression13() { doParserTest("<T>t -> t"); }
|
||||
public void testLambdaExpression14() { doParserTest("(String t) -> t"); }
|
||||
public void testLambdaExpression15() { doParserTest("(int a, int b) -> a + b"); }
|
||||
public void testLambdaExpression16() { doParserTest("(final int x) -> x"); }
|
||||
public void testLambdaExpression17() { doParserTest("(String s -> s"); }
|
||||
public void testLambdaExpression18() { doParserTest("(java.lang.String s, -> s"); }
|
||||
public void testLambdaExpression19() { doParserTest("(@A T t) -> (null)"); }
|
||||
|
||||
public void testAmbiguousLambdaExpression() { doParserTest("f( (x) < y , z > (w) -> v )"); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user