mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
exact method refs: mark as not exact if on raw type
This commit is contained in:
+60
-96
@@ -28,7 +28,6 @@ import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
|
||||
import com.intellij.psi.impl.source.JavaStubPsiElement;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.scope.ElementClassFilter;
|
||||
@@ -40,12 +39,13 @@ import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PsiMethodReferenceExpressionImpl extends JavaStubPsiElement<FunctionalExpressionStub<PsiMethodReferenceExpression>>
|
||||
implements PsiMethodReferenceExpression {
|
||||
@@ -147,105 +147,69 @@ public class PsiMethodReferenceExpressionImpl extends JavaStubPsiElement<Functio
|
||||
final PsiElement element = getReferenceNameElement();
|
||||
final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(this);
|
||||
final PsiClass containingClass = qualifierResolveResult.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
PsiMethod[] methods = null;
|
||||
if (element instanceof PsiIdentifier) {
|
||||
final String identifierName = element.getText();
|
||||
final List<PsiMethod> result = new ArrayList<PsiMethod>();
|
||||
for (HierarchicalMethodSignature signature : containingClass.getVisibleSignatures()) {
|
||||
if (identifierName.equals(signature.getName())) {
|
||||
result.add(signature.getMethod());
|
||||
}
|
||||
}
|
||||
if (containingClass == null) return null;
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
methods = result.toArray(new PsiMethod[result.size()]);
|
||||
//If the method reference expression has the form ReferenceType::[TypeArguments]Identifier or ClassType::[TypeArguments]new,
|
||||
//then ReferenceType does not denote a raw type.
|
||||
final PsiElement qualifier = getQualifier();
|
||||
if (qualifier instanceof PsiReferenceExpression) {
|
||||
PsiElement resolve = ((PsiReferenceExpression)qualifier).resolve();
|
||||
if (resolve instanceof PsiClass && ((PsiClass)resolve).hasTypeParameters()) {
|
||||
return null;
|
||||
}
|
||||
else if (isConstructor()) {
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(getProject());
|
||||
final PsiClass arrayClass = factory.getArrayClass(PsiUtil.getLanguageLevel(this));
|
||||
if (arrayClass == containingClass) {
|
||||
final PsiType componentType = qualifierResolveResult.getSubstitutor().substitute(arrayClass.getTypeParameters()[0]);
|
||||
LOG.assertTrue(componentType != null, qualifierResolveResult.getSubstitutor());
|
||||
//15.13.1 A method reference expression of the form ArrayType :: new is always exact.
|
||||
return factory.createMethodFromText("public " + componentType.createArrayType().getCanonicalText() + " __array__(int i) {return null;}", this);
|
||||
}
|
||||
else {
|
||||
if (getQualifierType() == null) {
|
||||
//ClassType is raw or is a non-static member type of a raw type.
|
||||
PsiClass aClass = containingClass;
|
||||
while (aClass != null) {
|
||||
if (aClass.hasTypeParameters()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (aClass.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
break;
|
||||
}
|
||||
|
||||
aClass = aClass.getContainingClass();
|
||||
|
||||
if (PsiTreeUtil.isAncestor(aClass, this, true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
methods = containingClass.getConstructors();
|
||||
PsiMethod[] methods = null;
|
||||
if (element instanceof PsiIdentifier) {
|
||||
final String identifierName = element.getText();
|
||||
final List<PsiMethod> result = new ArrayList<PsiMethod>();
|
||||
for (HierarchicalMethodSignature signature : containingClass.getVisibleSignatures()) {
|
||||
if (identifierName.equals(signature.getName())) {
|
||||
result.add(signature.getMethod());
|
||||
}
|
||||
}
|
||||
if (methods != null) {
|
||||
PsiMethod psiMethod = null;
|
||||
if (methods.length > 0) {
|
||||
for (PsiMethod method : methods) {
|
||||
if (PsiUtil.isAccessible(method, this, null)) {
|
||||
if (psiMethod != null) return null;
|
||||
psiMethod = method;
|
||||
}
|
||||
}
|
||||
if (psiMethod == null) return null;
|
||||
if (psiMethod.isVarArgs()) return null;
|
||||
if (psiMethod.getTypeParameters().length > 0) {
|
||||
final PsiReferenceParameterList parameterList = getParameterList();
|
||||
return parameterList != null && parameterList.getTypeParameterElements().length > 0 ? psiMethod : null;
|
||||
} else {
|
||||
final PsiSubstitutor classSubstitutor = TypeConversionUtil.getClassSubstitutor(psiMethod.getContainingClass(), containingClass, PsiSubstitutor.EMPTY);
|
||||
final Set<PsiType> signature = new HashSet<PsiType>(Arrays.asList(psiMethod.getSignature(PsiSubstitutor.EMPTY).getParameterTypes()));
|
||||
signature.add(psiMethod.getReturnType());
|
||||
boolean free = true;
|
||||
for (PsiType type : signature) {
|
||||
if (classSubstitutor != null) {
|
||||
type = classSubstitutor.substitute(type);
|
||||
}
|
||||
if (type != null && PsiPolyExpressionUtil.mentionsTypeParameters(type, ContainerUtil.newHashSet(containingClass.getTypeParameters()))) {
|
||||
free = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (free) return psiMethod;
|
||||
}
|
||||
}
|
||||
if (containingClass.hasTypeParameters()) {
|
||||
final PsiElement qualifier = getQualifier();
|
||||
PsiJavaCodeReferenceElement referenceElement = null;
|
||||
if (qualifier instanceof PsiTypeElement) {
|
||||
referenceElement = ((PsiTypeElement)qualifier).getInnermostComponentReferenceElement();
|
||||
} else if (qualifier instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression expression = (PsiReferenceExpression)qualifier;
|
||||
if (qualifierResolveResult.isReferenceTypeQualified()) {
|
||||
referenceElement = expression;
|
||||
}
|
||||
}
|
||||
if (referenceElement != null) {
|
||||
final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
|
||||
if (parameterList == null || parameterList.getTypeParameterElements().length == 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return psiMethod == null ? containingClass : psiMethod;
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
methods = result.toArray(new PsiMethod[result.size()]);
|
||||
}
|
||||
else if (isConstructor()) {
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(getProject());
|
||||
final PsiClass arrayClass = factory.getArrayClass(PsiUtil.getLanguageLevel(this));
|
||||
if (arrayClass == containingClass) {
|
||||
final PsiType componentType = qualifierResolveResult.getSubstitutor().substitute(arrayClass.getTypeParameters()[0]);
|
||||
LOG.assertTrue(componentType != null, qualifierResolveResult.getSubstitutor());
|
||||
//15.13.1 A method reference expression of the form ArrayType :: new is always exact.
|
||||
return factory.createMethodFromText("public " + componentType.createArrayType().getCanonicalText() + " __array__(int i) {return null;}", this);
|
||||
}
|
||||
else {
|
||||
methods = containingClass.getConstructors();
|
||||
}
|
||||
}
|
||||
|
||||
if (methods != null) {
|
||||
PsiMethod psiMethod = null;
|
||||
if (methods.length > 0) {
|
||||
//The type to search has exactly one member method with the name Identifier/constructor that is accessible to the class or interface
|
||||
// in which the method reference expression appears
|
||||
for (PsiMethod method : methods) {
|
||||
if (PsiUtil.isAccessible(method, this, null)) {
|
||||
if (psiMethod != null) return null;
|
||||
psiMethod = method;
|
||||
}
|
||||
}
|
||||
if (psiMethod == null) return null;
|
||||
// not variable arity
|
||||
if (psiMethod.isVarArgs()) return null;
|
||||
|
||||
//If this method/constructor is generic (§8.4.4), then the method reference expression provides TypeArguments.
|
||||
if (psiMethod.getTypeParameters().length > 0) {
|
||||
final PsiReferenceParameterList parameterList = getParameterList();
|
||||
return parameterList != null && parameterList.getTypeParameterElements().length > 0 ? psiMethod : null;
|
||||
}
|
||||
}
|
||||
return psiMethod == null ? containingClass : psiMethod;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class InlineRef {
|
||||
<K> void foo(Consumer<K> f) {}
|
||||
|
||||
void bar(){
|
||||
foo(Descriptor::<error descr="Invalid method reference: Object cannot be converted to Descriptor">getName</error>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Descriptor<Y> {
|
||||
static void getName(Descriptor d) {}
|
||||
}
|
||||
+4
@@ -533,6 +533,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNonExactMethodReferenceOnRawClassType() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user