Lambda expressions support: first round

This commit is contained in:
Roman Shevchenko
2012-06-05 21:52:05 +04:00
parent b3de9ce33f
commit 6ea4c06d8f
39 changed files with 750 additions and 216 deletions
@@ -2540,7 +2540,8 @@ public class HighlightUtil {
BIN_LITERALS(LanguageLevel.JDK_1_7, "feature.binary.literals"),
UNDERSCORES(LanguageLevel.JDK_1_7, "feature.underscores.in.literals"),
EXTENSION_METHODS(LanguageLevel.JDK_1_8, "feature.extension.methods"),
METHOD_REFERENCES(LanguageLevel.JDK_1_8, "feature.method.references");
METHOD_REFERENCES(LanguageLevel.JDK_1_8, "feature.method.references"),
LAMBDA_EXPRESSIONS(LanguageLevel.JDK_1_8, "feature.lambda.expressions");
private final LanguageLevel level;
private final String key;
@@ -2617,4 +2618,13 @@ public class HighlightUtil {
final String message = "Method references type check is not yet implemented";
return HighlightInfo.createHighlightInfo(HighlightInfoType.WEAK_WARNING, expression, message);
}
@Nullable
public static HighlightInfo checkLambdaFeature(final PsiLambdaExpression expression) {
final HighlightInfo info = checkFeature(expression, Feature.LAMBDA_EXPRESSIONS);
if (info != null) return info;
// todo[r.sh] stub; remove after implementing support in TypeConversionUtil
final String message = "Lambda expressions type check is not yet implemented";
return HighlightInfo.createHighlightInfo(HighlightInfoType.WEAK_WARNING, expression, message);
}
}
@@ -234,7 +234,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkPolyadicOperatorApplicable(expression));
}
@Override public void visitBreakStatement(PsiBreakStatement statement) {
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
myHolder.add(HighlightUtil.checkLambdaFeature(expression));
}
@Override
public void visitBreakStatement(PsiBreakStatement statement) {
super.visitBreakStatement(statement);
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findExitedStatement()));
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -48,12 +48,11 @@ import java.util.*;
public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl");
@NonNls private static final String IMPL_TYPNAME_SUFFIX = "Impl";
@NonNls private static final String IMPL_SUFFIX = "Impl";
@NonNls private static final String GET_PREFIX = "get";
@NonNls private static final String IS_PREFIX = "is";
@NonNls private static final String FIND_PREFIX = "find";
@NonNls private static final String CREATE_PREFIX = "create";
@NonNls private static final String WITH_PREFIX = "with";
@NonNls private static final String SET_PREFIX = "set";
private final Project myProject;
@@ -72,9 +71,10 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
CheckUtil.checkWritable(element);
if (!SourceTreeToPsiMap.hasTreeElement(element)) return element;
return SourceTreeToPsiMap.treeElementToPsi(
new ReferenceAdjuster(myProject).process((TreeElement)element.getNode(), (flags & DO_NOT_ADD_IMPORTS) == 0,
(flags & UNCOMPLETE_CODE) != 0));
final boolean addImports = (flags & DO_NOT_ADD_IMPORTS) == 0;
final boolean incompleteCode = (flags & UNCOMPLETE_CODE) != 0;
final TreeElement reference = new ReferenceAdjuster(myProject).process((TreeElement)element.getNode(), addImports, incompleteCode);
return SourceTreeToPsiMap.treeToPsiNotNull(reference);
}
@Override
@@ -88,7 +88,8 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
@Override
public PsiElement qualifyClassReferences(@NotNull PsiElement element) {
return SourceTreeToPsiMap.treeElementToPsi(new ReferenceAdjuster(true, true).process((TreeElement)element.getNode(), false, false));
final TreeElement reference = new ReferenceAdjuster(true, true).process((TreeElement)element.getNode(), false, false);
return SourceTreeToPsiMap.treeToPsiNotNull(reference);
}
@Override
@@ -117,10 +118,10 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
@Override
public void removeRedundantImports(@NotNull final PsiJavaFile file) throws IncorrectOperationException {
final Collection<PsiImportStatementBase> redundants = findRedundantImports(file);
if (redundants == null) return;
final Collection<PsiImportStatementBase> redundant = findRedundantImports(file);
if (redundant == null) return;
for (final PsiImportStatementBase importStatement : redundants) {
for (final PsiImportStatementBase importStatement : redundant) {
final PsiJavaCodeReferenceElement ref = importStatement.getImportReference();
//Do not remove non-resolving refs
if (ref == null || ref.resolve() == null) {
@@ -140,20 +141,21 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
if( imports.length == 0 ) return null;
Set<PsiImportStatementBase> allImports = new THashSet<PsiImportStatementBase>(Arrays.asList(imports));
final Collection<PsiImportStatementBase> redundants;
final Collection<PsiImportStatementBase> redundant;
if (JspPsiUtil.isInJspFile(file)) {
// remove only duplicate imports
redundants = new THashSet<PsiImportStatementBase>(TObjectHashingStrategy.IDENTITY);
ContainerUtil.addAll(redundants, imports);
redundants.removeAll(allImports);
@SuppressWarnings("unchecked") final TObjectHashingStrategy<PsiImportStatementBase> strategy = TObjectHashingStrategy.IDENTITY;
redundant = new THashSet<PsiImportStatementBase>(strategy);
ContainerUtil.addAll(redundant, imports);
redundant.removeAll(allImports);
for (PsiImportStatementBase importStatement : imports) {
if (importStatement instanceof JspxImportStatement && ((JspxImportStatement)importStatement).isForeignFileImport()) {
redundants.remove(importStatement);
redundant.remove(importStatement);
}
}
}
else {
redundants = allImports;
redundant = allImports;
final List<PsiFile> roots = file.getViewProvider().getAllFiles();
for (PsiElement root : roots) {
root.accept(new JavaRecursiveElementWalkingVisitor() {
@@ -164,7 +166,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope();
if (resolveScope instanceof PsiImportStatementBase) {
final PsiImportStatementBase importStatementBase = (PsiImportStatementBase)resolveScope;
redundants.remove(importStatementBase);
redundant.remove(importStatementBase);
}
}
}
@@ -183,7 +185,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
});
}
}
return redundants;
return redundant;
}
@Override
@@ -334,9 +336,10 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
private void suggestNamesForCollectionInheritors(final PsiType type,
final VariableKind variableKind,
Collection<String> suggestions, boolean correctKeywords) {
final Collection<String> suggestions,
final boolean correctKeywords) {
PsiType componentType = PsiUtil.extractIterableTypeParameter(type, false);
if( componentType == null ) {
if (componentType == null) {
return;
}
String typeName = normalizeTypeName(getTypeName(componentType));
@@ -347,12 +350,11 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
@Nullable
private static String normalizeTypeName(String typeName) {
if( typeName == null )
{
if (typeName == null) {
return null;
}
if (typeName.endsWith(IMPL_TYPNAME_SUFFIX) && typeName.length() > IMPL_TYPNAME_SUFFIX.length()) {
return typeName.substring(0, typeName.length() - IMPL_TYPNAME_SUFFIX.length());
if (typeName.endsWith(IMPL_SUFFIX) && typeName.length() > IMPL_SUFFIX.length()) {
return typeName.substring(0, typeName.length() - IMPL_SUFFIX.length());
}
return typeName;
}
@@ -363,47 +365,27 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
if (type instanceof PsiClassType) {
final PsiClassType classType = (PsiClassType)type;
final String className = classType.getClassName();
if (className != null) {
return className;
}
else {
final PsiClass aClass = classType.resolve();
if (aClass instanceof PsiAnonymousClass) {
return ((PsiAnonymousClass)aClass).getBaseClassType().getClassName();
}
else {
return null;
}
}
if (className != null) return className;
final PsiClass aClass = classType.resolve();
return aClass instanceof PsiAnonymousClass ? ((PsiAnonymousClass)aClass).getBaseClassType().getClassName() : null;
}
else if (type instanceof PsiPrimitiveType) {
return type.getPresentableText();
}
else if (type instanceof PsiWildcardType) {
return getTypeName(((PsiWildcardType)type).getExtendsBound());
}
else if (type instanceof PsiIntersectionType) {
return getTypeName(((PsiIntersectionType)type).getRepresentative());
}
else if (type instanceof PsiCapturedWildcardType) {
return getTypeName(((PsiCapturedWildcardType)type).getWildcard());
}
else if (type instanceof PsiDisjunctionType) {
return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound());
}
else {
if (type instanceof PsiPrimitiveType) {
return type.getPresentableText();
}
else {
if (type instanceof PsiWildcardType) {
return getTypeName(((PsiWildcardType)type).getExtendsBound());
}
else {
if (type instanceof PsiIntersectionType) {
return getTypeName(((PsiIntersectionType)type).getRepresentative());
}
else {
if (type instanceof PsiCapturedWildcardType) {
return getTypeName(((PsiCapturedWildcardType)type).getWildcard());
}
else {
if (type instanceof PsiDisjunctionType) {
return getTypeName(((PsiDisjunctionType)type).getLeastUpperBound());
}
else {
LOG.error("Unknown type:" + type);
return null;
}
}
}
}
}
return null;
}
}
@@ -411,66 +393,40 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
private static String getLongTypeName(PsiType type) {
if (type instanceof PsiClassType) {
PsiClass aClass = ((PsiClassType)type).resolve();
if( aClass == null )
{
if (aClass == null) {
return null;
}
if (aClass instanceof PsiAnonymousClass) {
else if (aClass instanceof PsiAnonymousClass) {
PsiClass baseClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve();
if( baseClass == null )
{
return null;
}
return baseClass.getQualifiedName();
}
return aClass.getQualifiedName();
}
else {
if (type instanceof PsiArrayType) {
return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]";
return baseClass != null ? baseClass.getQualifiedName() : null;
}
else {
if (type instanceof PsiPrimitiveType) {
return type.getPresentableText();
}
else {
if (type instanceof PsiWildcardType) {
final PsiType bound = ((PsiWildcardType)type).getBound();
if (bound != null) {
return getLongTypeName(bound);
}
else {
return CommonClassNames.JAVA_LANG_OBJECT;
}
}
else {
if (type instanceof PsiCapturedWildcardType) {
final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound();
if (bound != null) {
return getLongTypeName(bound);
}
else {
return CommonClassNames.JAVA_LANG_OBJECT;
}
}
else {
if (type instanceof PsiIntersectionType) {
return getLongTypeName(((PsiIntersectionType)type).getRepresentative());
}
else {
if (type instanceof PsiDisjunctionType) {
return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound());
}
else {
LOG.error("Unknown type:" + type);
return null;
}
}
}
}
}
return aClass.getQualifiedName();
}
}
else if (type instanceof PsiArrayType) {
return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]";
}
else if (type instanceof PsiPrimitiveType) {
return type.getPresentableText();
}
else if (type instanceof PsiWildcardType) {
final PsiType bound = ((PsiWildcardType)type).getBound();
return bound != null ? getLongTypeName(bound) : CommonClassNames.JAVA_LANG_OBJECT;
}
else if (type instanceof PsiCapturedWildcardType) {
final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound();
return bound != null ? getLongTypeName(bound) : CommonClassNames.JAVA_LANG_OBJECT;
}
else if (type instanceof PsiIntersectionType) {
return getLongTypeName(((PsiIntersectionType)type).getRepresentative());
}
else if (type instanceof PsiDisjunctionType) {
return getLongTypeName(((PsiDisjunctionType)type).getLeastUpperBound());
}
else {
return null;
}
}
private static class NamesByExprInfo {
@@ -701,10 +657,10 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
break;
}
}
PsiParameter[] parms = method.getParameterList().getParameters();
if (index < parms.length) {
String name = parms[index].getName();
if (name != null && TypeConversionUtil.areTypesAssignmentCompatible(subst.substitute(parms[index].getType()), expr)) {
PsiParameter[] parameters = method.getParameterList().getParameters();
if (index < parameters.length) {
String name = parameters[index].getName();
if (name != null && TypeConversionUtil.areTypesAssignmentCompatible(subst.substitute(parameters[index].getType()), expr)) {
name = variableNameToPropertyName(name, VariableKind.PARAMETER);
String[] names = getSuggestionsByName(name, variableKind, false, correctKeywords);
if (expressions.length == 1) {
@@ -760,6 +716,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager {
buffer.append(Character.toLowerCase(c));
continue;
}
//noinspection AssignmentToForLoopParameter
i++;
if (i < name.length()) {
c = name.charAt(i);
@@ -375,4 +375,8 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
visitExpression(expression);
}
public void visitLambdaExpression(PsiLambdaExpression expression) {
visitExpression(expression);
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2000-2012 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.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a Java lambda expression.
*/
public interface PsiLambdaExpression extends PsiExpression {
/**
* Returns this lambda expression's parameter list.
*
* @return parameter list.
*/
@NotNull
PsiParameterList getParameterList();
/**
* Returns PSI element representing lambda expression body: {@link PsiCodeBlock}, {@link PsiExpression}, or null if none.
*
* @return lambda expression body.
*/
@Nullable
PsiElement getBody();
}
@@ -0,0 +1,73 @@
/*
* Copyright 2000-2012 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.psi;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* A type which represents a function denoted by a lambda expression.
*/
public class PsiLambdaExpressionType extends PsiType {
private final PsiLambdaExpression myExpression;
public PsiLambdaExpressionType(PsiLambdaExpression expression) {
super(PsiAnnotation.EMPTY_ARRAY);
myExpression = expression;
}
@Override
public String getPresentableText() {
return "<lambda expression>";
}
@Override
public String getCanonicalText() {
return getPresentableText();
}
@Override
public String getInternalCanonicalText() {
return getCanonicalText();
}
@Override
public boolean isValid() {
return myExpression.isValid();
}
@Override
public boolean equalsToText(@NonNls final String text) {
return false;
}
@Override
public <A> A accept(@NotNull final PsiTypeVisitor<A> visitor) {
return visitor.visitType(this);
}
@Override
public GlobalSearchScope getResolveScope() {
return null;
}
@NotNull
@Override
public PsiType[] getSuperTypes() {
return PsiType.EMPTY_ARRAY;
}
}
@@ -0,0 +1,73 @@
/*
* Copyright 2000-2012 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.psi;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* A type which represents an omitted type for parameter of lambda expression.
*/
public class PsiLambdaParameterType extends PsiType {
private final PsiParameter myParameter;
public PsiLambdaParameterType(PsiParameter parameter) {
super(PsiAnnotation.EMPTY_ARRAY);
myParameter = parameter;
}
@Override
public String getPresentableText() {
return "<lambda parameter>";
}
@Override
public String getCanonicalText() {
return getPresentableText();
}
@Override
public String getInternalCanonicalText() {
return getCanonicalText();
}
@Override
public boolean isValid() {
return myParameter.isValid();
}
@Override
public boolean equalsToText(@NonNls final String text) {
return false;
}
@Override
public <A> A accept(@NotNull final PsiTypeVisitor<A> visitor) {
return visitor.visitType(this);
}
@Override
public GlobalSearchScope getResolveScope() {
return null;
}
@NotNull
@Override
public PsiType[] getSuperTypes() {
return PsiType.EMPTY_ARRAY;
}
}
@@ -57,7 +57,7 @@ public class PsiMethodReferenceType extends PsiType {
@Override
public <A> A accept(@NotNull final PsiTypeVisitor<A> visitor) {
return visitor.visitMethodReferenceType(this);
return visitor.visitType(this);
}
@Override
@@ -56,8 +56,4 @@ public class PsiTypeVisitor<A> {
public A visitDiamondType(PsiDiamondType diamondType) {
return visitType(diamondType);
}
public A visitMethodReferenceType(PsiMethodReferenceType methodReferenceType) {
return visitType(methodReferenceType);
}
}
@@ -644,6 +644,7 @@ public class TypeConversionUtil {
// todo[r.sh] implement
if (right instanceof PsiMethodReferenceType && left instanceof PsiClassType) return true;
if (right instanceof PsiLambdaExpressionType && left instanceof PsiClassType) return true;
if (left instanceof PsiIntersectionType) {
PsiType[] conjuncts = ((PsiIntersectionType)left).getConjuncts();
@@ -43,6 +43,8 @@ public class DeclarationParser {
JavaTokenType.IDENTIFIER, JavaTokenType.COMMA, JavaTokenType.EXTENDS_KEYWORD, JavaTokenType.IMPLEMENTS_KEYWORD);
private static final TokenSet APPEND_TO_METHOD_SET = TokenSet.create(
JavaTokenType.IDENTIFIER, JavaTokenType.COMMA, JavaTokenType.THROWS_KEYWORD);
private static final TokenSet PARAM_LIST_STOPPERS = TokenSet.create(
JavaTokenType.RPARENTH, JavaTokenType.LBRACE, JavaTokenType.ARROW);
private static final String WHITESPACES = "\n\r \t";
private static final String LINE_ENDS = "\n\r";
@@ -456,19 +458,28 @@ public class DeclarationParser {
@NotNull
public PsiBuilder.Marker parseParameterList(final PsiBuilder builder) {
return parseElementList(builder, false);
return parseElementList(builder, ListType.NORMAL);
}
@NotNull
public PsiBuilder.Marker parseResourceList(final PsiBuilder builder) {
return parseElementList(builder, true);
return parseElementList(builder, ListType.RESOURCE);
}
@NotNull
private PsiBuilder.Marker parseElementList(final PsiBuilder builder, final boolean resources) {
assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType();
public PsiBuilder.Marker parseLambdaParameterList(final PsiBuilder builder, final boolean typed) {
return parseElementList(builder, typed ? ListType.LAMBDA_TYPED : ListType.LAMBDA_UNTYPED);
}
private enum ListType { NORMAL, RESOURCE, LAMBDA_TYPED, LAMBDA_UNTYPED }
@NotNull
private PsiBuilder.Marker parseElementList(final PsiBuilder builder, final ListType type) {
final boolean lambda = (type == ListType.LAMBDA_TYPED || type == ListType.LAMBDA_UNTYPED);
final boolean resources = (type == ListType.RESOURCE);
final PsiBuilder.Marker elementList = builder.mark();
builder.advanceLexer();
final boolean leftParenth = expect(builder, JavaTokenType.LPARENTH);
assert lambda || leftParenth : builder.getTokenType();
final IElementType delimiter = resources ? JavaTokenType.SEMICOLON : JavaTokenType.COMMA;
final String noDelimiterMsg = resources ? "expected.semicolon" : "expected.comma";
@@ -480,10 +491,11 @@ public class DeclarationParser {
boolean noElements = true;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null || tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE) {
if (tokenType == null || PARAM_LIST_STOPPERS.contains(tokenType)) {
final boolean noLastElement = !delimiterExpected && (!noElements && !resources || noElements && resources);
if (noLastElement) {
error(builder, JavaErrorMessages.message("expected.identifier.or.type"));
final String key = lambda ? "expected.parameter" : "expected.identifier.or.type";
error(builder, JavaErrorMessages.message(key));
}
if (tokenType == JavaTokenType.RPARENTH) {
if (invalidElements != null) {
@@ -498,7 +510,9 @@ public class DeclarationParser {
invalidElements.error(errorMessage);
}
invalidElements = null;
error(builder, JavaErrorMessages.message("expected.rparen"));
if (leftParenth) {
error(builder, JavaErrorMessages.message("expected.rparen"));
}
}
}
break;
@@ -516,7 +530,9 @@ public class DeclarationParser {
}
}
else {
final PsiBuilder.Marker listElement = resources ? parseResource(builder) : parseParameter(builder, true, false);
final PsiBuilder.Marker listElement = resources ? parseResource(builder) :
lambda ? parseLambdaParameter(builder, type == ListType.LAMBDA_TYPED) :
parseParameter(builder, true, false);
if (listElement != null) {
delimiterExpected = true;
if (invalidElements != null) {
@@ -562,36 +578,45 @@ public class DeclarationParser {
@Nullable
public PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) {
return parseListElement(builder, ellipsis, disjunctiveType, false);
return parseListElement(builder, true, ellipsis, disjunctiveType, false);
}
@Nullable
public PsiBuilder.Marker parseResource(final PsiBuilder builder) {
return parseListElement(builder, false, false, true);
return parseListElement(builder, true, false, false, true);
}
@Nullable
public PsiBuilder.Marker parseLambdaParameter(final PsiBuilder builder, final boolean typed) {
return parseListElement(builder, typed, true, false, false);
}
@Nullable
private PsiBuilder.Marker parseListElement(final PsiBuilder builder,
final boolean ellipsis,
final boolean disjunctiveType,
final boolean resource) {
final boolean typed,
final boolean ellipsis,
final boolean disjunctiveType,
final boolean resource) {
final PsiBuilder.Marker param = builder.mark();
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS;
final ReferenceParser.TypeInfo typeInfo = myParser.getReferenceParser().parseTypeInfo(builder, flags);
ReferenceParser.TypeInfo typeInfo = null;
if (typed) {
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS;
typeInfo = myParser.getReferenceParser().parseTypeInfo(builder, flags);
if (typeInfo == null) {
if (modListInfo.second) {
param.rollbackTo();
return null;
}
else {
error(builder, JavaErrorMessages.message("expected.type"));
emptyElement(builder, JavaElementType.TYPE);
if (typeInfo == null) {
if (modListInfo.second) {
param.rollbackTo();
return null;
}
else {
error(builder, JavaErrorMessages.message("expected.type"));
emptyElement(builder, JavaElementType.TYPE);
}
}
}
@@ -514,6 +514,19 @@ public class ExpressionParser {
if (tokenType == JavaTokenType.LPARENTH) {
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);
@@ -554,6 +567,10 @@ public class ExpressionParser {
}
if (tokenType == JavaTokenType.IDENTIFIER) {
if (builder.lookAhead(1) == JavaTokenType.ARROW) {
return parseLambdaExpression(builder, builder.mark(), false);
}
final PsiBuilder.Marker refExpr;
if (annotation != null) {
final PsiBuilder.Marker refParam = annotation.precede();
@@ -810,6 +827,32 @@ 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);
}
@NotNull
private PsiBuilder.Marker parseLambdaExpressionFromArrow(final PsiBuilder builder, final PsiBuilder.Marker start) {
builder.advanceLexer();
final PsiBuilder.Marker body;
if (builder.getTokenType() == JavaTokenType.LBRACE) {
body = myParser.getStatementParser().parseCodeBlock(builder);
}
else {
body = parse(builder);
}
if (body == null) {
builder.error(JavaErrorMessages.message("expected.lbrace"));
}
start.done(JavaElementType.LAMBDA_EXPRESSION);
return start;
}
@NotNull
public PsiBuilder.Marker parseArgumentList(final PsiBuilder builder) {
final PsiBuilder.Marker list = builder.mark();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -17,9 +17,7 @@ package com.intellij.psi.impl.source;
import com.intellij.lang.LighterAST;
import com.intellij.lang.LighterASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.impl.ASTNodeBuilder;
import com.intellij.lang.impl.PsiBuilderImpl;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
@@ -32,7 +30,6 @@ import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.io.StringRef;
public class JavaLightStubBuilder extends LightStubBuilder {
@Override
protected StubElement createStubForFile(final PsiFile file, final LighterAST tree) {
@@ -53,20 +50,17 @@ public class JavaLightStubBuilder extends LightStubBuilder {
@Override
public boolean skipChildProcessingWhenBuildingStubs(final IElementType nodeType, final IElementType childType) {
return childType == JavaElementType.PARAMETER && nodeType != JavaElementType.PARAMETER_LIST;
return childType == JavaElementType.PARAMETER && nodeType != JavaElementType.PARAMETER_LIST ||
childType == JavaElementType.PARAMETER_LIST && nodeType == JavaElementType.LAMBDA_EXPRESSION;
}
static int totalMethods;
static int nonexpandedMethods;
@Override
public boolean skipChildProcessingWhenBuildingStubs(LightStubBuilder builder,
LighterAST tree,
LighterASTNode parent,
LighterASTNode child) {
public boolean skipChildProcessingWhenBuildingStubs(final LightStubBuilder builder,
final LighterAST tree,
final LighterASTNode parent,
final LighterASTNode child) {
if (child.getTokenType() == JavaElementType.CODE_BLOCK) {
if (child instanceof ASTNodeBuilder.ASTUnparsedNodeMarker) {
++totalMethods;
ASTNodeBuilder.ASTUnparsedNodeMarker nodeMarker = (ASTNodeBuilder.ASTUnparsedNodeMarker)child;
final ASTNodeBuilder nodeBuilder = nodeMarker.getBuilder();
final int endLexemIndex = nodeMarker.getEndLexemIndex();
@@ -89,7 +83,6 @@ public class JavaLightStubBuilder extends LightStubBuilder {
}
}
++nonexpandedMethods;
return true;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -167,7 +167,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
}
myCachedType = null;
return JavaSharedImplUtil.getType(this);
return JavaSharedImplUtil.getType(getTypeElement(), getNameIdentifier(), this);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -118,7 +118,13 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
}
myCachedType = null;
return JavaSharedImplUtil.getType(this);
final PsiTypeElement typeElement = getTypeElement();
if (typeElement == null && isLambdaParameter()) {
return new PsiLambdaParameterType(this);
}
return JavaSharedImplUtil.getType(typeElement, getNameIdentifier(), this);
}
@Override
@@ -134,13 +140,21 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
return null;
}
}
PsiTypeElement typeElement = getTypeElement();
PsiIdentifier nameIdentifier = getNameIdentifier();
return JavaSharedImplUtil.getTypeNoResolve(typeElement, nameIdentifier, this);
final PsiTypeElement typeElement = getTypeElement();
if (typeElement == null && isLambdaParameter()) {
return new PsiLambdaParameterType(this);
}
return JavaSharedImplUtil.getTypeNoResolve(typeElement, getNameIdentifier(), this);
}
private boolean isLambdaParameter() {
final PsiElement parent = getParent();
return parent instanceof PsiParameterList && parent.getParent() instanceof PsiLambdaExpression;
}
@Override
@NotNull
public PsiTypeElement getTypeElement() {
return (PsiTypeElement)getNode().findChildByRoleAsPsiElement(ChildRole.TYPE);
}
@@ -233,7 +247,8 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
}
myCachedType = null;
return SourceTreeToPsiMap.psiToTreeNotNull(getTypeElement()).findChildByType(JavaTokenType.ELLIPSIS) != null;
final PsiTypeElement typeElement = getTypeElement();
return typeElement != null && SourceTreeToPsiMap.psiToTreeNotNull(typeElement).findChildByType(JavaTokenType.ELLIPSIS) != null;
}
@Override
@@ -54,7 +54,7 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, JavaElemen
REFERENCE_EXPRESSION, LITERAL_EXPRESSION, THIS_EXPRESSION, SUPER_EXPRESSION, PARENTH_EXPRESSION, METHOD_CALL_EXPRESSION,
TYPE_CAST_EXPRESSION, PREFIX_EXPRESSION, POSTFIX_EXPRESSION, BINARY_EXPRESSION, POLYADIC_EXPRESSION, CONDITIONAL_EXPRESSION,
ASSIGNMENT_EXPRESSION, NEW_EXPRESSION, ARRAY_ACCESS_EXPRESSION, ARRAY_INITIALIZER_EXPRESSION, INSTANCE_OF_EXPRESSION,
CLASS_OBJECT_ACCESS_EXPRESSION, METHOD_REF_EXPRESSION, EMPTY_EXPRESSION);
CLASS_OBJECT_ACCESS_EXPRESSION, METHOD_REF_EXPRESSION, LAMBDA_EXPRESSION, EMPTY_EXPRESSION);
TokenSet ANNOTATION_MEMBER_VALUE_BIT_SET = TokenSet.orSet(EXPRESSION_BIT_SET,
TokenSet.create(ANNOTATION, ANNOTATION_ARRAY_INITIALIZER));
@@ -105,6 +105,7 @@ public interface JavaElementType {
IElementType CLASS_OBJECT_ACCESS_EXPRESSION = new JavaCompositeElementType("CLASS_OBJECT_ACCESS_EXPRESSION", PsiClassObjectAccessExpressionImpl.class);
IElementType EMPTY_EXPRESSION = new JavaCompositeElementType("EMPTY_EXPRESSION", PsiEmptyExpressionImpl.class, true);
IElementType METHOD_REF_EXPRESSION = new JavaCompositeElementType("METHOD_REF_EXPRESSION", PsiMethodReferenceExpressionImpl.class);
IElementType LAMBDA_EXPRESSION = new JavaCompositeElementType("LAMBDA_EXPRESSION", PsiLambdaExpressionImpl.class);
IElementType EXPRESSION_LIST = new JavaCompositeElementType("EXPRESSION_LIST", PsiExpressionListImpl.class, true);
IElementType EMPTY_STATEMENT = new JavaCompositeElementType("EMPTY_STATEMENT", PsiEmptyStatementImpl.class);
IElementType BLOCK_STATEMENT = new JavaCompositeElementType("BLOCK_STATEMENT", PsiBlockStatementImpl.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -32,30 +32,10 @@ import org.jetbrains.annotations.NotNull;
public class JavaSharedImplUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.JavaSharedImplUtil");
private JavaSharedImplUtil() {
}
public static PsiType getType(PsiVariable variable) {
PsiTypeElement typeElement = variable.getTypeElement();
PsiIdentifier nameIdentifier = variable.getNameIdentifier();
return getType(typeElement, nameIdentifier, variable);
}
private JavaSharedImplUtil() { }
public static PsiType getType(@NotNull PsiTypeElement typeElement, @NotNull PsiElement anchor, @NotNull PsiElement context) {
int cStyleArrayCount = 0;
ASTNode name = SourceTreeToPsiMap.psiElementToTree(anchor);
for (ASTNode child = name.getTreeNext(); child != null; child = child.getTreeNext()) {
IElementType i = child.getElementType();
if (i == JavaTokenType.LBRACKET) {
cStyleArrayCount++;
}
else if (i != JavaTokenType.RBRACKET && i != TokenType.WHITE_SPACE &&
i != JavaTokenType.C_STYLE_COMMENT &&
i != JavaDocElementType.DOC_COMMENT &&
i != JavaTokenType.END_OF_LINE_COMMENT) {
break;
}
}
int cStyleArrayCount = countBrackets(anchor);
PsiType type;
if (typeElement instanceof PsiTypeElementImpl) {
type = ((PsiTypeElementImpl)typeElement).getDetachedType(context);
@@ -63,33 +43,34 @@ public class JavaSharedImplUtil {
else {
type = typeElement.getType();
}
for (int i = 0; i < cStyleArrayCount; i++) {
type = type.createArrayType();
}
return type;
}
public static PsiType getTypeNoResolve(@NotNull PsiTypeElement typeElement, @NotNull PsiElement anchor, @NotNull PsiElement context) {
int cStyleArrayCount = countBrackets(anchor);
PsiType type = typeElement.getTypeNoResolve(context);
for (int i = 0; i < cStyleArrayCount; i++) {
type = type.createArrayType();
}
return type;
}
private static int countBrackets(PsiElement anchor) {
int cStyleArrayCount = 0;
ASTNode name = SourceTreeToPsiMap.psiElementToTree(anchor);
ASTNode name = SourceTreeToPsiMap.psiToTreeNotNull(anchor);
for (ASTNode child = name.getTreeNext(); child != null; child = child.getTreeNext()) {
IElementType i = child.getElementType();
if (i == JavaTokenType.LBRACKET) {
cStyleArrayCount++;
}
else if (i != JavaTokenType.RBRACKET && i != TokenType.WHITE_SPACE &&
i != JavaTokenType.C_STYLE_COMMENT &&
i != JavaDocElementType.DOC_COMMENT &&
i != JavaTokenType.END_OF_LINE_COMMENT) {
else if (i != JavaTokenType.RBRACKET && !ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(i)) {
break;
}
}
PsiType type = typeElement.getTypeNoResolve(context);
for (int i = 0; i < cStyleArrayCount; i++) {
type = type.createArrayType();
}
return type;
return cStyleArrayCount;
}
public static void normalizeBrackets(PsiVariable variable) {
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2012 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.psi.impl.source.tree.java;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements PsiLambdaExpression {
public PsiLambdaExpressionImpl() {
super(JavaElementType.LAMBDA_EXPRESSION);
}
@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);
}
@Override
public PsiType getType() {
return new PsiLambdaExpressionType(this);
}
@Override
public void accept(@NotNull final PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitLambdaExpression(this);
}
else {
visitor.visitElement(this);
}
}
@Override
public String toString() {
return "PsiLambdaExpression:" + getText();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -95,7 +95,7 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca
@Override
@NotNull
public final PsiType getType() {
return JavaSharedImplUtil.getType(this);
return JavaSharedImplUtil.getType(getTypeElement(), getNameIdentifier(), this);
}
@Override
@@ -158,6 +158,7 @@ public class ReplaceExpressionUtil {
i == JavaElementType.ARRAY_INITIALIZER_EXPRESSION ||
i == JavaElementType.JAVA_CODE_REFERENCE ||
i == JavaElementType.METHOD_REF_EXPRESSION ||
i == JavaElementType.LAMBDA_EXPRESSION ||
i == JavaElementType.EMPTY_EXPRESSION) {
return 14;
}
@@ -354,4 +354,5 @@ feature.binary.literals=Binary literals
feature.underscores.in.literals=Underscores in literals
feature.extension.methods=Extension methods
feature.method.references=Method references
feature.lambda.expressions=Lambda expressions
insufficient.language.level={0} are not supported at this language level
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.*;
import java.util.*;
@@ -38,7 +39,8 @@ class UnsupportedFeatures {
try <error descr="Try-with-resources are not supported at this language level">(Reader r = new FileReader("/dev/null"))</error> { }
I i = <error descr="Method references are not supported at this language level">UnsupportedFeatures::m</error>;
I i1 = <error descr="Method references are not supported at this language level">UnsupportedFeatures::m</error>;
I i2 = <error descr="Lambda expressions are not supported at this language level">() -> { }</error>;
}
interface I {
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2012 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.
*/
class C {
interface Simplest {
void m();
}
void simplest() { }
void use(Simplest s) { }
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>);
}
}
@@ -0,0 +1,12 @@
PsiJavaFile:LambdaExpression0.java
PsiLambdaExpression:p -> 42
PsiParameterList:p
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:42
PsiJavaToken:INTEGER_LITERAL('42')
@@ -0,0 +1,12 @@
PsiJavaFile:LambdaExpression1.java
PsiLambdaExpression:p ->
PsiParameterList:p
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiErrorElement:'{' expected
<empty list>
PsiWhiteSpace(' ')
@@ -0,0 +1,23 @@
PsiJavaFile:LambdaExpression10.java
PsiTypeCastExpression:(I)(p -> null)
PsiJavaToken:LPARENTH('(')
PsiTypeElement:I
PsiJavaCodeReferenceElement:I
PsiIdentifier:I('I')
PsiReferenceParameterList
<empty list>
PsiJavaToken:RPARENTH(')')
PsiParenthesizedExpression:(p -> null)
PsiJavaToken:LPARENTH('(')
PsiLambdaExpression:p -> null
PsiParameterList:p
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,12 @@
PsiJavaFile:LambdaExpression11.java
PsiLambdaExpression:() -> { }
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,14 @@
PsiJavaFile:LambdaExpression2.java
PsiLambdaExpression:p -> {
PsiParameterList:p
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiErrorElement:'}' expected
<empty list>
@@ -0,0 +1,16 @@
PsiJavaFile:LambdaExpression3.java
PsiLambdaExpression:(p) -> { }
PsiParameterList:(p)
PsiJavaToken:LPARENTH('(')
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,20 @@
PsiJavaFile:LambdaExpression4.java
PsiLambdaExpression:(p, v) -> null
PsiParameterList:(p, v)
PsiJavaToken:LPARENTH('(')
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiParameter:v
PsiModifierList:
<empty list>
PsiIdentifier:v('v')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
@@ -0,0 +1,21 @@
PsiJavaFile:LambdaExpression5.java
PsiLambdaExpression:(p, v -> null
PsiParameterList:(p, v
PsiJavaToken:LPARENTH('(')
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiParameter:v
PsiModifierList:
<empty list>
PsiIdentifier:v('v')
PsiErrorElement:')' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
@@ -0,0 +1,22 @@
PsiJavaFile:LambdaExpression6.java
PsiLambdaExpression:(p, v, -> null
PsiParameterList:(p, v,
PsiJavaToken:LPARENTH('(')
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiParameter:v
PsiModifierList:
<empty list>
PsiIdentifier:v('v')
PsiJavaToken:COMMA(',')
PsiErrorElement:Parameter expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
@@ -0,0 +1,15 @@
PsiJavaFile:LambdaExpression7.java
PsiParenthesizedExpression:(p -> null)
PsiJavaToken:LPARENTH('(')
PsiLambdaExpression:p -> null
PsiParameterList:p
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,22 @@
PsiJavaFile:LambdaExpression8.java
PsiTypeCastExpression:(I)(p) -> null
PsiJavaToken:LPARENTH('(')
PsiTypeElement:I
PsiJavaCodeReferenceElement:I
PsiIdentifier:I('I')
PsiReferenceParameterList
<empty list>
PsiJavaToken:RPARENTH(')')
PsiLambdaExpression:(p) -> null
PsiParameterList:(p)
PsiJavaToken:LPARENTH('(')
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
@@ -0,0 +1,20 @@
PsiJavaFile:LambdaExpression9.java
PsiTypeCastExpression:(I)p -> null
PsiJavaToken:LPARENTH('(')
PsiTypeElement:I
PsiJavaCodeReferenceElement:I
PsiIdentifier:I('I')
PsiReferenceParameterList
<empty list>
PsiJavaToken:RPARENTH(')')
PsiLambdaExpression:p -> null
PsiParameterList:p
PsiParameter:p
PsiModifierList:
<empty list>
PsiIdentifier:p('p')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
@@ -146,4 +146,5 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
public void testClassLiteral() throws Exception { doTest(false, false); }
public void testExtensionMethods() throws Exception { doTest(false, false); }
public void testMethodReferences() throws Exception { doTest(false, true, false); }
public void testLambdaExpressions() throws Exception { doTest(false, true, false); }
}
@@ -122,6 +122,19 @@ public class ExpressionParserTest extends JavaParsingTestCase {
public void testMethodRef4() { doParserTest("int[]::clone"); }
public void testMethodRef5() { doParserTest("(f ? list.map(String::length) : Collections.emptyList())::iterator"); }
public void testLambdaExpression0() { doParserTest("p -> 42"); }
public void testLambdaExpression1() { doParserTest("p -> "); }
public void testLambdaExpression2() { doParserTest("p -> {"); }
public void testLambdaExpression3() { doParserTest("(p) -> { }"); }
public void testLambdaExpression4() { doParserTest("(p, v) -> null"); }
public void testLambdaExpression5() { doParserTest("(p, v -> null"); }
public void testLambdaExpression6() { doParserTest("(p, v, -> null"); }
public void testLambdaExpression7() { doParserTest("(p -> null)"); }
public void testLambdaExpression8() { doParserTest("(I)(p) -> null"); }
public void testLambdaExpression9() { doParserTest("(I)p -> null"); }
public void testLambdaExpression10() { doParserTest("(I)(p -> null)"); }
public void testLambdaExpression11() { doParserTest("() -> { }"); }
private void doParserTest(@NonNls final String text) {
doParserTest(text, new MyTestParser());
}
@@ -221,6 +221,7 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
doTest("class C { {\n" +
" new O.P() { };\n" +
" X.new Y() { };\n" +
" f(p -> new R() { });\n" +
"} }",
"PsiJavaFileStub []\n" +
@@ -233,7 +234,8 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
" CLASS_INITIALIZER:PsiClassInitializerStub\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" +
" ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=O.P]\n" +
" ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Y inqualifnew]\n");
" ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Y inqualifnew]\n" +
" ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=R]\n");
}
public void testEnums() {