summaryrefslogtreecommitdiff
path: root/java/java-psi-api/src/com/intellij
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-psi-api/src/com/intellij')
-rw-r--r--java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java6
-rw-r--r--java/java-psi-api/src/com/intellij/psi/CommonClassNames.java98
-rw-r--r--java/java-psi-api/src/com/intellij/psi/HierarchicalMethodSignature.java11
-rw-r--r--java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java17
-rw-r--r--java/java-psi-api/src/com/intellij/psi/LambdaUtil.java187
-rw-r--r--java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java4
-rw-r--r--java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java86
-rw-r--r--java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java26
-rw-r--r--java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java24
-rw-r--r--java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java1
-rw-r--r--java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java16
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java10
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java49
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java37
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java18
15 files changed, 343 insertions, 247 deletions
diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java
index 0ca2c3709680..d67dec73361f 100644
--- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java
+++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java
@@ -293,9 +293,13 @@ public class AnnotationUtil {
}
public static boolean isAnnotatingApplicable(@NotNull PsiElement elt) {
+ return isAnnotatingApplicable(elt, NullableNotNullManager.getInstance(elt.getProject()).getDefaultNullable());
+ }
+
+ public static boolean isAnnotatingApplicable(@NotNull PsiElement elt, final String annotationFQN) {
final Project project = elt.getProject();
return PsiUtil.isLanguageLevel5OrHigher(elt) &&
- JavaPsiFacade.getInstance(project).findClass(NullableNotNullManager.getInstance(project).getDefaultNullable(), elt.getResolveScope()) != null;
+ JavaPsiFacade.getInstance(project).findClass(annotationFQN, elt.getResolveScope()) != null;
}
public static boolean isJetbrainsAnnotation(@NonNls final String simpleName) {
diff --git a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java
deleted file mode 100644
index 8ca2c256b23b..000000000000
--- a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2000-2013 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.NonNls;
-
-/**
- * @author peter
- */
-public interface CommonClassNames {
- @NonNls String DEFAULT_PACKAGE = "java.lang";
-
- @NonNls String JAVA_LANG_OBJECT = "java.lang.Object";
- @NonNls String JAVA_LANG_CLASS = "java.lang.Class";
- @NonNls String JAVA_LANG_OVERRIDE = "java.lang.Override";
- @NonNls String JAVA_LANG_ENUM = "java.lang.Enum";
- @NonNls String JAVA_LANG_VOID = "java.lang.Void";
-
- @NonNls String JAVA_LANG_THROWABLE = "java.lang.Throwable";
- @NonNls String JAVA_LANG_EXCEPTION = "java.lang.Exception";
- @NonNls String JAVA_LANG_ERROR = "java.lang.Error";
- @NonNls String JAVA_LANG_RUNTIME_EXCEPTION = "java.lang.RuntimeException";
- @NonNls String JAVA_LANG_AUTO_CLOSEABLE = "java.lang.AutoCloseable";
-
- @NonNls String JAVA_LANG_ITERABLE = "java.lang.Iterable";
- @NonNls String JAVA_UTIL_ITERATOR = "java.util.Iterator";
-
- @NonNls String JAVA_LANG_DEPRECATED = "java.lang.Deprecated";
-
- @NonNls String JAVA_LANG_ANNOTATION_INHERITED = "java.lang.annotation.Inherited";
- @NonNls String JAVA_LANG_ANNOTATION_ANNOTATION = "java.lang.annotation.Annotation";
-
- @NonNls String JAVA_LANG_REFLECT_ARRAY = "java.lang.reflect.Array";
-
- @NonNls String JAVA_UTIL_ARRAYS = "java.util.Arrays";
- @NonNls String JAVA_UTIL_COLLECTIONS = "java.util.Collections";
- @NonNls String JAVA_UTIL_COLLECTION = "java.util.Collection";
- @NonNls String JAVA_UTIL_MAP = "java.util.Map";
- @NonNls String JAVA_UTIL_LIST = "java.util.List";
- @NonNls String JAVA_UTIL_SET = "java.util.Set";
- @NonNls String JAVA_UTIL_PROPERTIES = "java.util.Properties";
- @NonNls String JAVA_UTIL_PROPERTY_RESOURCE_BUNDLE = "java.util.PropertyResourceBundle";
- @NonNls String JAVA_UTIL_DATE = "java.util.Date";
- @NonNls String JAVA_UTIL_CALENDAR = "java.util.Calendar";
- @NonNls String JAVA_UTIL_DICTIONARY = "java.util.Dictionary";
- @NonNls String JAVA_UTIL_COMPARATOR = "java.util.Comparator";
-
- /** @deprecated not that common (to remove in IDEA 13) */
- @SuppressWarnings("UnusedDeclaration") @NonNls String JAVA_SQL_DATE = "java.sql.Date";
-
- @NonNls String JAVA_IO_SERIALIZABLE = "java.io.Serializable";
- @NonNls String JAVA_IO_EXTERNALIZABLE = "java.io.Externalizable";
-
- @NonNls String JAVA_LANG_STRING = "java.lang.String";
- @NonNls String JAVA_LANG_STRING_SHORT = "String";
- @NonNls String JAVA_LANG_NUMBER = "java.lang.Number";
- @NonNls String JAVA_LANG_BOOLEAN = "java.lang.Boolean";
- @NonNls String JAVA_LANG_BYTE = "java.lang.Byte";
- @NonNls String JAVA_LANG_SHORT = "java.lang.Short";
- @NonNls String JAVA_LANG_INTEGER = "java.lang.Integer";
- @NonNls String JAVA_LANG_LONG = "java.lang.Long";
- @NonNls String JAVA_LANG_FLOAT = "java.lang.Float";
- @NonNls String JAVA_LANG_DOUBLE = "java.lang.Double";
- @NonNls String JAVA_LANG_CHARACTER = "java.lang.Character";
-
- @NonNls String JAVA_LANG_STRING_BUFFER = "java.lang.StringBuffer";
- @NonNls String JAVA_LANG_STRING_BUILDER = "java.lang.StringBuilder";
- @NonNls String JAVA_LANG_ABSTRACT_STRING_BUILDER = "java.lang.AbstractStringBuilder";
-
- @NonNls String JAVA_LANG_CLONEABLE = "java.lang.Cloneable";
- @NonNls String JAVA_LANG_COMPARABLE = "java.lang.Comparable";
- @NonNls String CLASS_FILE_EXTENSION = ".class";
-
- @NonNls String JAVA_UTIL_CONCURRENT_FUTURE = "java.util.concurrent.Future";
- @NonNls String JAVA_UTIL_ARRAY_LIST = "java.util.ArrayList";
-
- @NonNls String JAVA_LANG_INVOKE_MH_POLYMORPHIC = "java.lang.invoke.MethodHandle.PolymorphicSignature";
- @NonNls String TARGET_ANNOTATION_FQ_NAME = "java.lang.annotation.Target";
- @NonNls String JAVA_LANG_RUNNABLE = "java.lang.Runnable";
- @NonNls String JAVA_IO_FILE = "java.io.File";
- @NonNls String JAVA_LANG_ASSERTION_ERROR = "java.lang.AssertionError";
- @NonNls String JAVA_UTIL_CONCURRENT_CALLABLE = "java.util.concurrent.Callable";
- @NonNls String JAVA_UTIL_MAP_ENTRY = "java.util.Map.Entry";
- @NonNls String JAVA_UTIL_HASH_MAP = "java.util.HashMap";
-}
diff --git a/java/java-psi-api/src/com/intellij/psi/HierarchicalMethodSignature.java b/java/java-psi-api/src/com/intellij/psi/HierarchicalMethodSignature.java
index 3c920d38a5e6..8de679aae04a 100644
--- a/java/java-psi-api/src/com/intellij/psi/HierarchicalMethodSignature.java
+++ b/java/java-psi-api/src/com/intellij/psi/HierarchicalMethodSignature.java
@@ -29,9 +29,18 @@ import java.util.List;
public abstract class HierarchicalMethodSignature extends MethodSignatureBackedByPsiMethod {
public HierarchicalMethodSignature(@NotNull MethodSignatureBackedByPsiMethod signature) {
super(signature.getMethod(), signature.getSubstitutor(), signature.isRaw(),
- signature.getParameterTypes(), signature.getTypeParameters());
+ getParameterTypes(signature.getMethod()), signature.getTypeParameters());
}
+ private static PsiType[] getParameterTypes(PsiMethod method) {
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ final PsiType[] paramTypes = new PsiType[parameters.length];
+ for (int i = 0; i < paramTypes.length; i++) {
+ paramTypes[i] = parameters[i].getType();
+ }
+ return paramTypes;
+ }
+
/**
* Returns the list of super method signatures for the specified signature.
*
diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java
index 6d7df2d11d6b..07cc842b7e05 100644
--- a/java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java
@@ -32,7 +32,12 @@ public class LambdaHighlightingUtil {
final List<MethodSignature> signatures = LambdaUtil.findFunctionCandidates(psiClass);
if (signatures == null) return "Target type of a lambda conversion must be an interface";
if (signatures.isEmpty()) return "No target method found";
- return signatures.size() == 1 ? null : "Multiple non-overriding abstract methods found";
+ if (signatures.size() == 1) {
+ final MethodSignature functionalMethod = signatures.get(0);
+ if (functionalMethod.getTypeParameters().length > 0) return "Target method is generic";
+ return null;
+ }
+ return "Multiple non-overriding abstract methods found";
}
public static String checkReturnTypeCompatible(PsiLambdaExpression lambdaExpression, PsiType functionalInterfaceReturnType) {
@@ -40,11 +45,11 @@ public class LambdaHighlightingUtil {
final PsiElement body = lambdaExpression.getBody();
if (body instanceof PsiCodeBlock) {
if (!LambdaUtil.getReturnExpressions(lambdaExpression).isEmpty()) return "Unexpected return value";
- } else if (body instanceof PsiExpression) {
- /*final PsiType type = ((PsiExpression)body).getType();
+ } else if (body instanceof PsiReferenceExpression || body instanceof PsiLiteralExpression) {
+ final PsiType type = ((PsiExpression)body).getType();
if (type != PsiType.VOID) {
return "Incompatible return type " + (type == PsiType.NULL || type == null ? "<null>" : type.getPresentableText()) +" in lambda expression";
- }*/
+ }
}
} else if (functionalInterfaceReturnType != null) {
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
@@ -98,12 +103,12 @@ public class LambdaHighlightingUtil {
final PsiType substitution = resolveResult.getSubstitutor().substitute(parameter);
if (substitution instanceof PsiWildcardType && !((PsiWildcardType)substitution).isBounded()) {
for (PsiType paramType : methodSignature.getParameterTypes()) {
- if (LambdaUtil.depends(paramType, parameter, new LambdaUtil.TypeParamsChecker((PsiMethod)null, aClass) {
+ if (LambdaUtil.depends(paramType, new LambdaUtil.TypeParamsChecker((PsiMethod)null, aClass) {
@Override
public boolean startedInference() {
return true;
}
- })) {
+ }, parameter)) {
depends = true;
break;
}
diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java
index 5214e3eb0cfa..672f290abbdc 100644
--- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java
@@ -37,7 +37,6 @@ import java.util.*;
*/
public class LambdaUtil {
private static final Logger LOG = Logger.getInstance("#" + LambdaUtil.class.getName());
- public static ThreadLocal<Set<PsiParameterList>> ourParams = new ThreadLocal<Set<PsiParameterList>>();
@NonNls public static final String JAVA_LANG_FUNCTIONAL_INTERFACE = "java.lang.FunctionalInterface";
@Nullable
@@ -82,7 +81,16 @@ public class LambdaUtil {
final PsiClass methodContainingClass = method.getContainingClass();
LOG.assertTrue(methodContainingClass != null);
- return TypeConversionUtil.getSuperClassSubstitutor(methodContainingClass, derivedClass, resolveResult.getSubstitutor());
+ PsiSubstitutor initialSubst = resolveResult.getSubstitutor();
+ final PsiSubstitutor superClassSubstitutor =
+ TypeConversionUtil.getSuperClassSubstitutor(methodContainingClass, derivedClass, PsiSubstitutor.EMPTY);
+ for (PsiTypeParameter param : superClassSubstitutor.getSubstitutionMap().keySet()) {
+ final PsiType substitute = superClassSubstitutor.substitute(param);
+ if (substitute != null) {
+ initialSubst = initialSubst.put(param, initialSubst.substitute(substitute));
+ }
+ }
+ return initialSubst;
}
public static boolean isValidLambdaContext(PsiElement context) {
@@ -103,7 +111,7 @@ public class LambdaUtil {
if (hasParams && !checkRawAcceptable(expression, functionalInterfaceType)) {
return false;
}
- return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression, null);
+ return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression);
}
return true;
}
@@ -121,6 +129,13 @@ public class LambdaUtil {
if (type instanceof PsiClassType && ((PsiClassType)type).isRaw()) {
return true;
}
+ final PsiMethod method = ((PsiMethodCallExpression)gParent).resolveMethod();
+ if (method != null) {
+ int lambdaIdx = getLambdaIdx((PsiExpressionList)parent, expression);
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ final PsiType normalizedType = getNormalizedType(parameters[adjustLambdaIdx(lambdaIdx, method, parameters)]);
+ if (normalizedType instanceof PsiClassType && ((PsiClassType)normalizedType).isRaw()) return true;
+ }
}
if (functionalInterfaceType instanceof PsiClassType && ((PsiClassType)functionalInterfaceType).isRaw()){
return false;
@@ -248,6 +263,7 @@ public class LambdaUtil {
for (HierarchicalMethodSignature signature : visibleSignatures) {
final PsiMethod psiMethod = signature.getMethod();
if (!psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) continue;
+ if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) continue;
if (!overridesPublicObjectMethod(psiMethod)) {
methods.add(signature);
}
@@ -295,34 +311,30 @@ public class LambdaUtil {
return -1;
}
- public static boolean dependsOnTypeParams(PsiType type, PsiLambdaExpression expr) {
- return dependsOnTypeParams(type, expr, null);
- }
-
public static boolean dependsOnTypeParams(PsiType type,
PsiLambdaExpression expr,
PsiTypeParameter param2Check) {
- return depends(type, param2Check, new TypeParamsChecker(expr));
+ return depends(type, new TypeParamsChecker(expr), param2Check);
}
public static boolean dependsOnTypeParams(PsiType type,
PsiType functionalInterfaceType,
PsiElement lambdaExpression,
- PsiTypeParameter param2Check) {
- return depends(type, param2Check, new TypeParamsChecker(lambdaExpression,
- PsiUtil.resolveClassInType(functionalInterfaceType)));
+ PsiTypeParameter... param2Check) {
+ return depends(type, new TypeParamsChecker(lambdaExpression,
+ PsiUtil.resolveClassInType(functionalInterfaceType)), param2Check);
}
public static boolean dependsOnTypeParams(PsiType type,
PsiClass aClass,
PsiMethod aMethod) {
- return depends(type, null, new TypeParamsChecker(aMethod, aClass));
+ return depends(type, new TypeParamsChecker(aMethod, aClass));
}
- static boolean depends(PsiType type, PsiTypeParameter param2Check, TypeParamsChecker visitor) {
+ static boolean depends(PsiType type, TypeParamsChecker visitor, PsiTypeParameter... param2Check) {
if (!visitor.startedInference()) return false;
final Boolean accept = type.accept(visitor);
- if (param2Check != null) {
+ if (param2Check.length > 0) {
return visitor.used(param2Check);
}
return accept != null && accept.booleanValue();
@@ -352,6 +364,14 @@ public class LambdaUtil {
final PsiParameter[] lambdaParams = lambdaExpression.getParameterList().getParameters();
if (lambdaParams.length != methodParameters.length) return false;
final boolean[] independent = new boolean[]{true};
+ final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(functionalInterfaceType);
+ if (interfaceMethod == null) return false;
+ final TypeParamsChecker paramsChecker = new TypeParamsChecker(lambdaExpression);
+ for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
+ subst.substitute(parameter.getType()).accept(paramsChecker);
+ }
+ paramsChecker.myUsedTypeParams.add(typeParam);
+
expression.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitConditionalExpression(PsiConditionalExpression expression) {
@@ -377,7 +397,8 @@ public class LambdaUtil {
}
}
- if (usedParamIdx > -1 && dependsOnTypeParams(subst.substitute(methodParameters[usedParamIdx].getType()), functionalInterfaceType, lambdaExpression, typeParam)) {
+ if (usedParamIdx > -1 && dependsOnTypeParams(subst.substitute(methodParameters[usedParamIdx].getType()), functionalInterfaceType,
+ lambdaExpression, paramsChecker.myUsedTypeParams.toArray(new PsiTypeParameter[paramsChecker.myUsedTypeParams.size()]))) {
independent[0] = false;
}
}
@@ -387,6 +408,11 @@ public class LambdaUtil {
@Nullable
public static PsiType getFunctionalInterfaceType(PsiElement expression, final boolean tryToSubstitute) {
+ return getFunctionalInterfaceType(expression, tryToSubstitute, -1);
+ }
+
+ @Nullable
+ public static PsiType getFunctionalInterfaceType(PsiElement expression, final boolean tryToSubstitute, int paramIdx) {
PsiElement parent = expression.getParent();
PsiElement element = expression;
while (parent instanceof PsiParenthesizedExpression || parent instanceof PsiConditionalExpression) {
@@ -416,13 +442,13 @@ public class LambdaUtil {
final int lambdaIdx = getLambdaIdx(expressionList, expression);
if (lambdaIdx > -1) {
- if (!tryToSubstitute) {
- final Map<PsiElement,Pair<PsiMethod,PsiSubstitutor>> currentMethodCandidates = MethodCandidateInfo.CURRENT_CANDIDATE.get();
- final Pair<PsiMethod, PsiSubstitutor> method = currentMethodCandidates != null ? currentMethodCandidates.get(parent) : null;
- if (method != null) {
- final PsiParameter[] parameters = method.first.getParameterList().getParameters();
- return lambdaIdx < parameters.length ? method.second.substitute(parameters[lambdaIdx].getType()) : null;
- }
+ PsiType cachedType = null;
+ final Map<PsiElement,Pair<PsiMethod,PsiSubstitutor>> currentMethodCandidates = MethodCandidateInfo.CURRENT_CANDIDATE.get();
+ final Pair<PsiMethod, PsiSubstitutor> method = currentMethodCandidates != null ? currentMethodCandidates.get(parent) : null;
+ if (method != null) {
+ final PsiParameter[] parameters = method.first.getParameterList().getParameters();
+ cachedType = lambdaIdx < parameters.length ? method.second.substitute(getNormalizedType(parameters[adjustLambdaIdx(lambdaIdx, method.first, parameters)])) : null;
+ if (!tryToSubstitute) return cachedType;
}
final PsiElement gParent = expressionList.getParent();
@@ -432,12 +458,23 @@ public class LambdaUtil {
final PsiElement resolve = resolveResult.getElement();
if (resolve instanceof PsiMethod) {
final PsiParameter[] parameters = ((PsiMethod)resolve).getParameterList().getParameters();
- if (lambdaIdx < parameters.length) {
- if (!tryToSubstitute) return parameters[lambdaIdx].getType();
+ final int finalLambdaIdx = adjustLambdaIdx(lambdaIdx, (PsiMethod)resolve, parameters);
+ if (finalLambdaIdx < parameters.length) {
+ if (!tryToSubstitute) return getNormalizedType(parameters[finalLambdaIdx]);
+ if (cachedType != null && paramIdx > -1) {
+ final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(cachedType);
+ if (interfaceMethod != null) {
+ final PsiClassType.ClassResolveResult cachedResult = PsiUtil.resolveGenericsClassInType(cachedType);
+ final PsiType interfaceMethodParameterType = interfaceMethod.getParameterList().getParameters()[paramIdx].getType();
+ if (!dependsOnTypeParams(cachedResult.getSubstitutor().substitute(interfaceMethodParameterType), cachedType, expression)){
+ return cachedType;
+ }
+ }
+ }
return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
- return resolveResult.getSubstitutor().substitute(parameters[lambdaIdx].getType());
+ return resolveResult.getSubstitutor().substitute(getNormalizedType(parameters[finalLambdaIdx]));
}
});
}
@@ -461,6 +498,24 @@ public class LambdaUtil {
return null;
}
+ private static int adjustLambdaIdx(int lambdaIdx, PsiMethod resolve, PsiParameter[] parameters) {
+ final int finalLambdaIdx;
+ if (((PsiMethod)resolve).isVarArgs() && lambdaIdx >= parameters.length) {
+ finalLambdaIdx = parameters.length - 1;
+ } else {
+ finalLambdaIdx = lambdaIdx;
+ }
+ return finalLambdaIdx;
+ }
+
+ private static PsiType getNormalizedType(PsiParameter parameter) {
+ final PsiType type = parameter.getType();
+ if (type instanceof PsiEllipsisType) {
+ return ((PsiEllipsisType)type).getComponentType();
+ }
+ return type;
+ }
+
public static PsiType getLambdaParameterType(PsiParameter param) {
final PsiElement paramParent = param.getParent();
if (paramParent instanceof PsiParameterList) {
@@ -469,35 +524,23 @@ public class LambdaUtil {
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
if (lambdaExpression != null) {
- Set<PsiParameterList> currentStack = ourParams.get();
- if (currentStack == null) {
- currentStack = new HashSet<PsiParameterList>();
- ourParams.set(currentStack);
- }
-
final PsiParameterList parameterList = lambdaExpression.getParameterList();
- final boolean add = currentStack.add(parameterList);
- try {
- PsiType type = getFunctionalInterfaceType(lambdaExpression, true);
- if (type == null) {
- type = getFunctionalInterfaceType(lambdaExpression, false);
+ PsiType type = getFunctionalInterfaceType(lambdaExpression, true, parameterIndex);
+ if (type == null) {
+ type = getFunctionalInterfaceType(lambdaExpression, false);
+ }
+ if (type instanceof PsiIntersectionType) {
+ final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
+ for (PsiType conjunct : conjuncts) {
+ final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, conjunct);
+ if (lambdaParameterFromType != null) return lambdaParameterFromType;
}
- if (type instanceof PsiIntersectionType) {
- final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
- for (PsiType conjunct : conjuncts) {
- final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, conjunct);
- if (lambdaParameterFromType != null) return lambdaParameterFromType;
- }
- } else {
- final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, type);
- if (lambdaParameterFromType != null) {
- return lambdaParameterFromType;
- }
+ } else {
+ final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, type);
+ if (lambdaParameterFromType != null) {
+ return lambdaParameterFromType;
}
}
- finally {
- if (add) currentStack.remove(parameterList);
- }
}
}
}
@@ -512,7 +555,7 @@ public class LambdaUtil {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameterIndex < parameters.length) {
final PsiType psiType = getSubstitutor(method, resolveResult).substitute(parameters[parameterIndex].getType());
- if (!dependsOnTypeParams(psiType, conjunct, lambdaExpression, null)) {
+ if (!dependsOnTypeParams(psiType, conjunct, lambdaExpression)) {
return GenericsUtil.eliminateWildcards(psiType);
}
}
@@ -593,22 +636,39 @@ public class LambdaUtil {
return result;
}
- public static void checkMoreSpecificReturnType(List<CandidateInfo> conflicts, int functionalInterfaceIdx) {
+ public static void checkMoreSpecificReturnType(List<CandidateInfo> conflicts, PsiType[] actualParameterTypes) {
final CandidateInfo[] newConflictsArray = conflicts.toArray(new CandidateInfo[conflicts.size()]);
for (int i = 1; i < newConflictsArray.length; i++) {
final CandidateInfo method = newConflictsArray[i];
- final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method);
for (int j = 0; j < i; j++) {
final CandidateInfo conflict = newConflictsArray[j];
assert conflict != method;
- final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict);
- if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) {
- int moreSpecific = isMoreSpecific(interfaceReturnType, interfaceReturnType1);
- if (moreSpecific > 0) {
+ int moreSpecific = 0;
+ final PsiMethod methodElement = (PsiMethod)method.getElement();
+ final PsiMethod conflictElement = (PsiMethod)conflict.getElement();
+ if (methodElement.isVarArgs() == conflictElement.isVarArgs()) {
+ for (int functionalInterfaceIdx = 0; functionalInterfaceIdx < actualParameterTypes.length; functionalInterfaceIdx++) {
+ final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method);
+ final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict);
+ if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiLambdaExpressionType || actualParameterTypes[functionalInterfaceIdx] instanceof PsiMethodReferenceType) {
+ if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) {
+ int moreSpecific1 = isMoreSpecific(interfaceReturnType, interfaceReturnType1);
+ if (moreSpecific < 0 && moreSpecific1 > 0 || moreSpecific > 0 && moreSpecific1 < 0) {
+ moreSpecific = 0;
+ break;
+ }
+ moreSpecific = moreSpecific1;
+ }
+ } else if (interfaceReturnType != null && interfaceReturnType1 != null) {
+ moreSpecific = 0;
+ break;
+ }
+ }
+ if (moreSpecific > 0 && conflictElement.getParameterList().getParametersCount() <= actualParameterTypes.length) {
conflicts.remove(method);
break;
}
- else if (moreSpecific < 0) {
+ else if (moreSpecific < 0 && methodElement.getParameterList().getParametersCount() <= actualParameterTypes.length) {
conflicts.remove(conflict);
}
}
@@ -622,7 +682,7 @@ public class LambdaUtil {
if (!(returnType1 instanceof PsiPrimitiveType)) {
return -1;
} else {
- return TypeConversionUtil.areTypesConvertible(returnType, returnType1) ? 1 : -1;
+ return TypeConversionUtil.isAssignable(returnType, returnType1) ? 1 : -1;
}
}
if (returnType1 instanceof PsiPrimitiveType) {
@@ -707,7 +767,7 @@ public class LambdaUtil {
public TypeParamsChecker(PsiElement expression, PsiClass aClass) {
myClass = aClass;
- PsiElement parent = expression.getParent();
+ PsiElement parent = expression != null ? expression.getParent() : null;
while (parent instanceof PsiParenthesizedExpression) {
parent = parent.getParent();
}
@@ -796,8 +856,11 @@ public class LambdaUtil {
return false;
}
- public boolean used(PsiTypeParameter parameter) {
- return myUsedTypeParams.contains(parameter);
+ public boolean used(PsiTypeParameter... parameters) {
+ for (PsiTypeParameter parameter : parameters) {
+ if (myUsedTypeParams.contains(parameter)) return true;
+ }
+ return false;
}
}
}
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java b/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java
index 5da222421d35..a264aada4f42 100644
--- a/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java
+++ b/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java
@@ -16,12 +16,16 @@
package com.intellij.psi;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.RecursionGuard;
+import com.intellij.openapi.util.RecursionManager;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public abstract class PsiDiamondType extends PsiType {
+ public static final RecursionGuard ourDiamondGuard = RecursionManager.createGuard("diamondInference");
+
public PsiDiamondType(PsiAnnotation[] annotations) {
super(annotations);
}
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java
index 635f4ce4539a..1d0b2d750304 100644
--- a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java
@@ -16,11 +16,10 @@
package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.psi.codeStyle.JavaCodeStyleManager;
-import com.intellij.psi.util.InheritanceUtil;
-import com.intellij.psi.util.MethodSignature;
-import com.intellij.psi.util.PsiUtil;
-import com.intellij.psi.util.TypeConversionUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.util.*;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
@@ -77,12 +76,7 @@ public class PsiMethodReferenceUtil {
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
final PsiExpression expression = methodReferenceExpression.getQualifierExpression();
if (expression != null) {
- final PsiType expressionType = expression.getType();
- if (expressionType instanceof PsiArrayType) {
- containingClass = JavaPsiFacade.getInstance(methodReferenceExpression.getProject())
- .findClass(CommonClassNames.JAVA_LANG_OBJECT, methodReferenceExpression.getResolveScope());
- return new QualifierResolveResult(containingClass, substitutor, false);
- }
+ final PsiType expressionType = getExpandedType(expression.getType(), expression);
PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(expressionType);
containingClass = result.getElement();
if (containingClass != null) {
@@ -101,7 +95,8 @@ public class PsiMethodReferenceUtil {
else {
final PsiTypeElement typeElement = methodReferenceExpression.getQualifierType();
if (typeElement != null) {
- PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(typeElement.getType());
+ PsiType type = getExpandedType(typeElement.getType(), typeElement);
+ PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type);
containingClass = result.getElement();
if (containingClass != null) {
substitutor = result.getSubstitutor();
@@ -142,14 +137,21 @@ public class PsiMethodReferenceUtil {
final QualifierResolveResult qualifierResolveResult = getQualifierResolveResult(methodReferenceExpression);
final PsiElement resolve = result.getElement();
if (resolve instanceof PsiMethod) {
- final MethodSignature signature1 = method.getSignature(resolveResult.getSubstitutor());
+ final MethodSignature signature1 = method.getSignature(LambdaUtil.getSubstitutor(method, resolveResult));
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
subst = subst.putAll(qualifierResolveResult.getSubstitutor());
subst = subst.putAll(result.getSubstitutor());
final MethodSignature signature2 = ((PsiMethod)resolve).getSignature(subst);
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(left);
- PsiType methodReturnType = subst.substitute(((PsiMethod)resolve).getReturnType());
+
+ PsiType returnType = PsiTypesUtil.patchMethodGetClassReturnType(methodReferenceExpression, methodReferenceExpression,
+ (PsiMethod)resolve, null,
+ PsiUtil.getLanguageLevel(methodReferenceExpression));
+ if (returnType == null) {
+ returnType = ((PsiMethod)resolve).getReturnType();
+ }
+ PsiType methodReturnType = subst.substitute(returnType);
if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) {
if (methodReturnType == null) {
methodReturnType = JavaPsiFacade.getElementFactory(methodReferenceExpression.getProject()).createType(((PsiMethod)resolve).getContainingClass(), subst);
@@ -161,9 +163,18 @@ public class PsiMethodReferenceUtil {
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(left);
if (interfaceReturnType != null) {
if (interfaceReturnType == PsiType.VOID) return true;
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ if (resolve == JavaPsiFacade.getElementFactory(resolve.getProject()).getArrayClass(PsiUtil.getLanguageLevel(resolve))) {
+ if (parameters.length != 1 || parameters[0].getType() != PsiType.INT) return false;
+ final PsiTypeParameter[] typeParameters = ((PsiClass)resolve).getTypeParameters();
+ if (typeParameters.length == 1) {
+ final PsiType arrayComponentType = result.getSubstitutor().substitute(typeParameters[0]);
+ return arrayComponentType != null && TypeConversionUtil.isAssignable(interfaceReturnType, arrayComponentType.createArrayType(), true);
+ }
+ return false;
+ }
final PsiClassType classType = JavaPsiFacade.getElementFactory(methodReferenceExpression.getProject()).createType((PsiClass)resolve, result.getSubstitutor());
if (TypeConversionUtil.isAssignable(interfaceReturnType, classType, !((PsiClass)resolve).hasTypeParameters())) {
- final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length == 0) return true;
if (parameters.length == 1) {
if (isReceiverType(resolveResult.getSubstitutor().substitute(parameters[0].getType()), qualifierResolveResult.getContainingClass(), qualifierResolveResult.getSubstitutor())) return true;
@@ -176,25 +187,29 @@ public class PsiMethodReferenceUtil {
}
private static boolean isReceiverType(@Nullable PsiClass aClass, @Nullable PsiClass containingClass) {
- while (containingClass != null) {
- if (InheritanceUtil.isInheritorOrSelf(aClass, containingClass, true)) return true;
- containingClass = containingClass.getContainingClass();
- }
- return false;
+ return InheritanceUtil.isInheritorOrSelf(aClass, containingClass, true);
}
public static boolean isReceiverType(PsiType receiverType, @Nullable PsiClass containingClass, PsiSubstitutor psiSubstitutor) {
+ if (containingClass != null) {
+ receiverType = getExpandedType(receiverType, containingClass);
+ }
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(receiverType));
final PsiClass receiverClass = resolveResult.getElement();
if (receiverClass != null && isReceiverType(receiverClass, containingClass)) {
LOG.assertTrue(containingClass != null);
return resolveResult.getSubstitutor().equals(psiSubstitutor) ||
- PsiUtil.isRawSubstitutor(containingClass, psiSubstitutor) ||
- PsiUtil.isRawSubstitutor(receiverClass, resolveResult.getSubstitutor());
+ emptyOrRaw(containingClass, psiSubstitutor) ||
+ emptyOrRaw(receiverClass, resolveResult.getSubstitutor());
}
return false;
}
+ private static boolean emptyOrRaw(PsiClass containingClass, PsiSubstitutor psiSubstitutor) {
+ return PsiUtil.isRawSubstitutor(containingClass, psiSubstitutor) ||
+ (!containingClass.hasTypeParameters() && psiSubstitutor.getSubstitutionMap().isEmpty());
+ }
+
public static boolean isReceiverType(PsiType functionalInterfaceType, PsiClass containingClass, @Nullable PsiMethod referencedMethod) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final MethodSignature function = LambdaUtil.getFunction(resolveResult.getElement());
@@ -259,14 +274,23 @@ public class PsiMethodReferenceUtil {
return true;
}
- public static PsiLocalVariable createMethodReferenceExpressionAccording2Type(PsiMethodReferenceExpression methodReferenceExpression,
- PsiType leftType) {
- final String uniqueVarName =
- JavaCodeStyleManager.getInstance(methodReferenceExpression.getProject())
- .suggestUniqueVariableName("l", methodReferenceExpression, true);
- final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(methodReferenceExpression.getProject())
- .createStatementFromText(leftType.getCanonicalText() + " " + uniqueVarName + " = " + methodReferenceExpression.getText(),
- methodReferenceExpression);
- return (PsiLocalVariable)((PsiDeclarationStatement)assignmentFromText).getDeclaredElements()[0];
+
+ public static boolean onArrayType(PsiClass containingClass, MethodSignature signature) {
+ if (signature.getParameterTypes().length == 1 && signature.getParameterTypes()[0] == PsiType.INT) {
+ if (containingClass != null) {
+ final Project project = containingClass.getProject();
+ final LanguageLevel level = PsiUtil.getLanguageLevel(containingClass);
+ return containingClass == JavaPsiFacade.getElementFactory(project).getArrayClass(level);
+ }
+ }
+ return false;
+ }
+
+ private static PsiType getExpandedType(PsiType type, @NotNull PsiElement typeElement) {
+ if (type instanceof PsiArrayType) {
+ type = JavaPsiFacade.getElementFactory(typeElement.getProject()).getArrayClassType(((PsiArrayType)type).getComponentType(),
+ PsiUtil.getLanguageLevel(typeElement));
+ }
+ return type;
}
}
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java b/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java
index be0712efa5bc..e82221e7a887 100644
--- a/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java
+++ b/java/java-psi-api/src/com/intellij/psi/PsiNameHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 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.
@@ -67,17 +67,12 @@ public abstract class PsiNameHelper {
@NotNull
public static String getShortClassName(@NotNull String referenceText) {
- return getShortClassName(referenceText, true);
- }
+ int lessPos = referenceText.length(), bracesBalance = 0, i;
- private static String getShortClassName(String referenceText, boolean removeWhitespace) {
- int lessPos = referenceText.length();
- int bracesBalance = 0;
- int i;
loop:
for (i = referenceText.length() - 1; i >= 0; i--) {
- final char aChar = referenceText.charAt(i);
- switch (aChar) {
+ char ch = referenceText.charAt(i);
+ switch (ch) {
case ')':
case '>':
bracesBalance++;
@@ -91,22 +86,25 @@ public abstract class PsiNameHelper {
case '@':
case '.':
- if (bracesBalance == 0) break loop;
+ if (bracesBalance <= 0) break loop;
break;
default:
- if (bracesBalance == 0 && removeWhitespace && !Character.isWhitespace(aChar) && !Character.isJavaIdentifierPart(aChar)) {
- return getShortClassName(removeWhitespace(referenceText), false);
+ if (Character.isWhitespace(ch) && bracesBalance <= 0) {
+ for (int j = i + 1; j < lessPos; j++) {
+ if (!Character.isWhitespace(referenceText.charAt(j))) break loop;
+ }
+ lessPos = i;
}
}
}
+
String sub = referenceText.substring(i + 1, lessPos).trim();
return sub.length() == referenceText.length() ? sub : new String(sub);
}
public static String getPresentableText(PsiJavaCodeReferenceElement ref) {
final String referenceName = ref.getReferenceName();
-
PsiType[] typeParameters = ref.getTypeParameters();
return getPresentableText(referenceName, typeParameters);
}
@@ -167,7 +165,7 @@ public abstract class PsiNameHelper {
* <code>["List&lt;String&gt","Integer"]</code>
*
* @param referenceText the text of the reference to calculate type parameters for.
- * @return the calculated array of type parameters.
+ * @return the calculated array of type parameters.
*/
public static String[] getClassParametersText(String referenceText) {
if (referenceText.indexOf('<') < 0) return ArrayUtil.EMPTY_STRING_ARRAY;
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java b/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java
new file mode 100644
index 000000000000..f3851a9fe54e
--- /dev/null
+++ b/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2013 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;
+
+/**
+ * Represents a receiver parameter of a Java method (Java 8).
+ *
+ * @since 12.1
+ */
+public interface PsiReceiverParameter extends PsiParameter {
+}
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java b/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java
index 5a035acac1f6..d97216077be9 100644
--- a/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java
+++ b/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
*/
public interface PsiResolveHelper {
RecursionGuard ourGuard = RecursionManager.createGuard("typeArgInference");
+ RecursionGuard ourGraphGuard = RecursionManager.createGuard("graphTypeArgInference");
class SERVICE {
private SERVICE() {
diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java
index 8c6f4c4ed477..cac0f3bc2c89 100644
--- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java
+++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java
@@ -18,6 +18,7 @@ package com.intellij.psi.infos;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.RecursionGuard;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
@@ -28,7 +29,6 @@ import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
-import java.util.Set;
/**
* @author ik, dsl
@@ -98,11 +98,15 @@ public class MethodCandidateInfo extends CandidateInfo{
PsiSubstitutor incompleteSubstitutor = super.getSubstitutor();
PsiMethod method = getElement();
if (myTypeArguments == null) {
- final Set<PsiParameterList> lists = LambdaUtil.ourParams.get();
- if (lists != null && !lists.isEmpty()) {
- return inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE);
- }
- myCalcedSubstitutor = inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE);
+ final RecursionGuard.StackStamp stackStamp = PsiDiamondType.ourDiamondGuard.markStack();
+
+ final PsiSubstitutor inferredSubstitutor = inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE);
+
+ if (!stackStamp.mayCacheNow()) {
+ return inferredSubstitutor;
+ }
+
+ myCalcedSubstitutor = inferredSubstitutor;
}
else {
PsiTypeParameter[] typeParams = method.getTypeParameters();
diff --git a/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java b/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java
index ff63ac313491..94f5170e7a84 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.LinkedHashSet;
import java.util.Set;
public class InheritanceUtil {
@@ -105,7 +106,14 @@ public class InheritanceUtil {
getSuperClassesOfList(aClass.getSuperTypes(), results, includeNonProject, new THashSet<PsiClass>(), aClass.getManager());
}
- private static void getSuperClassesOfList(@NotNull PsiClassType[] types,
+ public static LinkedHashSet<PsiClass> getSuperClasses(@NotNull PsiClass aClass) {
+ LinkedHashSet<PsiClass> result = new LinkedHashSet<PsiClass>();
+ getSuperClasses(aClass, result, true);
+ return result;
+ }
+
+
+ private static void getSuperClassesOfList(@NotNull PsiClassType[] types,
@NotNull Set<PsiClass> results,
boolean includeNonProject,
@NotNull Set<PsiClass> visited,
diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java
index 1eb3ae340a0e..43890225a21c 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/PsiTypesUtil.java
@@ -15,7 +15,13 @@
*/
package com.intellij.psi.util;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.util.containers.HashMap;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -47,6 +53,8 @@ public class PsiTypesUtil {
ourBoxedTypes.put("char", CommonClassNames.JAVA_LANG_CHARACTER);
}
+ @NonNls private static final String GET_CLASS_METHOD = "getClass";
+
private PsiTypesUtil() { }
public static String getDefaultValueOfType(PsiType type) {
@@ -135,4 +143,45 @@ public class PsiTypesUtil {
}
return null;
}
+
+ public static PsiType patchMethodGetClassReturnType(@NotNull PsiExpression call,
+ @NotNull PsiReferenceExpression methodExpression,
+ @NotNull PsiMethod method,
+ @Nullable Condition<IElementType> condition,
+ @NotNull LanguageLevel languageLevel) {
+ //JLS3 15.8.2
+ if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) &&
+ GET_CLASS_METHOD.equals(method.getName()) &&
+ CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName())) {
+ PsiExpression qualifier = methodExpression.getQualifierExpression();
+ PsiType qualifierType = null;
+ final Project project = call.getProject();
+ if (qualifier != null) {
+ qualifierType = TypeConversionUtil.erasure(qualifier.getType());
+ }
+ else if (condition != null) {
+ ASTNode parent = call.getNode().getTreeParent();
+ while (parent != null && condition.value(parent.getElementType())) {
+ parent = parent.getTreeParent();
+ }
+ if (parent != null) {
+ qualifierType = JavaPsiFacade.getInstance(project).getElementFactory().createType((PsiClass)parent.getPsi());
+ }
+ }
+ if (qualifierType != null) {
+ PsiClass javaLangClass = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_CLASS, call.getResolveScope());
+ if (javaLangClass != null && javaLangClass.getTypeParameters().length == 1) {
+ Map<PsiTypeParameter, PsiType> map = new HashMap<PsiTypeParameter, PsiType>();
+ map.put(javaLangClass.getTypeParameters()[0], PsiWildcardType.createExtends(call.getManager(), qualifierType));
+ PsiSubstitutor substitutor = JavaPsiFacade.getInstance(project).getElementFactory().createSubstitutor(map);
+ final PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory()
+ .createType(javaLangClass, substitutor, languageLevel);
+ final PsiElement parent = call.getParent();
+ return parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression
+ ? PsiUtil.captureToplevelWildcards(classType, methodExpression) : classType;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java
index 0585ec3b0496..bba6f97400b8 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2013 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,6 +32,7 @@ import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.meta.PsiMetaOwner;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.EmptyIterable;
@@ -465,14 +466,16 @@ public final class PsiUtil extends PsiUtilCore {
final PsiParameter[] parms = method.getParameterList().getParameters();
if (args.length < parms.length - 1) return ApplicabilityLevel.NOT_APPLICABLE;
- if (!areFirstArgumentsApplicable(args, parms, languageLevel, substitutorForMethod)) return ApplicabilityLevel.NOT_APPLICABLE;
+ final boolean isRaw = isRawSubstitutor(method, substitutorForMethod);
+ if (!areFirstArgumentsApplicable(args, parms, languageLevel, substitutorForMethod, isRaw)) return ApplicabilityLevel.NOT_APPLICABLE;
if (args.length == parms.length) {
if (parms.length == 0) return ApplicabilityLevel.FIXED_ARITY;
PsiType parmType = getParameterType(parms[parms.length - 1], languageLevel, substitutorForMethod);
PsiType argType = args[args.length - 1];
if (argType == null) return ApplicabilityLevel.NOT_APPLICABLE;
if (TypeConversionUtil.isAssignable(parmType, argType)) return ApplicabilityLevel.FIXED_ARITY;
- if (isRawSubstitutor(method, substitutorForMethod)) {
+
+ if (isRaw) {
final PsiType erasedParamType = TypeConversionUtil.erasure(parmType);
final PsiType erasedArgType = TypeConversionUtil.erasure(argType);
if (erasedArgType != null && erasedParamType != null &&
@@ -507,13 +510,19 @@ public final class PsiUtil extends PsiUtilCore {
private static boolean areFirstArgumentsApplicable(@NotNull PsiType[] args,
@NotNull final PsiParameter[] parms,
@NotNull LanguageLevel languageLevel,
- @NotNull final PsiSubstitutor substitutorForMethod) {
+ @NotNull final PsiSubstitutor substitutorForMethod, boolean isRaw) {
for (int i = 0; i < parms.length - 1; i++) {
final PsiType type = args[i];
if (type == null) return false;
final PsiParameter parameter = parms[i];
final PsiType substitutedParmType = getParameterType(parameter, languageLevel, substitutorForMethod);
- if (!TypeConversionUtil.isAssignable(substitutedParmType, type)) {
+ if (isRaw) {
+ final PsiType substErasure = TypeConversionUtil.erasure(substitutedParmType);
+ final PsiType typeErasure = TypeConversionUtil.erasure(type);
+ if (substErasure != null && typeErasure != null && !TypeConversionUtil.isAssignable(substErasure, typeErasure)) {
+ return false;
+ }
+ } else if (!TypeConversionUtil.isAssignable(substitutedParmType, type)) {
return false;
}
}
@@ -542,7 +551,7 @@ public final class PsiUtil extends PsiUtilCore {
if (typeParameters1.length != typeParameters2.length) return false;
for (int i = 0; i < typeParameters1.length; i++) {
final PsiType substituted2 = s2.substitute(typeParameters2[i]);
- if (!Comparing.equal(s1.substituteWithBoundsPromotion(typeParameters1[i]), substituted2) &&
+ if (!Comparing.equal(s1.substituteWithBoundsPromotion(typeParameters1[i]), substituted2) &&
!Comparing.equal(s1.substitute(typeParameters1[i]), substituted2)) return false;
}
if (aClass.hasModifierProperty(PsiModifier.STATIC)) return true;
@@ -827,15 +836,15 @@ public final class PsiUtil extends PsiUtilCore {
if (element instanceof PsiDirectory) return JavaDirectoryService.getInstance().getLanguageLevel((PsiDirectory)element);
final PsiFile file = element.getContainingFile();
if (file == null) {
- final LanguageLevelProjectExtension instance = LanguageLevelProjectExtension.getInstance(element.getProject());
- return instance != null ? instance.getLanguageLevel() : LanguageLevel.HIGHEST;
+ LanguageLevelProjectExtension instance = LanguageLevelProjectExtension.getInstance(element.getProject());
+ return instance == null ? LanguageLevel.HIGHEST : instance.getLanguageLevel();
}
if (!(file instanceof PsiJavaFile)) {
final PsiElement context = file.getContext();
if (context != null) return getLanguageLevel(context);
- final LanguageLevelProjectExtension instance = LanguageLevelProjectExtension.getInstance(file.getProject());
- return instance != null ? instance.getLanguageLevel() : LanguageLevel.HIGHEST;
+ LanguageLevelProjectExtension instance = LanguageLevelProjectExtension.getInstance(file.getProject());
+ return instance == null ? LanguageLevel.HIGHEST : instance.getLanguageLevel();
}
return ((PsiJavaFile)file).getLanguageLevel();
@@ -850,7 +859,7 @@ public final class PsiUtil extends PsiUtilCore {
public static boolean hasDefaultConstructor(@NotNull PsiClass clazz) {
return hasDefaultConstructor(clazz, false);
}
-
+
public static boolean hasDefaultConstructor(@NotNull PsiClass clazz, boolean allowProtected) {
return hasDefaultConstructor(clazz, allowProtected, true);
}
@@ -941,10 +950,14 @@ public final class PsiUtil extends PsiUtilCore {
return parent instanceof PsiIfStatement && element == ((PsiIfStatement)parent).getElseBranch();
}
- public static boolean isJavaToken(@Nullable final PsiElement element, final IElementType type) {
+ public static boolean isJavaToken(@Nullable PsiElement element, IElementType type) {
return element instanceof PsiJavaToken && ((PsiJavaToken)element).getTokenType() == type;
}
+ public static boolean isJavaToken(@Nullable PsiElement element, @NotNull TokenSet types) {
+ return element instanceof PsiJavaToken && types.contains(((PsiJavaToken)element).getTokenType());
+ }
+
public static boolean isCatchParameter(@Nullable final PsiElement element) {
return element instanceof PsiParameter && element.getParent() instanceof PsiCatchSection;
}
diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java
index a206a642e396..09ef657b4c4a 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java
@@ -686,6 +686,9 @@ public class TypeConversionUtil {
final PsiType lType = lLambdaExpression.getFunctionalInterfaceType();
return Comparing.equal(rType, lType);
}
+ if (left instanceof PsiArrayType) {
+ return false;
+ }
return LambdaUtil.isAcceptable(rLambdaExpression, left, false);
}
@@ -815,21 +818,6 @@ public class TypeConversionUtil {
}
public static boolean boxingConversionApplicable(final PsiType left, final PsiType right) {
- if (right instanceof PsiMethodReferenceType) {
- final JavaResolveResult result = ((PsiMethodReferenceType)right).getExpression().advancedResolve(false);
- PsiElement element = result.getElement();
- final PsiClassType.ClassResolveResult functionalInterfaceResult = PsiUtil.resolveGenericsClassInType(left);
- final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceResult);
- if (element instanceof PsiMethod && interfaceMethod != null) {
- final PsiType[] parameterTypes = ((PsiMethod)element).getSignature(result.getSubstitutor()).getParameterTypes();
- final PsiType[] argTypes = interfaceMethod.getSignature(functionalInterfaceResult.getSubstitutor()).getParameterTypes();
- if (parameterTypes.length != argTypes.length) return false;
- for (int i = 0; i < parameterTypes.length; i++) {
- if (boxingConversionApplicable(parameterTypes[i], argTypes[i])) return true;
- }
- }
- }
-
if (left instanceof PsiPrimitiveType && !PsiType.NULL.equals(left)) {
return right instanceof PsiClassType && isAssignable(left, right);
}