method reference on getClass: fix method reference constraint

This commit is contained in:
Anna Kozlova
2016-02-01 16:53:20 +03:00
parent bd2113b739
commit ea9e4ba63c
6 changed files with 50 additions and 22 deletions
@@ -104,7 +104,7 @@ public class PsiMethodReferenceUtil {
final PsiElement resolve = result.getElement();
if (resolve instanceof PsiMethod) {
containingClass = ((PsiMethod)resolve).getContainingClass();
methodReturnType = PsiTypesUtil.patchMethodGetClassReturnType(expression, expression, (PsiMethod)resolve, null, PsiUtil.getLanguageLevel(expression));
methodReturnType = PsiTypesUtil.patchMethodGetClassReturnType(expression, (PsiMethod)resolve);
if (methodReturnType == null) {
methodReturnType = ((PsiMethod)resolve).getReturnType();
if (PsiType.VOID.equals(methodReturnType)) {
@@ -138,6 +138,15 @@ public class PsiTypesUtil {
return null;
}
public static PsiType patchMethodGetClassReturnType(@NotNull PsiMethodReferenceExpression methodExpression,
@NotNull PsiMethod method) {
if (isGetClass(method)) {
final PsiType qualifierType = PsiMethodReferenceUtil.getQualifierType(methodExpression);
return qualifierType != null ? createJavaLangClassType(methodExpression, qualifierType, true) : null;
}
return null;
}
public static PsiType patchMethodGetClassReturnType(@NotNull PsiExpression call,
@NotNull PsiReferenceExpression methodExpression,
@NotNull PsiMethod method,
@@ -145,10 +154,6 @@ public class PsiTypesUtil {
@NotNull LanguageLevel languageLevel) {
//JLS3 15.8.2
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) && isGetClass(method)) {
if (methodExpression instanceof PsiMethodReferenceExpression) {
final PsiType qualifierType = PsiMethodReferenceUtil.getQualifierType((PsiMethodReferenceExpression)methodExpression);
return qualifierType != null ? createJavaLangClassType(methodExpression, qualifierType, true) : null;
}
PsiExpression qualifier = methodExpression.getQualifierExpression();
PsiType qualifierType = null;
final Project project = call.getProject();
@@ -21,10 +21,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfacePa
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.infos.MethodCandidateInfo;
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.psi.util.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -79,7 +76,6 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, applicableMember, applicableMemberContainingClass);
PsiType applicableMethodReturnType = applicableMember instanceof PsiMethod ? ((PsiMethod)applicableMember).getReturnType() : null;
int idx = 0;
for (PsiTypeParameter param : ((PsiTypeParameterListOwner)applicableMember).getTypeParameters()) {
if (idx < typeParameters.length) {
@@ -110,6 +106,12 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
return false;
}
if (!PsiType.VOID.equals(returnType) && returnType != null) {
PsiType applicableMethodReturnType = null;
if (applicableMember instanceof PsiMethod) {
final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType(myExpression, (PsiMethod)applicableMember);
applicableMethodReturnType = getClassReturnType != null ? getClassReturnType : ((PsiMethod)applicableMember).getReturnType();
}
if (PsiType.VOID.equals(applicableMethodReturnType)) {
session.registerIncompatibleErrorMessage("Incompatible types: expected not void but compile-time declaration for the method reference has void return type");
return false;
@@ -171,7 +173,8 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, PsiSubstitutor.EMPTY);
}
else {
referencedMethodReturnType = method.getReturnType();
final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType(myExpression, method);
referencedMethodReturnType = getClassReturnType != null ? getClassReturnType : method.getReturnType();
}
LOG.assertTrue(referencedMethodReturnType != null, method);
@@ -0,0 +1,30 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Stream;
class Test {
public <T> void some() {
Function<AtomicReference<T>, ? extends Class<? extends AtomicReference>> a = AtomicReference<T>::getClass;
Function<AtomicReference<T>, ? extends Class<? extends AtomicReference>> b = AtomicReference::getClass;
}
}
class Test1<M> {
public <T> void some(Stream<Test1<T>> stream) {
stream.map(Test1::getClass);
stream.map(Test1<T>::getClass);
}
public String getClass(String name) {
return null;
}
}
class Test2<M> {
public <T> void some(Stream<Test2<T>> stream) {
stream.map(Test2::getClass);
stream.map(Test2<T>::getClass);
}
}
@@ -1,10 +0,0 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
class Test {
public <T> void some() {
Function<AtomicReference<T>, ? extends Class<? extends AtomicReference>> a = AtomicReference<T>::getClass;
Function<AtomicReference<T>, ? extends Class<? extends AtomicReference>> b = AtomicReference::getClass;
}
}
@@ -490,7 +490,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testGetClassReturnTypeInMethodRefrence() throws Exception {
public void testGetClassReturnTypeInMethodReference() throws Exception {
doTest();
}