mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
redundant type arguments: recapture captured wildcards for original elements (IDEA-242856)
GitOrigin-RevId: 6f2da6bbdbc50708571177d6ff5f279a4fee8eb1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
e2f1377a65
commit
70232ecaa1
@@ -8,26 +8,26 @@ import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.PsiImmediateClassType;
|
||||
import com.intellij.psi.impl.RecaptureTypeMapper;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.bugs.NullArgumentToVariableArgMethodInspection;
|
||||
import com.siyeh.ig.psiutils.ExpectedTypeUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RedundantCastUtil {
|
||||
private static final Logger LOG = Logger.getInstance(RedundantCastUtil.class);
|
||||
private static final Key<PsiElement> SELF_REFERENCE = Key.create("SELF_REFERENCE");
|
||||
|
||||
private RedundantCastUtil() { }
|
||||
|
||||
@@ -269,9 +269,9 @@ public class RedundantCastUtil {
|
||||
if (newCall == null) return false;
|
||||
PsiExpression newQualifier = deparenthesizeExpression(newCall.getMethodExpression().getQualifierExpression());
|
||||
LOG.assertTrue(newQualifier != null);
|
||||
PsiElement oldReference = newQualifier.getCopyableUserData(SELF_REFERENCE);
|
||||
PsiElement oldReference = newQualifier.getCopyableUserData(RecaptureTypeMapper.SELF_REFERENCE);
|
||||
PsiElement replace = newQualifier.replace(getInnerMostOperand(newQualifier));
|
||||
replace.putCopyableUserData(SELF_REFERENCE, oldReference);
|
||||
replace.putCopyableUserData(RecaptureTypeMapper.SELF_REFERENCE, oldReference);
|
||||
|
||||
final JavaResolveResult newResult = newCall.getMethodExpression().advancedResolve(false);
|
||||
if (!newResult.isValidResult()) return false;
|
||||
@@ -282,7 +282,7 @@ public class RedundantCastUtil {
|
||||
PsiType newReturnType = newCall.getType();
|
||||
PsiType oldReturnType = ((PsiMethodCallExpression)parent).getType();
|
||||
|
||||
if (Comparing.equal(newReturnType == null ? null : new RedundantCastRecaptureMapper().mapType(newReturnType), oldReturnType) &&
|
||||
if (Comparing.equal(newReturnType == null ? null : new RecaptureTypeMapper().mapType(newReturnType), oldReturnType) &&
|
||||
(Comparing.equal(newTargetMethod, targetMethod) ||
|
||||
!(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) &&
|
||||
MethodSignatureUtil.isSuperMethod(newTargetMethod, targetMethod) &&
|
||||
@@ -391,7 +391,7 @@ public class RedundantCastUtil {
|
||||
return oldMethod.equals(newResult.getElement()) &&
|
||||
newResult.isValidResult() &&
|
||||
!(newResult instanceof MethodCandidateInfo && ((MethodCandidateInfo)newResult).getInferenceErrorMessage() != null) &&
|
||||
new RedundantCastRecaptureMapper().recapture(newResult.getSubstitutor()).equals(oldResult.getSubstitutor());
|
||||
new RecaptureTypeMapper().recapture(newResult.getSubstitutor()).equals(oldResult.getSubstitutor());
|
||||
}
|
||||
|
||||
private static boolean castForBoxing(PsiExpression operand, PsiType oppositeType, PsiType conditionalType) {
|
||||
@@ -557,43 +557,16 @@ public class RedundantCastUtil {
|
||||
|
||||
@Nullable
|
||||
private static PsiCall copyCallExpression(PsiCall expression, PsiType typeByParent) {
|
||||
class Encoder {
|
||||
private void encode(PsiElement expression) {
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiExpression) {
|
||||
element.putCopyableUserData(SELF_REFERENCE, element);
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void clean(PsiElement expression) {
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiExpression) {
|
||||
element.putCopyableUserData(SELF_REFERENCE, null);
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Encoder encoder = new Encoder();
|
||||
PsiElement encoded = null;
|
||||
try {
|
||||
if (typeByParent != null && PsiTypesUtil.isDenotableType(typeByParent, expression)) {
|
||||
encoder.encode(encoded = expression);
|
||||
RecaptureTypeMapper.encode(encoded = expression);
|
||||
return (PsiCall)LambdaUtil.copyWithExpectedType(expression, typeByParent);
|
||||
}
|
||||
else {
|
||||
final PsiCall call = LambdaUtil.treeWalkUp(expression);
|
||||
if (call != null) {
|
||||
encoder.encode(encoded = call);
|
||||
RecaptureTypeMapper.encode(encoded = call);
|
||||
Object marker = new Object();
|
||||
PsiTreeUtil.mark(expression, marker);
|
||||
final PsiCall callCopy = LambdaUtil.copyTopLevelCall(call);
|
||||
@@ -601,7 +574,7 @@ public class RedundantCastUtil {
|
||||
return (PsiCall)PsiTreeUtil.releaseMark(callCopy, marker);
|
||||
}
|
||||
else {
|
||||
encoder.encode(encoded = expression);
|
||||
RecaptureTypeMapper.encode(encoded = expression);
|
||||
return (PsiCall)expression.copy();
|
||||
}
|
||||
}
|
||||
@@ -611,7 +584,7 @@ public class RedundantCastUtil {
|
||||
}
|
||||
finally {
|
||||
if (encoded != null) {
|
||||
encoder.clean(encoded);
|
||||
RecaptureTypeMapper.clean(encoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -966,49 +939,6 @@ public class RedundantCastUtil {
|
||||
}
|
||||
super.visitArrayAccessExpression(expression);
|
||||
}
|
||||
|
||||
private static class RedundantCastRecaptureMapper extends PsiTypeMapper {
|
||||
private final Set<PsiClassType> myVisited = ContainerUtil.newIdentityTroveSet();
|
||||
|
||||
@Override
|
||||
public PsiType visitType(@NotNull PsiType type) {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType visitClassType(@NotNull PsiClassType classType) {
|
||||
if (!myVisited.add(classType)) return classType;
|
||||
final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
|
||||
final PsiClass psiClass = classResolveResult.getElement();
|
||||
final PsiSubstitutor substitutor = classResolveResult.getSubstitutor();
|
||||
if (psiClass == null) return classType;
|
||||
return new PsiImmediateClassType(psiClass, recapture(substitutor));
|
||||
}
|
||||
|
||||
PsiSubstitutor recapture(PsiSubstitutor substitutor) {
|
||||
PsiSubstitutor result = PsiSubstitutor.EMPTY;
|
||||
for (Map.Entry<PsiTypeParameter, PsiType> entry : substitutor.getSubstitutionMap().entrySet()) {
|
||||
PsiType value = entry.getValue();
|
||||
result = result.put(entry.getKey(), value == null ? null : mapType(value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType visitCapturedWildcardType(@NotNull PsiCapturedWildcardType capturedWildcardType) {
|
||||
PsiElement context = capturedWildcardType.getContext();
|
||||
@Nullable PsiElement original = context.getCopyableUserData(SELF_REFERENCE);
|
||||
if (original != null) {
|
||||
context = original;
|
||||
}
|
||||
PsiCapturedWildcardType mapped =
|
||||
PsiCapturedWildcardType.create(capturedWildcardType.getWildcard(), context, capturedWildcardType.getTypeParameter());
|
||||
|
||||
mapped.setUpperBound(capturedWildcardType.getUpperBound(false).accept(this));
|
||||
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isTypeCastSemantic(PsiTypeCastExpression typeCast) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PsiDiamondTypeUtil {
|
||||
private static final Logger LOG = Logger.getInstance(PsiDiamondTypeUtil.class);
|
||||
@@ -180,13 +181,15 @@ public class PsiDiamondTypeUtil {
|
||||
boolean constructorRef,
|
||||
@Nullable PsiMethod method,
|
||||
PsiTypeParameter[] typeParameters) {
|
||||
PsiElement encoded = null;
|
||||
try {
|
||||
final PsiElement copy;
|
||||
final PsiType typeByParent = PsiTypesUtil.getExpectedTypeByParent(context);
|
||||
if (typeByParent != null) {
|
||||
if (typeByParent != null && PsiTypesUtil.isDenotableType(typeByParent, context)) {
|
||||
if (isAugmented(context)) {
|
||||
return false;
|
||||
}
|
||||
RecaptureTypeMapper.encode(encoded = context);
|
||||
copy = LambdaUtil.copyWithExpectedType(context, typeByParent);
|
||||
}
|
||||
else {
|
||||
@@ -195,6 +198,7 @@ public class PsiDiamondTypeUtil {
|
||||
PsiTreeUtil.mark(argumentList != null ? argumentList : context, marker);
|
||||
final PsiCall call = LambdaUtil.treeWalkUp(context);
|
||||
if (call != null) {
|
||||
RecaptureTypeMapper.encode(encoded = call);
|
||||
final PsiCall callCopy = LambdaUtil.copyTopLevelCall(call);
|
||||
copy = callCopy != null ? PsiTreeUtil.releaseMark(callCopy, marker) : null;
|
||||
}
|
||||
@@ -245,15 +249,24 @@ public class PsiDiamondTypeUtil {
|
||||
|
||||
PsiCallExpression newParentCall = exprCopy != null ? PsiTreeUtil.getParentOfType(exprCopy, PsiCallExpression.class) : null;
|
||||
PsiCallExpression oldParentCall = PsiTreeUtil.getParentOfType(context, PsiCallExpression.class);
|
||||
if (newParentCall != null && oldParentCall != null &&
|
||||
!newParentCall.resolveMethodGenerics().equals(oldParentCall.resolveMethodGenerics())) {
|
||||
return false;
|
||||
if (newParentCall != null && oldParentCall != null) {
|
||||
JavaResolveResult newResult = newParentCall.resolveMethodGenerics();
|
||||
JavaResolveResult oldResult = oldParentCall.resolveMethodGenerics();
|
||||
if (!Objects.equals(newResult.getElement(), oldResult.getElement()) ||
|
||||
!new RecaptureTypeMapper().recapture(newResult.getSubstitutor()).equals(oldResult.getSubstitutor())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.info(e);
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
if (encoded != null) {
|
||||
RecaptureTypeMapper.clean(encoded);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.PsiImmediateClassType;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class RecaptureTypeMapper extends PsiTypeMapper {
|
||||
public static final Key<PsiElement> SELF_REFERENCE = Key.create("SELF_REFERENCE");
|
||||
private final Set<PsiClassType> myVisited = ContainerUtil.newIdentityTroveSet();
|
||||
|
||||
@Override
|
||||
public PsiType visitType(@NotNull PsiType type) {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType visitClassType(@NotNull PsiClassType classType) {
|
||||
if (!myVisited.add(classType)) return classType;
|
||||
final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
|
||||
final PsiClass psiClass = classResolveResult.getElement();
|
||||
final PsiSubstitutor substitutor = classResolveResult.getSubstitutor();
|
||||
if (psiClass == null) return classType;
|
||||
return new PsiImmediateClassType(psiClass, recapture(substitutor));
|
||||
}
|
||||
|
||||
public PsiSubstitutor recapture(PsiSubstitutor substitutor) {
|
||||
PsiSubstitutor result = PsiSubstitutor.EMPTY;
|
||||
for (Map.Entry<PsiTypeParameter, PsiType> entry : substitutor.getSubstitutionMap().entrySet()) {
|
||||
PsiType value = entry.getValue();
|
||||
result = result.put(entry.getKey(), value == null ? null : mapType(value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType visitCapturedWildcardType(@NotNull PsiCapturedWildcardType capturedWildcardType) {
|
||||
PsiElement context = capturedWildcardType.getContext();
|
||||
@Nullable PsiElement original = context.getCopyableUserData(SELF_REFERENCE);
|
||||
if (original != null) {
|
||||
context = original;
|
||||
}
|
||||
PsiCapturedWildcardType mapped =
|
||||
PsiCapturedWildcardType.create(capturedWildcardType.getWildcard(), context, capturedWildcardType.getTypeParameter());
|
||||
|
||||
mapped.setUpperBound(capturedWildcardType.getUpperBound(false).accept(this));
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
public static void encode(PsiElement expression) {
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiExpression) {
|
||||
element.putCopyableUserData(SELF_REFERENCE, element);
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void clean(PsiElement expression) {
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiExpression) {
|
||||
element.putCopyableUserData(SELF_REFERENCE, null);
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Replace with <>" "true"
|
||||
interface I<T> {
|
||||
I<T> then(T t);
|
||||
}
|
||||
class J<T extends String> {}
|
||||
class MyTest {
|
||||
|
||||
<K> I<K> when(K p) { return null;}
|
||||
|
||||
|
||||
|
||||
void m(J<?> l){
|
||||
|
||||
when(l).then((J) new J<>());
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Replace with <>" "true"
|
||||
interface I<T> {
|
||||
I<T> then(T t);
|
||||
}
|
||||
class J<T extends String> {}
|
||||
class MyTest {
|
||||
|
||||
<K> I<K> when(K p) { return null;}
|
||||
|
||||
|
||||
|
||||
void m(J<?> l){
|
||||
|
||||
when(l).then((J)new J<Str<caret>ing>());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user