Change Signature: Reduce JetChangeSignatureUsageProcessor state to prevent
memory leaks. JetMethodDescriptor is stored in UsageInfo list
This commit is contained in:
@@ -49,7 +49,7 @@ import java.util.ArrayList
|
|||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
|
|
||||||
public class JetChangeInfo(
|
public open class JetChangeInfo(
|
||||||
val methodDescriptor: JetMethodDescriptor,
|
val methodDescriptor: JetMethodDescriptor,
|
||||||
private var name: String = methodDescriptor.getName(),
|
private var name: String = methodDescriptor.getName(),
|
||||||
val newReturnType: JetType? = methodDescriptor.baseDescriptor.getReturnType(),
|
val newReturnType: JetType? = methodDescriptor.baseDescriptor.getReturnType(),
|
||||||
|
|||||||
+75
-37
@@ -83,12 +83,48 @@ import org.jetbrains.kotlin.types.TypeUtils;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
|
public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
|
||||||
|
// This is special 'PsiElement' whose purpose is to wrap JetMethodDescriptor so that it can be kept in the usage list
|
||||||
|
private static class OriginalJavaMethodDescriptorWrapper extends UsageInfo {
|
||||||
|
JetMethodDescriptor originalJavaMethodDescriptor;
|
||||||
|
|
||||||
|
public OriginalJavaMethodDescriptorWrapper(@NotNull PsiElement element) {
|
||||||
|
super(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DummyJetChangeInfo extends JetChangeInfo {
|
||||||
|
public DummyJetChangeInfo(
|
||||||
|
@NotNull PsiElement method,
|
||||||
|
@NotNull JetMethodDescriptor methodDescriptor
|
||||||
|
) {
|
||||||
|
super(methodDescriptor,
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
"",
|
||||||
|
Visibilities.INTERNAL,
|
||||||
|
Collections.<JetParameterInfo>emptyList(),
|
||||||
|
null,
|
||||||
|
method,
|
||||||
|
Collections.<PsiElement>emptyList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static OriginalJavaMethodDescriptorWrapper getOriginalJavaMethodDescriptorWrapper(@NotNull UsageInfo[] usages) {
|
||||||
|
return KotlinPackage.firstOrNull(KotlinPackage.filterIsInstance(usages, OriginalJavaMethodDescriptorWrapper.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's here to prevent O(usage_count^2) performance
|
||||||
|
private boolean initializedOriginalDescriptor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsageInfo[] findUsages(ChangeInfo info) {
|
public UsageInfo[] findUsages(ChangeInfo info) {
|
||||||
originalJavaMethodDescriptor = null;
|
initializedOriginalDescriptor = false;
|
||||||
|
|
||||||
Set<UsageInfo> result = new HashSet<UsageInfo>();
|
Set<UsageInfo> result = new HashSet<UsageInfo>();
|
||||||
|
|
||||||
|
result.add(new OriginalJavaMethodDescriptorWrapper(info.getMethod()));
|
||||||
|
|
||||||
if (info instanceof JetChangeInfo) {
|
if (info instanceof JetChangeInfo) {
|
||||||
findAllMethodUsages((JetChangeInfo) info, result);
|
findAllMethodUsages((JetChangeInfo) info, result);
|
||||||
}
|
}
|
||||||
@@ -813,8 +849,6 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetMethodDescriptor originalJavaMethodDescriptor;
|
|
||||||
|
|
||||||
private static boolean isJavaMethodUsage(UsageInfo usageInfo) {
|
private static boolean isJavaMethodUsage(UsageInfo usageInfo) {
|
||||||
// MoveRenameUsageInfo corresponds to non-Java usage of Java method
|
// MoveRenameUsageInfo corresponds to non-Java usage of Java method
|
||||||
return usageInfo instanceof JavaMethodDeferredKotlinUsage || usageInfo instanceof MoveRenameUsageInfo;
|
return usageInfo instanceof JavaMethodDeferredKotlinUsage || usageInfo instanceof MoveRenameUsageInfo;
|
||||||
@@ -836,6 +870,11 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
|||||||
refTarget != null && ChangeSignaturePackage.isCaller(refTarget, allUsages));
|
refTarget != null && ChangeSignaturePackage.isCaller(refTarget, allUsages));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean canCreateReplacementUsage(UsageInfo originalUsageInfo) {
|
||||||
|
if (originalUsageInfo instanceof JavaMethodDeferredKotlinUsage) return true;
|
||||||
|
return PsiTreeUtil.getParentOfType(originalUsageInfo.getElement(), JetCallElement.class) != null;
|
||||||
|
}
|
||||||
|
|
||||||
private static class NullabilityPropagator {
|
private static class NullabilityPropagator {
|
||||||
private final NullableNotNullManager nullManager;
|
private final NullableNotNullManager nullManager;
|
||||||
private final JavaPsiFacade javaPsiFacade;
|
private final JavaPsiFacade javaPsiFacade;
|
||||||
@@ -958,55 +997,54 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (beforeMethodChange) {
|
if (beforeMethodChange) {
|
||||||
boolean startedFromJava = method instanceof PsiMethod;
|
if (!(method instanceof PsiMethod) || initializedOriginalDescriptor) return true;
|
||||||
if (startedFromJava && originalJavaMethodDescriptor == null) {
|
|
||||||
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
|
|
||||||
assert methodDescriptor != null;
|
|
||||||
originalJavaMethodDescriptor =
|
|
||||||
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));;
|
|
||||||
|
|
||||||
// This change info is used as a placeholder before primary method update
|
OriginalJavaMethodDescriptorWrapper descriptorWrapper = getOriginalJavaMethodDescriptorWrapper(usages);
|
||||||
// It gets replaced with real change info afterwards
|
if (descriptorWrapper == null || descriptorWrapper.originalJavaMethodDescriptor != null) return true;
|
||||||
JetChangeInfo dummyChangeInfo =
|
|
||||||
new JetChangeInfo(originalJavaMethodDescriptor,
|
|
||||||
"",
|
|
||||||
null,
|
|
||||||
"",
|
|
||||||
Visibilities.INTERNAL,
|
|
||||||
Collections.<JetParameterInfo>emptyList(),
|
|
||||||
null,
|
|
||||||
changeInfo.getMethod(),
|
|
||||||
Collections.<PsiElement>emptyList());
|
|
||||||
for (int i = 0; i < usages.length; i++) {
|
|
||||||
UsageInfo oldUsageInfo = usages[i];
|
|
||||||
if (!isJavaMethodUsage(oldUsageInfo)) continue;
|
|
||||||
|
|
||||||
UsageInfo newUsageInfo = createReplacementUsage(oldUsageInfo, dummyChangeInfo, usages);
|
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
|
||||||
if (newUsageInfo != null) {
|
assert methodDescriptor != null;
|
||||||
usages[i] = newUsageInfo;
|
descriptorWrapper.originalJavaMethodDescriptor =
|
||||||
}
|
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));
|
||||||
|
|
||||||
|
// This change info is used as a placeholder before primary method update
|
||||||
|
// It gets replaced with real change info afterwards
|
||||||
|
JetChangeInfo dummyChangeInfo = new DummyJetChangeInfo(changeInfo.getMethod(), descriptorWrapper.originalJavaMethodDescriptor);
|
||||||
|
for (int i = 0; i < usages.length; i++) {
|
||||||
|
UsageInfo oldUsageInfo = usages[i];
|
||||||
|
if (!isJavaMethodUsage(oldUsageInfo)) continue;
|
||||||
|
|
||||||
|
UsageInfo newUsageInfo = createReplacementUsage(oldUsageInfo, dummyChangeInfo, usages);
|
||||||
|
if (newUsageInfo != null) {
|
||||||
|
usages[i] = newUsageInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializedOriginalDescriptor = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsiElement element = usageInfo.getElement();
|
PsiElement element = usageInfo.getElement();
|
||||||
if (element == null) return false;
|
if (element == null) return false;
|
||||||
|
|
||||||
if (originalJavaMethodDescriptor != null) {
|
if (usageInfo instanceof JavaMethodKotlinUsageWithDelegate) {
|
||||||
JetChangeInfo javaMethodChangeInfo = ChangeSignaturePackage.toJetChangeInfo(changeInfo, originalJavaMethodDescriptor);
|
JavaMethodKotlinUsageWithDelegate usageWithDelegate = (JavaMethodKotlinUsageWithDelegate) usageInfo;
|
||||||
originalJavaMethodDescriptor = null;
|
// Do not call getOriginalJavaMethodDescriptorWrapper() on each usage to avoid O(usage_count^2) performance
|
||||||
|
if (((JavaMethodKotlinUsageWithDelegate) usageInfo).getJavaMethodChangeInfo() instanceof DummyJetChangeInfo) {
|
||||||
|
OriginalJavaMethodDescriptorWrapper descriptorWrapper = getOriginalJavaMethodDescriptorWrapper(usages);
|
||||||
|
JetMethodDescriptor methodDescriptor = descriptorWrapper != null ? descriptorWrapper.originalJavaMethodDescriptor : null;
|
||||||
|
if (methodDescriptor == null) return true;
|
||||||
|
|
||||||
for (UsageInfo info : usages) {
|
JetChangeInfo javaMethodChangeInfo = ChangeSignaturePackage.toJetChangeInfo(changeInfo, methodDescriptor);
|
||||||
if (info instanceof JavaMethodKotlinUsageWithDelegate) {
|
for (UsageInfo info : usages) {
|
||||||
((JavaMethodKotlinUsageWithDelegate) info).setJavaMethodChangeInfo(javaMethodChangeInfo);
|
if (info instanceof JavaMethodKotlinUsageWithDelegate) {
|
||||||
|
((JavaMethodKotlinUsageWithDelegate) info).setJavaMethodChangeInfo(javaMethodChangeInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (usageInfo instanceof JavaMethodKotlinUsageWithDelegate) {
|
return usageWithDelegate.processUsage(usages);
|
||||||
return ((JavaMethodKotlinUsageWithDelegate) usageInfo).processUsage(usages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usageInfo instanceof MoveRenameUsageInfo && isJavaMethodUsage) {
|
if (usageInfo instanceof MoveRenameUsageInfo && isJavaMethodUsage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user