diff options
Diffstat (limited to 'java/java-psi-api/src/com/intellij')
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<String>","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); } |