mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
inference for method references: register new variables for raw access
IDEA-189883, IDEA-188976: according to the 15.13.1 search for member is performed in the parameterization (non-raw) type which is a subtype of the first parameter type, in this case no additional variables are required as the type contains type arguments
This commit is contained in:
+24
-8
@@ -208,8 +208,12 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
}
|
||||
}
|
||||
|
||||
if (PsiUtil.isRawSubstitutor(containingClass, qualifierResolveResult.getSubstitutor())) {
|
||||
session.initBounds(myExpression, containingClass.getTypeParameters());
|
||||
PsiClass qContainingClass = qualifierResolveResult.getContainingClass();
|
||||
if (qContainingClass != null && PsiUtil.isRawSubstitutor(qContainingClass, qualifierResolveResult.getSubstitutor())) {
|
||||
//15.13.1 If there exist a parameterization, then it would be used to search, the *raw type* would be used otherwise
|
||||
if (getParameterization(signature, qualifierResolveResult, method, myExpression, qContainingClass) == null) {
|
||||
session.initBounds(myExpression, qContainingClass.getTypeParameters());
|
||||
}
|
||||
}
|
||||
|
||||
referencedMethodReturnType = psiSubstitutor.substitute(referencedMethodReturnType);
|
||||
@@ -233,12 +237,9 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
// the type to search is the result of capture conversion (5.1.10) applied to T;
|
||||
// otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference.
|
||||
if (PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) {
|
||||
PsiClassType subclassType;
|
||||
if (member instanceof PsiMethod &&
|
||||
PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, methodReferenceExpression) &&
|
||||
(subclassType = StrictSubtypingConstraint.getSubclassType(qContainingClass, signature.getParameterTypes()[0], true)) != null &&
|
||||
!subclassType.isRaw()) {
|
||||
final PsiType pType = PsiUtil.captureToplevelWildcards(subclassType, methodReferenceExpression);
|
||||
PsiClassType parameterization = getParameterization(signature, qualifierResolveResult, member, methodReferenceExpression, qContainingClass);
|
||||
if (parameterization != null) {
|
||||
final PsiType pType = PsiUtil.captureToplevelWildcards(parameterization, methodReferenceExpression);
|
||||
psiSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(qContainingClass, (PsiClassType)pType);
|
||||
}
|
||||
else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) {
|
||||
@@ -278,6 +279,21 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
return psiSubstitutor;
|
||||
}
|
||||
|
||||
private static PsiClassType getParameterization(MethodSignature signature,
|
||||
PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult,
|
||||
PsiMember member,
|
||||
PsiMethodReferenceExpression methodReferenceExpression,
|
||||
PsiClass qContainingClass) {
|
||||
if (member instanceof PsiMethod &&
|
||||
PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, methodReferenceExpression)) {
|
||||
PsiClassType subclassType = StrictSubtypingConstraint.getSubclassType(qContainingClass, signature.getParameterTypes()[0], true);
|
||||
if (subclassType != null && !subclassType.isRaw()) {
|
||||
return subclassType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(PsiSubstitutor substitutor, boolean cache) {
|
||||
myT = substitutor.substitute(myT);
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import java.util.stream.Stream;
|
||||
import java.util.Optional;
|
||||
|
||||
class SomeClass<T> {
|
||||
|
||||
private T id;
|
||||
|
||||
public T getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void n(final Optional<SomeClass<T>> o) {
|
||||
T otherId = o.map(SomeClass::getId).orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class A {
|
||||
interface Base<T> {
|
||||
T foo();
|
||||
}
|
||||
|
||||
interface Sub<S> extends Base<S> { }
|
||||
|
||||
void m(Stream<Sub> stream) {
|
||||
stream.map( Sub::foo);
|
||||
}
|
||||
}
|
||||
+1
@@ -180,6 +180,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testMethodReferenceSwallowedErrors() { doTest(); }
|
||||
public void testConflictingVarargsFromFirstSearchWithNArityOfTheSecondSearch() { doTest(); }
|
||||
public void testSkipInferenceForInapplicableMethodReference() { doTest(); }
|
||||
public void testRegisterVariablesForNonFoundParameterizations() { doTest(); }
|
||||
|
||||
public void testPreferErrorOnTopLevelToFailedSubstitutorOnNestedLevel() { doTest(); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user