mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
method refs: patch getClass return value in the same way it is done in PsiMethodCallExpression
This commit is contained in:
@@ -18,10 +18,7 @@ package com.intellij.psi;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -79,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) {
|
||||
@@ -152,7 +144,14 @@ public class PsiMethodReferenceUtil {
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-35
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.tree.java;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
@@ -27,19 +28,15 @@ import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.tree.ChildRoleBase;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements PsiMethodCallExpression {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl");
|
||||
@NonNls private static final String GET_CLASS_METHOD = "getClass";
|
||||
|
||||
public PsiMethodCallExpressionImpl() {
|
||||
super(JavaElementType.METHOD_CALL_EXPRESSION);
|
||||
@@ -174,39 +171,19 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements
|
||||
private static PsiType getResultType(PsiExpression call, PsiReferenceExpression methodExpression, JavaResolveResult result) {
|
||||
final PsiMethod method = (PsiMethod)result.getElement();
|
||||
if (method == null) return null;
|
||||
PsiManager manager = call.getManager();
|
||||
|
||||
final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(call);
|
||||
boolean is15OrHigher = languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0;
|
||||
//JLS3 15.8.2
|
||||
if (is15OrHigher &&
|
||||
GET_CLASS_METHOD.equals(method.getName()) &&
|
||||
CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName())) {
|
||||
PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
PsiType qualifierType = null;
|
||||
if (qualifier != null) {
|
||||
qualifierType = TypeConversionUtil.erasure(qualifier.getType());
|
||||
}
|
||||
else {
|
||||
ASTNode parent = call.getNode().getTreeParent();
|
||||
while (parent != null && parent.getElementType() != JavaElementType.CLASS) parent = parent.getTreeParent();
|
||||
if (parent != null) {
|
||||
qualifierType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType((PsiClass)parent.getPsi());
|
||||
}
|
||||
}
|
||||
if (qualifierType != null) {
|
||||
PsiClass javaLangClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("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(manager, qualifierType));
|
||||
PsiSubstitutor substitutor = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createSubstitutor(map);
|
||||
final PsiClassType classType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory()
|
||||
.createType(javaLangClass, substitutor, languageLevel);
|
||||
final PsiElement parent = call.getParent();
|
||||
return parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression
|
||||
? PsiUtil.captureToplevelWildcards(classType, methodExpression) : classType;
|
||||
}
|
||||
}
|
||||
final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType(call, methodExpression, method,
|
||||
new Condition<IElementType>() {
|
||||
@Override
|
||||
public boolean value(IElementType type) {
|
||||
return type != JavaElementType.CLASS;
|
||||
}
|
||||
}, languageLevel);
|
||||
|
||||
if (getClassReturnType != null) {
|
||||
return getClassReturnType;
|
||||
}
|
||||
|
||||
PsiType ret = method.getReturnType();
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ class MyTest1 {
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'MyTest1.I3'">I3 c3 = arr::clone;</error>
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'MyTest1.I4'">I4 c5 = arr::clone;</error>
|
||||
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'MyTest1.I5'">I5 c4 = this::getClass;</error>
|
||||
I5 c4 = this::getClass;
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'MyTest1.I6'">I6 c6 = this::getClass;</error>
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import java.util.List;
|
||||
class GetClassTest {
|
||||
interface GetCl {
|
||||
Class<? extends List> _();
|
||||
}
|
||||
|
||||
interface GetClReturnTypeProblems {
|
||||
Class<List<String>> _();
|
||||
}
|
||||
|
||||
void test(int[] iarr, List<String> ls) {
|
||||
GetCl c4 = ls::getClass;
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'GetClassTest.GetClReturnTypeProblems'">GetClReturnTypeProblems c5 = ls::getClass;</error>
|
||||
}
|
||||
}
|
||||
+4
@@ -196,6 +196,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testGetClassSpecifics() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user