method references: exclude type parameter used in return types only (IDEA-171480)

This commit is contained in:
Anna.Kozlova
2017-04-18 15:03:44 +02:00
parent 9f6e8ccb35
commit a3dca1423c
4 changed files with 66 additions and 29 deletions
@@ -335,39 +335,47 @@ public class PsiTypesUtil {
}
@NotNull
public static PsiTypeParameter[] filterUnusedTypeParameters(final PsiType superReturnTypeInBaseClassType,
@NotNull PsiTypeParameter[] typeParameters) {
if (typeParameters.length == 0) return typeParameters;
public static PsiTypeParameter[] filterUnusedTypeParameters(@NotNull PsiTypeParameter[] typeParameters,
final PsiType... types) {
if (typeParameters.length == 0) return PsiTypeParameter.EMPTY_ARRAY;
final Set<PsiTypeParameter> usedParameters = new HashSet<>();
superReturnTypeInBaseClassType.accept(new PsiTypeVisitor<Object>(){
@Nullable
@Override
public Object visitClassType(PsiClassType classType) {
final PsiClass aClass = classType.resolve();
if (aClass instanceof PsiTypeParameter && ArrayUtil.find(typeParameters, aClass) > -1) {
usedParameters.add((PsiTypeParameter)aClass);
for (PsiType type : types) {
type.accept(new PsiTypeVisitor<Object>() {
@Nullable
@Override
public Object visitClassType(PsiClassType classType) {
final PsiClass aClass = classType.resolve();
if (aClass instanceof PsiTypeParameter && ArrayUtil.find(typeParameters, aClass) > -1) {
usedParameters.add((PsiTypeParameter)aClass);
return null;
}
for (PsiType type : classType.getParameters()) {
type.accept(this);
}
return null;
}
for (PsiType type : classType.getParameters()) {
type.accept(this);
@Nullable
@Override
public Object visitWildcardType(PsiWildcardType wildcardType) {
final PsiType bound = wildcardType.getBound();
return bound != null ? bound.accept(this) : null;
}
return null;
}
@Nullable
@Override
public Object visitWildcardType(PsiWildcardType wildcardType) {
final PsiType bound = wildcardType.getBound();
return bound != null ? bound.accept(this) : null;
}
@Nullable
@Override
public Object visitArrayType(PsiArrayType arrayType) {
return arrayType.getComponentType().accept(this);
}
});
@Nullable
@Override
public Object visitArrayType(PsiArrayType arrayType) {
return arrayType.getComponentType().accept(this);
}
});
}
return usedParameters.toArray(new PsiTypeParameter[usedParameters.size()]);
}
@NotNull
public static PsiTypeParameter[] filterUnusedTypeParameters(final PsiType superReturnTypeInBaseClassType,
@NotNull PsiTypeParameter[] typeParameters) {
return filterUnusedTypeParameters(typeParameters, superReturnTypeInBaseClassType);
}
}
@@ -237,7 +237,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
psiSubstitutor = getParameterizedTypeSubstitutor(qContainingClass, pType);
}
else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) {
//15.13.1
//15.13.1
//If ClassType is a raw type, but is not a non-static member type of a raw type,
//the candidate notional member methods are those specified in §15.9.3 for a class instance creation expression that uses <>
//to elide the type arguments to a class.
@@ -247,7 +247,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
LOG.assertTrue(paramTypes.length == signature.getParameterTypes().length, "expr: " + methodReferenceExpression + "; " +
paramTypes.length + "; " +
Arrays.toString(signature.getParameterTypes()));
psiSubstitutor = helper.inferTypeArguments(qContainingClass.getTypeParameters(),
psiSubstitutor = helper.inferTypeArguments(PsiTypesUtil.filterUnusedTypeParameters(qContainingClass.getTypeParameters(), paramTypes),
paramTypes,
signature.getParameterTypes(),
PsiUtil.getLanguageLevel(methodReferenceExpression));
@@ -0,0 +1,28 @@
import java.util.function.Function;
abstract class View<Tv, Av, Bv> {
public Const<Av, Tv> apply(final Fixed<Tv, Av, Bv, Const<Av, Tv>, Const<Av, Bv>> fix) {
return fix.apply(Const::new);
}
}
@FunctionalInterface
interface Fixed< T, A, B,
FT extends Functor<T>,
FB extends Functor<B>> {
FT apply(Function< A, FB> function);
}
interface Functor<A> {
}
final class Const<A, B> implements Functor<B> {
A a;
public Const(A a) {
this.a = a;
}
}
@@ -167,6 +167,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testReturnTypeCompatibilityConstraintForSecondSearchCase() { doTest(); }
public void testMethodInInheritorFoundBySecondSearch() { doTest(); }
public void testNonExactMethodReferenceOnRawClassType() { doTest(); }
public void testIncludeOnlyTypeParametersUsedInParameterTypesExcludeThoseUsedInReturnOnly() { doTest(); }
public void testMethodREfToContainingMethodWithGenericParam() { doTest(); }
public void testDistinguishCapturedWildcardsByDifferentParameters() throws Exception { doTest(); }