Change Signature: Process Kotlin-based usages when changing signature of the Java function
This commit is contained in:
+20
@@ -22,6 +22,13 @@ import org.jetbrains.jet.lang.resolve.java.JvmResolverForModule
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.asJava.KotlinLightMethod
|
||||
import org.jetbrains.jet.lang.resolve.java.resolveMethod
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaMethodImpl
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaConstructorImpl
|
||||
import org.jetbrains.jet.lang.resolve.java.resolveConstructor
|
||||
|
||||
public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDescriptorResolver, BindingContext>> {
|
||||
override val platform: TargetPlatform = TargetPlatform.JVM
|
||||
@@ -38,4 +45,17 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDes
|
||||
|
||||
public fun getContext(project: Project, element: PsiElement): BindingContext =
|
||||
KotlinCacheService.getInstance(project)[this](element).second
|
||||
}
|
||||
|
||||
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
|
||||
if (this is KotlinLightMethod) throw AssertionError("Light methods are not allowed here: ${origin?.getText()}")
|
||||
|
||||
val resolver = JavaResolveExtension.getResolver(getProject(), this)
|
||||
val methodDescriptor = when {
|
||||
this.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(this))
|
||||
else -> resolver.resolveMethod(JavaMethodImpl(this))
|
||||
}
|
||||
assert(methodDescriptor != null) { "No descriptor found for " + getText() }
|
||||
|
||||
return methodDescriptor!!
|
||||
}
|
||||
@@ -22,14 +22,12 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.changeSignature.ChangeInfo;
|
||||
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
|
||||
import com.intellij.refactoring.changeSignature.JavaChangeInfo;
|
||||
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
|
||||
import com.intellij.refactoring.changeSignature.*;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import kotlin.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -44,6 +42,7 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@@ -339,4 +338,45 @@ public class JetChangeInfo implements ChangeInfo {
|
||||
primaryMethodUpdated = true;
|
||||
javaChangeInfo = null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetChangeInfo fromJavaChangeInfo(
|
||||
@NotNull ChangeInfo javaChangeInfo,
|
||||
@NotNull JetMethodDescriptor originalChangeSignatureDescriptor
|
||||
) {
|
||||
PsiMethod method = (PsiMethod) javaChangeInfo.getMethod();
|
||||
|
||||
FunctionDescriptor functionDescriptor = ResolvePackage.getJavaMethodDescriptor(method);
|
||||
|
||||
final List<ValueParameterDescriptor> parameterDescriptors = functionDescriptor.getValueParameters();
|
||||
List<JetParameterInfo> newParameters = KotlinPackage.map(
|
||||
KotlinPackage.withIndices(javaChangeInfo.getNewParameters()),
|
||||
new Function1<Pair<? extends Integer, ? extends ParameterInfo>, JetParameterInfo>() {
|
||||
@Override
|
||||
public JetParameterInfo invoke(Pair<? extends Integer, ? extends ParameterInfo> pair) {
|
||||
ParameterInfo info = pair.getSecond();
|
||||
JetParameterInfo jetParameterInfo = new JetParameterInfo(
|
||||
info.getOldIndex(),
|
||||
info.getName(),
|
||||
parameterDescriptors.get(pair.getFirst()).getType(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
jetParameterInfo.setDefaultValueText(info.getDefaultValue());
|
||||
return jetParameterInfo;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return new JetChangeInfo(
|
||||
originalChangeSignatureDescriptor,
|
||||
javaChangeInfo.getNewName(),
|
||||
functionDescriptor.getReturnType(),
|
||||
"",
|
||||
functionDescriptor.getVisibility(),
|
||||
newParameters,
|
||||
method,
|
||||
new JetGeneratedInfo()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-4
@@ -62,14 +62,21 @@ public final class JetChangeSignatureData implements JetMethodDescriptor {
|
||||
this.descriptorsForSignatureChange = descriptorsForSignatureChange;
|
||||
final List<JetParameter> valueParameters = this.baseDeclaration instanceof JetFunction
|
||||
? ((JetFunction) this.baseDeclaration).getValueParameters()
|
||||
: ((JetClass) this.baseDeclaration).getPrimaryConstructorParameters();
|
||||
: this.baseDeclaration instanceof JetClass
|
||||
? ((JetClass) this.baseDeclaration).getPrimaryConstructorParameters()
|
||||
: null;
|
||||
this.parameters = new ArrayList<JetParameterInfo>(
|
||||
ContainerUtil.map(this.baseDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetParameterInfo>() {
|
||||
@Override
|
||||
public JetParameterInfo fun(ValueParameterDescriptor param) {
|
||||
JetParameter parameter = valueParameters.get(param.getIndex());
|
||||
return new JetParameterInfo(param.getIndex(), param.getName().asString(), param.getType(),
|
||||
parameter.getDefaultValue(), parameter.getValOrVarNode());
|
||||
JetParameter parameter = valueParameters != null ? valueParameters.get(param.getIndex()) : null;
|
||||
return new JetParameterInfo(
|
||||
param.getIndex(),
|
||||
param.getName().asString(),
|
||||
param.getType(),
|
||||
parameter != null ? parameter.getDefaultValue() : null,
|
||||
parameter != null ? parameter.getValOrVarNode() : null
|
||||
);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
+74
-5
@@ -19,10 +19,13 @@ package org.jetbrains.jet.plugin.refactoring.changeSignature;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.changeSignature.*;
|
||||
import com.intellij.refactoring.rename.ResolveSnapshotProvider;
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo;
|
||||
import com.intellij.refactoring.util.TextOccurrencesUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Function;
|
||||
@@ -31,6 +34,7 @@ import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.KotlinLightMethod;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -41,8 +45,10 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.*;
|
||||
import org.jetbrains.jet.plugin.references.JetSimpleNameReference;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -238,11 +244,31 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
||||
});
|
||||
}
|
||||
|
||||
private JetMethodDescriptor originalJavaMethodDescriptor;
|
||||
|
||||
private static boolean isJavaMethodUsage(UsageInfo usageInfo) {
|
||||
if (!(usageInfo instanceof MoveRenameUsageInfo)) return false;
|
||||
PsiElement referencedElement = ((MoveRenameUsageInfo) usageInfo).getReferencedElement();
|
||||
return referencedElement instanceof PsiMethod && !(referencedElement instanceof KotlinLightMethod);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UsageInfo createFunctionCallUsage(
|
||||
UsageInfo originalUsageInfo,
|
||||
JetChangeInfo javaMethodChangeInfo
|
||||
) {
|
||||
JetCallElement callElement = PsiTreeUtil.getParentOfType(originalUsageInfo.getElement(), JetCallElement.class);
|
||||
return callElement != null ? new JavaMethodKotlinCallUsage(callElement, javaMethodChangeInfo) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processUsage(ChangeInfo changeInfo, UsageInfo usageInfo, boolean beforeMethodChange, UsageInfo[] usages) {
|
||||
PsiElement method = changeInfo.getMethod();
|
||||
boolean isJavaMethodUsage = isJavaMethodUsage(usageInfo);
|
||||
|
||||
if (usageInfo instanceof KotlinWrapperForJavaUsageInfos) {
|
||||
JavaChangeInfo javaChangeInfo = ((JetChangeInfo) changeInfo).getOrCreateJavaChangeInfo();
|
||||
assert javaChangeInfo != null : "JavaChangeInfo not found: " + changeInfo.getMethod().getText();
|
||||
assert javaChangeInfo != null : "JavaChangeInfo not found: " + method.getText();
|
||||
UsageInfo[] javaUsageInfos = ((KotlinWrapperForJavaUsageInfos) usageInfo).getJavaUsageInfos();
|
||||
ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions();
|
||||
|
||||
@@ -257,13 +283,56 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
||||
}
|
||||
}
|
||||
|
||||
if (beforeMethodChange) return true;
|
||||
if (beforeMethodChange) {
|
||||
if (isJavaMethodUsage) {
|
||||
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
|
||||
JetChangeSignatureData changeSignatureData =
|
||||
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));
|
||||
if (changeSignatureData != originalJavaMethodDescriptor) {
|
||||
originalJavaMethodDescriptor = changeSignatureData;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiElement element = usageInfo.getElement();
|
||||
if (element != null)
|
||||
return usageInfo instanceof JetUsageInfo ? ((JetUsageInfo) usageInfo).processUsage((JetChangeInfo) changeInfo, element) : true;
|
||||
else
|
||||
if (element == null) return false;
|
||||
|
||||
if (isJavaMethodUsage && originalJavaMethodDescriptor != null) {
|
||||
JetChangeInfo javaMethodChangeInfo = JetChangeInfo.fromJavaChangeInfo(changeInfo, originalJavaMethodDescriptor);
|
||||
originalJavaMethodDescriptor = null;
|
||||
|
||||
for (int i = 0; i < usages.length; i++) {
|
||||
UsageInfo oldUsageInfo = usages[i];
|
||||
if (!isJavaMethodUsage(oldUsageInfo)) continue;
|
||||
|
||||
UsageInfo newUsageInfo = createFunctionCallUsage(oldUsageInfo, javaMethodChangeInfo);
|
||||
if (newUsageInfo != null) {
|
||||
usages[i] = newUsageInfo;
|
||||
if (oldUsageInfo == usageInfo) {
|
||||
usageInfo = newUsageInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usageInfo instanceof JavaMethodKotlinCallUsage) {
|
||||
return ((JavaMethodKotlinCallUsage) usageInfo).processUsage();
|
||||
}
|
||||
|
||||
if (usageInfo instanceof MoveRenameUsageInfo && isJavaMethodUsage) {
|
||||
JetSimpleNameExpression callee = PsiTreeUtil.getParentOfType(usageInfo.getElement(), JetSimpleNameExpression.class, false);
|
||||
PsiReference ref = callee != null ? callee.getReference() : null;
|
||||
if (ref instanceof JetSimpleNameReference) {
|
||||
((JetSimpleNameReference) ref).handleElementRename(((PsiMethod)method).getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return usageInfo instanceof JetUsageInfo ? ((JetUsageInfo) usageInfo).processUsage((JetChangeInfo) changeInfo, element) : true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.plugin.refactoring.changeSignature.usages
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetCallElement
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
|
||||
public class JavaMethodKotlinCallUsage(
|
||||
val callElement: JetCallElement,
|
||||
val javaMethodChangeInfo: JetChangeInfo): UsageInfo(javaMethodChangeInfo.getMethod()) {
|
||||
private val delegateUsage = JetFunctionCallUsage(callElement, javaMethodChangeInfo.getMethod(), false)
|
||||
|
||||
fun processUsage(): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, callElement)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun test() {
|
||||
J("1")
|
||||
J("3")
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class J {
|
||||
J(String s) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun test() {
|
||||
J("1", 2)
|
||||
J("3", 4)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class J {
|
||||
<caret>J(String s, int n) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import J.bar
|
||||
|
||||
fun test() {
|
||||
J.bar("1")
|
||||
J.bar("3")
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class J {
|
||||
static void bar(String s) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import J.foo
|
||||
|
||||
fun test() {
|
||||
J.foo("1", 2)
|
||||
J.foo("3", 4)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class J {
|
||||
static void <caret>foo(String s, int n) {
|
||||
|
||||
}
|
||||
}
|
||||
+31
@@ -28,6 +28,7 @@ import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
|
||||
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
|
||||
import com.intellij.refactoring.changeSignature.ThrownExceptionInfo;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -328,6 +329,36 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
|
||||
doTest(changeInfo);
|
||||
}
|
||||
|
||||
public void testJavaMethodKotlinUsages() throws Exception {
|
||||
doJavaTest(
|
||||
new JavaRefactoringProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
String getNewName(@NotNull PsiMethod method) {
|
||||
return "bar";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
ParameterInfoImpl[] getNewParameters(@NotNull PsiMethod method) {
|
||||
return ArrayUtil.remove(super.getNewParameters(method), 1);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void testJavaConstructorKotlinUsages() throws Exception {
|
||||
doJavaTest(
|
||||
new JavaRefactoringProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
ParameterInfoImpl[] getNewParameters(@NotNull PsiMethod method) {
|
||||
return ArrayUtil.remove(super.getNewParameters(method), 1);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void testFunctionRenameJavaUsages() throws Exception {
|
||||
JetChangeInfo changeInfo = getChangeInfo();
|
||||
changeInfo.setNewName("bar");
|
||||
|
||||
Reference in New Issue
Block a user