diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/JavaResolveExtension.kt b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/JavaResolveExtension.kt index 8c0ec430fdb..8f5a07c29d9 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/JavaResolveExtension.kt +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/JavaResolveExtension.kt @@ -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> { override val platform: TargetPlatform = TargetPlatform.JVM @@ -38,4 +45,17 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair resolver.resolveConstructor(JavaConstructorImpl(this)) + else -> resolver.resolveMethod(JavaMethodImpl(this)) + } + assert(methodDescriptor != null) { "No descriptor found for " + getText() } + + return methodDescriptor!! } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java index 95afe4edf40..2de77ae7f36 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java @@ -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 parameterDescriptors = functionDescriptor.getValueParameters(); + List newParameters = KotlinPackage.map( + KotlinPackage.withIndices(javaChangeInfo.getNewParameters()), + new Function1, JetParameterInfo>() { + @Override + public JetParameterInfo invoke(Pair 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() + ); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java index fb8cc4484fe..31f11d29bea 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java @@ -62,14 +62,21 @@ public final class JetChangeSignatureData implements JetMethodDescriptor { this.descriptorsForSignatureChange = descriptorsForSignatureChange; final List 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( ContainerUtil.map(this.baseDescriptor.getValueParameters(), new Function() { @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 + ); } })); } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java index c6072652600..0b9e372cd1a 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -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 diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinCallUsage.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinCallUsage.kt new file mode 100644 index 00000000000..93d920b92dd --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinCallUsage.kt @@ -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) +} diff --git a/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesAfter.1.kt b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesAfter.1.kt new file mode 100644 index 00000000000..8360cab72ab --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesAfter.1.kt @@ -0,0 +1,4 @@ +fun test() { + J("1") + J("3") +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesAfter.java b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesAfter.java new file mode 100644 index 00000000000..3c247b01af4 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesAfter.java @@ -0,0 +1,5 @@ +class J { + J(String s) { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesBefore.1.kt b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesBefore.1.kt new file mode 100644 index 00000000000..9bab37bf509 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesBefore.1.kt @@ -0,0 +1,4 @@ +fun test() { + J("1", 2) + J("3", 4) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesBefore.java b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesBefore.java new file mode 100644 index 00000000000..2719b2802ed --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaConstructorKotlinUsagesBefore.java @@ -0,0 +1,5 @@ +class J { + J(String s, int n) { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesAfter.1.kt b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesAfter.1.kt new file mode 100644 index 00000000000..0269874ea59 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesAfter.1.kt @@ -0,0 +1,6 @@ +import J.bar + +fun test() { + J.bar("1") + J.bar("3") +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesAfter.java b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesAfter.java new file mode 100644 index 00000000000..0b2fcad948d --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesAfter.java @@ -0,0 +1,5 @@ +class J { + static void bar(String s) { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesBefore.1.kt b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesBefore.1.kt new file mode 100644 index 00000000000..1286ce13afc --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesBefore.1.kt @@ -0,0 +1,6 @@ +import J.foo + +fun test() { + J.foo("1", 2) + J.foo("3", 4) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesBefore.java b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesBefore.java new file mode 100644 index 00000000000..bb1d4d8f8e5 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/JavaMethodKotlinUsagesBefore.java @@ -0,0 +1,5 @@ +class J { + static void foo(String s, int n) { + + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java index e5209c1ae34..0da5789cbbb 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java @@ -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");