diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java index 0f4a58c01a3..f25f871854e 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java @@ -26,18 +26,19 @@ import com.intellij.openapi.util.NullableLazyValue; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.PsiPackage; import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; import com.intellij.psi.impl.light.LightClass; import com.intellij.psi.impl.light.LightMethod; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.PsiClassHolderFileStub; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; -import jet.runtime.typeinfo.JetValueParameter; import kotlin.Function1; import kotlin.KotlinPackage; import org.jetbrains.annotations.NonNls; @@ -58,7 +59,6 @@ import org.jetbrains.jet.lexer.JetModifierKeywordToken; import org.jetbrains.jet.plugin.JetLanguage; import javax.swing.*; -import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -299,6 +299,27 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC public PsiClassHolderFileStub getStub() { return getJavaFileStub(); } + + @SuppressWarnings("Contract") + @Override + public boolean processDeclarations( + @NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement lastParent, + @NotNull PsiElement place + ) { + if (!super.processDeclarations(processor, state, lastParent, place)) return false; + + // We have to explicitly process package declarations if current file belongs to default package + // so that Java resolve can find classes located in that package + String packageName = getPackageName(); + if (!packageName.isEmpty()) return true; + + PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(packageName); + if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false; + + return true; + } }; } }; @@ -359,6 +380,11 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC return parent.getValue(); } + @Override + public PsiElement getContext() { + return getParent(); + } + @Nullable @Override public PsiTypeParameterList getTypeParameterList() { diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightMethodForDeclaration.kt b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightMethodForDeclaration.kt index 63084f0adde..9711b488064 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightMethodForDeclaration.kt +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightMethodForDeclaration.kt @@ -32,6 +32,9 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject import com.intellij.psi.impl.light.LightTypeParameterListBuilder import com.intellij.psi.search.SearchScope import com.intellij.lang.Language +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.MethodSignature +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod open public class KotlinLightMethodForDeclaration( manager: PsiManager, @@ -43,7 +46,7 @@ open public class KotlinLightMethodForDeclaration( private val paramsList: CachedValue by Delegates.blockingLazy { val cacheManager = CachedValuesManager.getManager(delegate.getProject()) cacheManager.createCachedValue({ - val parameterBuilder = LightParameterListBuilder(getManager(), JetLanguage.INSTANCE) + val parameterBuilder = LightParameterListBuilder(getManager(), JetLanguage.INSTANCE, this) for ((index, parameter) in delegate.getParameterList().getParameters().withIndices()) { parameterBuilder.addParameter(KotlinLightParameter(parameter, index, this)) @@ -56,10 +59,8 @@ open public class KotlinLightMethodForDeclaration( private val typeParamsList: CachedValue by Delegates.blockingLazy { val cacheManager = CachedValuesManager.getManager(delegate.getProject()) cacheManager.createCachedValue({ - val declaration = if (origin is JetPropertyAccessor) origin.getNonStrictParentOfType() else origin - val list = if (origin is JetClassOrObject) { - LightTypeParameterListBuilder(getManager(), getLanguage()) + KotlinLightTypeParameterListBuilder(getManager()) } else { LightClassUtil.buildLightTypeParameterList(this@KotlinLightMethodForDeclaration, origin) @@ -98,6 +99,13 @@ open public class KotlinLightMethodForDeclaration( override fun getTypeParameters(): Array = getTypeParameterList()?.let { it.getTypeParameters() } ?: PsiTypeParameter.EMPTY_ARRAY + override fun getSignature(substitutor: PsiSubstitutor): MethodSignature { + if (substitutor == PsiSubstitutor.EMPTY) { + return delegate.getSignature(substitutor) + } + return MethodSignatureBackedByPsiMethod.create(this, substitutor) + } + override fun copy(): PsiElement { return KotlinLightMethodForDeclaration(getManager()!!, delegate, origin.copy() as JetDeclaration, getContainingClass()!!) } @@ -106,6 +114,10 @@ open public class KotlinLightMethodForDeclaration( override fun getLanguage(): Language = JetLanguage.INSTANCE + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean { + return getTypeParameters().all { processor.execute(it, state) } + } + override fun equals(other: Any?): Boolean = other is KotlinLightMethodForDeclaration && getName() == other.getName() && diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameter.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameter.java index 5ee420eee07..22f2d8bfc94 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameter.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameter.java @@ -134,4 +134,10 @@ public class KotlinLightTypeParameter public Language getLanguage() { return JetLanguage.INSTANCE; } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + return obj instanceof KotlinLightTypeParameter && getOrigin().equals(((KotlinLightTypeParameter) obj).getOrigin()); + } } diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameterListBuilder.kt b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameterListBuilder.kt new file mode 100644 index 00000000000..6103918bf9c --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightTypeParameterListBuilder.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.asJava + +import com.intellij.psi.PsiManager +import org.jetbrains.jet.plugin.JetLanguage +import com.intellij.psi.impl.light.LightTypeParameterListBuilder +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.ResolveState +import com.intellij.psi.PsiElement + +public class KotlinLightTypeParameterListBuilder(manager: PsiManager): LightTypeParameterListBuilder(manager, JetLanguage.INSTANCE) { + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean { + return getTypeParameters().all { processor.execute(it, state) } + } +} \ No newline at end of file diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java index f0b06850fdd..300e9d169b0 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java @@ -301,7 +301,7 @@ public class LightClassUtil { public static PsiTypeParameterList buildLightTypeParameterList( PsiTypeParameterListOwner owner, JetDeclaration declaration) { - LightTypeParameterListBuilder builder = new LightTypeParameterListBuilder(owner.getManager(), owner.getLanguage()); + LightTypeParameterListBuilder builder = new KotlinLightTypeParameterListBuilder(owner.getManager()); if (declaration instanceof JetTypeParameterListOwner) { JetTypeParameterListOwner typeParameterListOwner = (JetTypeParameterListOwner) declaration; List parameters = typeParameterListOwner.getTypeParameters(); diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightParameterListBuilder.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightParameterListBuilder.java index 7931b23457f..0a1e4ae71e6 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightParameterListBuilder.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightParameterListBuilder.java @@ -27,10 +27,12 @@ import java.util.List; // Copy of com.intellij.psi.impl.light.LightParameterListBuilder public class LightParameterListBuilder extends LightElement implements PsiParameterList { private final List myParameters = new ArrayList(); + private final KotlinLightMethod parent; private PsiParameter[] myCachedParameters; - public LightParameterListBuilder(PsiManager manager, Language language) { + public LightParameterListBuilder(PsiManager manager, Language language, KotlinLightMethod parent) { super(manager, language); + this.parent = parent; } public void addParameter(PsiParameter parameter) { @@ -38,6 +40,11 @@ public class LightParameterListBuilder extends LightElement implements PsiParame myCachedParameters = null; } + @Override + public KotlinLightMethod getParent() { + return parent; + } + @Override public String toString() { return "Light parameter lsit"; 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 748717757f1..71a0a01696f 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java @@ -37,14 +37,16 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.Visibilities; import org.jetbrains.jet.lang.descriptors.Visibility; -import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.jet.lang.psi.JetFunction; +import org.jetbrains.jet.lang.psi.JetFunctionLiteral; import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; 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 org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionDefinitionUsage; import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers; import java.util.Collection; @@ -96,7 +98,7 @@ public class JetChangeInfo implements ChangeInfo { return KotlinPackage.firstOrNull(psiMethods); } - public String getNewSignature(@Nullable FunctionDescriptor inheritedFunctionDescriptor, boolean isInherited) { + public String getNewSignature(@NotNull JetFunctionDefinitionUsage inheritedFunction) { StringBuilder buffer = new StringBuilder(); if (isConstructor()) { @@ -112,7 +114,7 @@ public class JetChangeInfo implements ChangeInfo { buffer.append(JetTokens.FUN_KEYWORD).append(' ').append(newName); } - buffer.append(getNewParametersSignature(inheritedFunctionDescriptor, isInherited, false, buffer.length())); + buffer.append(getNewParametersSignature(inheritedFunction, buffer.length())); if (newReturnType != null && !KotlinBuiltIns.isUnit(newReturnType) && !isConstructor()) buffer.append(": ").append(newReturnTypeText); @@ -126,16 +128,12 @@ public class JetChangeInfo implements ChangeInfo { } public String getNewParametersSignature( - @Nullable FunctionDescriptor inheritedFunctionDescriptor, - boolean isInherited, - boolean hasExpectedType, + @NotNull JetFunctionDefinitionUsage inheritedFunction, int indentLength ) { - hasExpectedType = hasExpectedType && !isRefactoringTarget(inheritedFunctionDescriptor); - - boolean isLambda = inheritedFunctionDescriptor instanceof AnonymousFunctionDescriptor; - if (isLambda && newParameters.size() == 1 && !newParameters.get(0).requiresExplicitType(inheritedFunctionDescriptor, hasExpectedType)) { - return newParameters.get(0).getDeclarationSignature(isInherited, hasExpectedType, inheritedFunctionDescriptor, oldDescriptor); + boolean isLambda = inheritedFunction.getDeclaration() instanceof JetFunctionLiteral; + if (isLambda && newParameters.size() == 1 && !newParameters.get(0).requiresExplicitType(inheritedFunction)) { + return newParameters.get(0).getDeclarationSignature(0, inheritedFunction); } StringBuilder buffer = new StringBuilder("("); @@ -148,7 +146,7 @@ public class JetChangeInfo implements ChangeInfo { buffer.append(indent); } - buffer.append(parameterInfo.getDeclarationSignature(isInherited, hasExpectedType, inheritedFunctionDescriptor, oldDescriptor)); + buffer.append(parameterInfo.getDeclarationSignature(i, inheritedFunction)); } buffer.append(")"); @@ -271,10 +269,6 @@ public class JetChangeInfo implements ChangeInfo { return oldDescriptor.isConstructor(); } - public String getNewReturnTypeText() { - return newReturnTypeText; - } - public void setNewReturnTypeText(String newReturnTypeText) { this.newReturnTypeText = newReturnTypeText; } @@ -313,6 +307,17 @@ public class JetChangeInfo implements ChangeInfo { return oldDescriptor.getAffectedFunctions(); } + public String renderReturnType(@NotNull JetFunctionDefinitionUsage inheritedFunction) { + TypeSubstitutor typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor(); + if (typeSubstitutor == null) return newReturnTypeText; + + FunctionDescriptor currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor(); + if (currentBaseFunction == null) return newReturnTypeText; + + JetType originalType = currentBaseFunction.getReturnType(); + return ChangeSignaturePackage.renderTypeWithSubstitution(originalType, typeSubstitutor, newReturnTypeText, false); + } + @Nullable public JavaChangeInfo getOrCreateJavaChangeInfo() { if (javaChangeInfo == null) { 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 609b863edbd..8fac53959e1 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java @@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil; import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionDefinitionUsage; import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers; @@ -50,6 +51,8 @@ public final class JetChangeSignatureData implements JetMethodDescriptor { private final List parameters; @NotNull private final Collection descriptorsForSignatureChange; + private JetFunctionDefinitionUsage originalPrimaryFunction; + private Collection> primaryFunctions = null; private Collection affectedFunctions = null; public JetChangeSignatureData( @@ -99,26 +102,61 @@ public final class JetChangeSignatureData implements JetMethodDescriptor { parameters.clear(); } + @NotNull + @Override + public JetFunctionDefinitionUsage getOriginalPrimaryFunction() { + if (originalPrimaryFunction == null) { + originalPrimaryFunction = KotlinPackage.first( + getPrimaryFunctions(), + new Function1, Boolean>() { + @Override + public Boolean invoke(JetFunctionDefinitionUsage usage) { + return usage.getDeclaration() == baseDeclaration; + } + } + ); + } + return originalPrimaryFunction; + } + + @Override + @NotNull + public Collection> getPrimaryFunctions() { + if (primaryFunctions == null) { + primaryFunctions = KotlinPackage.map( + descriptorsForSignatureChange, + new Function1>() { + @Override + public JetFunctionDefinitionUsage invoke(FunctionDescriptor descriptor) { + PsiElement declaration = DescriptorToDeclarationUtil.INSTANCE$.getDeclaration(baseDeclaration.getProject(), + descriptor); + assert declaration != null : "No declaration found for " + descriptor; + return new JetFunctionDefinitionUsage(declaration, descriptor, null, null); + } + } + ); + } + + return primaryFunctions; + } + @Override @NotNull public Collection getAffectedFunctions() { if (affectedFunctions == null) { affectedFunctions = KotlinPackage.flatMapTo( - descriptorsForSignatureChange, + getPrimaryFunctions(), new HashSet(), - new Function1>() { + new Function1, Iterable>() { @Override - public Iterable invoke(final FunctionDescriptor descriptor) { - PsiElement declaration = DescriptorToDeclarationUtil.INSTANCE$.getDeclaration(baseDeclaration.getProject(), - descriptor); - assert declaration != null : "No declaration found for " + descriptor; - + public Iterable invoke(final JetFunctionDefinitionUsage primaryFunction) { Set result = Sets.newHashSet(); - result.add(new JetFunctionDefinitionUsage(declaration, descriptor, false)); + result.add(primaryFunction); - if (!(declaration instanceof JetNamedFunction)) return result; + PsiElement primaryDeclaration = primaryFunction.getDeclaration(); + if (!(primaryDeclaration instanceof JetNamedFunction)) return result; - final PsiMethod baseLightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) declaration); + final PsiMethod baseLightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) primaryDeclaration); // there are valid situations when light method is null: local functions and literals if (baseLightMethod == null) return result; @@ -130,9 +168,15 @@ public final class JetChangeSignatureData implements JetMethodDescriptor { public UsageInfo invoke(PsiMethod method) { if (method instanceof KotlinLightMethod) { JetDeclaration declaration = ((KotlinLightMethod) method).getOrigin(); - return declaration != null - ? new JetFunctionDefinitionUsage(declaration, descriptor, true) - : null; + if (declaration == null) return null; + + FunctionDescriptor currentDescriptor = + (FunctionDescriptor) ResolvePackage.resolveToDescriptor(declaration); + + return new JetFunctionDefinitionUsage(declaration, + currentDescriptor, + primaryFunction, + null); } return new OverriderUsageInfo(method, baseLightMethod, true, true, true); diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java index 717ce85114b..f8750103e9b 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java @@ -354,7 +354,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< @Override protected String calculateSignature() { JetChangeInfo changeInfo = evaluateChangeInfo(); - return changeInfo.getNewSignature(null, false); + return changeInfo.getNewSignature(getMethodDescriptor().getOriginalPrimaryFunction()); } @Override 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 0002e48ae1b..71ce0a0a21e 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -84,12 +84,15 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro JetChangeInfo changeInfo, Set result ) { - result.add(functionUsageInfo); + boolean isInherited = functionUsageInfo.isInherited(); + + if (isInherited) { + result.add(functionUsageInfo); + } PsiElement functionPsi = functionUsageInfo.getElement(); if (functionPsi == null) return; - boolean isInherited = functionUsageInfo.isInherited(); for (PsiReference reference : ReferencesSearch.search(functionPsi, functionPsi.getUseScope())) { PsiElement element = reference.getElement(); @@ -98,12 +101,12 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro PsiElement parent = element.getParent(); if (parent instanceof JetCallExpression) - result.add(new JetFunctionCallUsage((JetCallExpression) parent, functionUsageInfo.getFunctionDescriptor(), isInherited)); + result.add(new JetFunctionCallUsage((JetCallExpression) parent, functionUsageInfo)); else if (parent instanceof JetUserType && parent.getParent() instanceof JetTypeReference) { parent = parent.getParent().getParent(); if (parent instanceof JetConstructorCalleeExpression && parent.getParent() instanceof JetDelegatorToSuperCall) - result.add(new JetFunctionCallUsage((JetDelegatorToSuperCall)parent.getParent(), functionUsageInfo.getFunctionDescriptor(), isInherited)); + result.add(new JetFunctionCallUsage((JetDelegatorToSuperCall)parent.getParent(), functionUsageInfo)); } } } @@ -129,12 +132,8 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro if (element instanceof JetSimpleNameExpression && !(element.getParent() instanceof JetValueArgumentName)) // Usages in named arguments of the calls usage will be changed when the function call is changed { - JetParameterUsage parameterUsage = new JetParameterUsage( - (JetSimpleNameExpression) element, - parameterInfo, - functionUsageInfo.getFunctionDescriptor(), - isInherited - ); + JetParameterUsage parameterUsage = + new JetParameterUsage((JetSimpleNameExpression) element, parameterInfo, functionUsageInfo); result.add(parameterUsage); } } @@ -178,11 +177,16 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro JetExpression argExpression = arguments.get(0).getArgumentExpression(); if (!(argExpression instanceof JetFunctionLiteralExpression)) continue; + BindingContext context = ResolvePackage.analyze(callExpression); + JetFunctionLiteral functionLiteral = ((JetFunctionLiteralExpression) argExpression).getFunctionLiteral(); - FunctionDescriptor functionDescriptor = - ResolvePackage.analyze(functionLiteral).get(BindingContext.FUNCTION, functionLiteral); + FunctionDescriptor functionDescriptor = context.get(BindingContext.FUNCTION, functionLiteral); assert functionDescriptor != null : "No descriptor for " + functionLiteral.getText(); - result.add(new KotlinSAMUsage(functionLiteral, functionDescriptor)); + + JetType samCallType = context.get(BindingContext.EXPRESSION_TYPE, callExpression); + if (samCallType == null) continue; + + result.add(new KotlinSAMUsage(functionLiteral, functionDescriptor, samCallType)); } } @@ -304,12 +308,24 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro @Nullable private static UsageInfo createReplacementUsage( UsageInfo originalUsageInfo, - JetChangeInfo javaMethodChangeInfo + final JetChangeInfo javaMethodChangeInfo ) { if (originalUsageInfo instanceof KotlinSAMUsage) { - JetFunctionLiteral functionLiteral = ((KotlinSAMUsage) originalUsageInfo).getFunctionLiteral(); - FunctionDescriptor functionDescriptor = ((KotlinSAMUsage) originalUsageInfo).getFunctionDescriptor(); - return new JavaMethodKotlinDerivedDefinitionUsage(functionLiteral, functionDescriptor, javaMethodChangeInfo); + final KotlinSAMUsage samUsage = (KotlinSAMUsage) originalUsageInfo; + return new JavaMethodKotlinUsageWithDelegate(samUsage.getFunctionLiteral(), javaMethodChangeInfo) { + private final JetFunctionDefinitionUsage delegateUsage = new JetFunctionDefinitionUsage( + samUsage.getFunctionLiteral(), + samUsage.getFunctionDescriptor(), + javaMethodChangeInfo.getFunctionDescriptor().getOriginalPrimaryFunction(), + samUsage.getSamCallType() + ); + + @NotNull + @Override + protected JetUsageInfo getDelegateUsage() { + return delegateUsage; + } + }; } JetCallElement callElement = PsiTreeUtil.getParentOfType(originalUsageInfo.getElement(), JetCallElement.class); @@ -470,7 +486,13 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro @Override public boolean processPrimaryMethod(ChangeInfo changeInfo) { - ((JetChangeInfo)changeInfo).primaryMethodUpdated(); + if (!(changeInfo instanceof JetChangeInfo)) return false; + + JetChangeInfo jetChangeInfo = (JetChangeInfo) changeInfo; + for (JetFunctionDefinitionUsage primaryFunction : jetChangeInfo.getFunctionDescriptor().getPrimaryFunctions()) { + primaryFunction.processUsage(jetChangeInfo, primaryFunction.getDeclaration()); + } + jetChangeInfo.primaryMethodUpdated(); return true; } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java index 0893f03f7b4..43f21834572 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java @@ -23,10 +23,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.Visibility; +import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionDefinitionUsage; import java.util.Collection; public interface JetMethodDescriptor extends MethodDescriptor { + @NotNull + JetFunctionDefinitionUsage getOriginalPrimaryFunction(); + + @NotNull + Collection> getPrimaryFunctions(); + @NotNull Collection getAffectedFunctions(); diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java index e458b5bd449..45d1aa1555c 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java @@ -27,7 +27,9 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionDefinitionUsage; import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers; import java.util.List; @@ -73,18 +75,29 @@ public class JetParameterInfo implements ParameterInfo { return name; } - public String getInheritedName( - boolean isInherited, - @Nullable FunctionDescriptor inheritedFunctionDescriptor, - @NotNull JetMethodDescriptor baseFunction - ) { - if (!isInherited || inheritedFunctionDescriptor == null) return name; + public String renderType(int parameterIndex, @NotNull JetFunctionDefinitionUsage inheritedFunction) { + TypeSubstitutor typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor(); + if (typeSubstitutor == null) return typeText; - FunctionDescriptor baseFunctionDescriptor = baseFunction.getDescriptor(); - assert baseFunctionDescriptor != null : "No descriptor for " + baseFunction.getMethod().getText(); + FunctionDescriptor currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor(); + if (currentBaseFunction == null) return typeText; + JetType parameterType = currentBaseFunction.getValueParameters().get(parameterIndex).getType(); + + return ChangeSignaturePackage.renderTypeWithSubstitution(parameterType, typeSubstitutor, typeText, true); + } + + public String getInheritedName(@NotNull JetFunctionDefinitionUsage inheritedFunction) { + if (!inheritedFunction.isInherited()) return name; + + JetFunctionDefinitionUsage baseFunction = inheritedFunction.getBaseFunction(); + FunctionDescriptor baseFunctionDescriptor = baseFunction.getOriginalFunctionDescriptor(); + + FunctionDescriptor inheritedFunctionDescriptor = inheritedFunction.getOriginalFunctionDescriptor(); List inheritedParameterDescriptors = inheritedFunctionDescriptor.getValueParameters(); - if (oldIndex < 0 || oldIndex >= baseFunction.getParametersCount() || oldIndex >= inheritedParameterDescriptors.size()) return name; + if (oldIndex < 0 + || oldIndex >= baseFunctionDescriptor.getValueParameters().size() + || oldIndex >= inheritedParameterDescriptors.size()) return name; String inheritedParamName = inheritedParameterDescriptors.get(oldIndex).getName().asString(); String oldParamName = baseFunctionDescriptor.getValueParameters().get(oldIndex).getName().asString(); @@ -161,10 +174,11 @@ public class JetParameterInfo implements ParameterInfo { return type; } - public boolean requiresExplicitType(@Nullable FunctionDescriptor inheritedFunctionDescriptor, boolean hasExpectedType) { - if (inheritedFunctionDescriptor == null || !(inheritedFunctionDescriptor instanceof AnonymousFunctionDescriptor)) return true; + public boolean requiresExplicitType(@NotNull JetFunctionDefinitionUsage inheritedFunction) { + FunctionDescriptor inheritedFunctionDescriptor = inheritedFunction.getOriginalFunctionDescriptor(); + if (!(inheritedFunctionDescriptor instanceof AnonymousFunctionDescriptor)) return true; - if (oldIndex < 0) return !hasExpectedType; + if (oldIndex < 0) return !inheritedFunction.hasExpectedType(); ValueParameterDescriptor inheritedParameterDescriptor = inheritedFunctionDescriptor.getValueParameters().get(oldIndex); JetParameter parameter = (JetParameter) DescriptorToSourceUtils.descriptorToDeclaration(inheritedParameterDescriptor); @@ -173,11 +187,7 @@ public class JetParameterInfo implements ParameterInfo { return parameter.getTypeReference() != null; } - public String getDeclarationSignature( - boolean isInherited, - boolean hasExpectedType, - @Nullable FunctionDescriptor inheritedFunctionDescriptor, - JetMethodDescriptor baseFunction) { + public String getDeclarationSignature(int parameterIndex, @NotNull JetFunctionDefinitionUsage inheritedFunction) { StringBuilder buffer = new StringBuilder(); JetValVar valVar = getValOrVar(); @@ -185,13 +195,13 @@ public class JetParameterInfo implements ParameterInfo { buffer.append(valVar.toString()).append(' '); } - buffer.append(getInheritedName(isInherited, inheritedFunctionDescriptor, baseFunction)); + buffer.append(getInheritedName(inheritedFunction)); - if (requiresExplicitType(inheritedFunctionDescriptor, hasExpectedType)) { - buffer.append(": ").append(getTypeText()); + if (requiresExplicitType(inheritedFunction)) { + buffer.append(": ").append(renderType(parameterIndex, inheritedFunction)); } - if (defaultValue != null && !isInherited) { + if (defaultValue != null && !inheritedFunction.isInherited()) { buffer.append(" = ").append(defaultValue.getText()); } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/typeUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/typeUtils.kt new file mode 100644 index 00000000000..ffd880c8945 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/typeUtils.kt @@ -0,0 +1,77 @@ +/* + * 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 + +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.types.TypeSubstitutor +import org.jetbrains.jet.lang.types.TypeConstructor +import org.jetbrains.jet.lang.types.TypeProjection +import java.util.LinkedHashMap +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure +import org.jetbrains.jet.lang.types.TypeProjectionImpl +import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionDefinitionUsage +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers +import org.jetbrains.jet.lang.types.Variance + +private fun getTypeSubstitution(baseType: JetType, derivedType: JetType): LinkedHashMap? { + val substitutedType = TypeCheckingProcedure.findCorrespondingSupertype(derivedType, baseType) ?: return null + + val substitution = LinkedHashMap(substitutedType.getArguments().size) + for ((param, arg) in baseType.getConstructor().getParameters() zip substitutedType.getArguments()) { + substitution[param.getTypeConstructor()] = arg + } + + return substitution +} + +private fun getFunctionSubstitution( + baseFunction: FunctionDescriptor, + derivedFunction: FunctionDescriptor +): MutableMap? { + val baseClass = baseFunction.getContainingDeclaration() as? ClassDescriptor ?: return null + val derivedClass = derivedFunction.getContainingDeclaration() as? ClassDescriptor ?: return null + val substitution = getTypeSubstitution(baseClass.getDefaultType(), derivedClass.getDefaultType()) ?: return null + + for ((baseParam, derivedParam) in baseFunction.getTypeParameters() zip derivedFunction.getTypeParameters()) { + substitution[baseParam.getTypeConstructor()] = TypeProjectionImpl(derivedParam.getDefaultType()) + } + + return substitution +} + +fun getTypeSubstitutor(baseType: JetType, derivedType: JetType): TypeSubstitutor? { + return getTypeSubstitution(baseType, derivedType)?.let { TypeSubstitutor.create(it) } +} + +fun getFunctionSubstitutor( + baseFunction: JetFunctionDefinitionUsage<*>, + derivedFunction: JetFunctionDefinitionUsage<*> +): TypeSubstitutor? { + val currentBaseFunction = baseFunction.getCurrentFunctionDescriptor() + val currentDerivedFunction = derivedFunction.getCurrentFunctionDescriptor() + if (currentBaseFunction == null || currentDerivedFunction == null) return null + + return getFunctionSubstitution(currentBaseFunction, currentDerivedFunction)?.let { TypeSubstitutor.create(it) } +} + +fun JetType.renderTypeWithSubstitution(substitutor: TypeSubstitutor?, defaultText: String, inArgumentPosition: Boolean): String { + val newType = substitutor?.substitute(this, Variance.INVARIANT) ?: return defaultText + val renderer = if (inArgumentPosition) IdeDescriptorRenderers.SOURCE_CODE_FOR_TYPE_ARGUMENTS else IdeDescriptorRenderers.SOURCE_CODE + return renderer.renderType(newType) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt index 4fb30b8cedb..52650ae52b5 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt @@ -24,18 +24,18 @@ import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.lang.psi.JetFunction import org.jetbrains.jet.lang.descriptors.FunctionDescriptor -public abstract class JavaMethodKotlinUsageWithDelegate( - val jetElement: T, +public abstract class JavaMethodKotlinUsageWithDelegate( + val psiElement: T, val javaMethodChangeInfo: JetChangeInfo): UsageInfo(javaMethodChangeInfo.getMethod()) { protected abstract val delegateUsage: JetUsageInfo - fun processUsage(): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, jetElement) + fun processUsage(): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, psiElement) } public class JavaMethodKotlinCallUsage( callElement: JetCallElement, javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate(callElement, javaMethodChangeInfo) { - override protected val delegateUsage = JetFunctionCallUsage(jetElement, javaMethodChangeInfo.getFunctionDescriptor().getDescriptor(), false) + override protected val delegateUsage = JetFunctionCallUsage(psiElement, javaMethodChangeInfo.getFunctionDescriptor().getOriginalPrimaryFunction()) } public class JavaMethodKotlinDerivedDefinitionUsage( @@ -43,5 +43,10 @@ public class JavaMethodKotlinDerivedDefinitionUsage( functionDescriptor: FunctionDescriptor, javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate(function, javaMethodChangeInfo) { [suppress("CAST_NEVER_SUCCEEDS")] - override protected val delegateUsage = JetFunctionDefinitionUsage(jetElement, functionDescriptor, true) as JetUsageInfo -} \ No newline at end of file + override protected val delegateUsage = JetFunctionDefinitionUsage( + psiElement, + functionDescriptor, + javaMethodChangeInfo.getFunctionDescriptor().getOriginalPrimaryFunction(), + null + ) +} diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt index 07272f24b58..1a29e6f8d2e 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt @@ -37,7 +37,7 @@ public class JetEnumEntryWithoutSuperCallUsage(enumEntry: JetEnumEntry) : JetUsa ) as JetDelegatorToSuperCall element.addBefore(psiFactory.createColon(), delegatorToSuperCall) - return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.getFunctionDescriptor().getDescriptor(), false) + return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.getFunctionDescriptor().getOriginalPrimaryFunction()) .processUsage(changeInfo, delegatorToSuperCall) } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionCallUsage.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionCallUsage.java index a7ff6b89d80..58a01e2f887 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionCallUsage.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionCallUsage.java @@ -18,7 +18,6 @@ package org.jetbrains.jet.plugin.refactoring.changeSignature.usages; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo; @@ -30,13 +29,11 @@ import java.util.Map; import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; public class JetFunctionCallUsage extends JetUsageInfo { - private final FunctionDescriptor functionDescriptor; - private final boolean isInherited; + private final JetFunctionDefinitionUsage callee; - public JetFunctionCallUsage(@NotNull JetCallElement element, @NotNull FunctionDescriptor functionDescriptor, boolean isInherited) { + public JetFunctionCallUsage(@NotNull JetCallElement element, JetFunctionDefinitionUsage callee) { super(element); - this.functionDescriptor = functionDescriptor; - this.isInherited = isInherited; + this.callee = callee; } @Override @@ -76,7 +73,7 @@ public class JetFunctionCallUsage extends JetUsageInfo { String defaultValueText = parameterInfo.getDefaultValueText(); if (isNamedCall) { - String newName = parameterInfo.getInheritedName(isInherited, functionDescriptor, changeInfo.getFunctionDescriptor()); + String newName = parameterInfo.getInheritedName(callee); parametersBuilder.append(newName).append('='); } @@ -96,7 +93,7 @@ public class JetFunctionCallUsage extends JetUsageInfo { if (oldArgument != null) { JetValueArgumentName argumentName = oldArgument.getArgumentName(); JetSimpleNameExpression argumentNameExpression = argumentName != null ? argumentName.getReferenceExpression() : null; - changeArgumentName(changeInfo, argumentNameExpression, parameterInfo); + changeArgumentName(argumentNameExpression, parameterInfo); newArgument.replace(oldArgument); } else if (parameterInfo.getDefaultValueText().isEmpty()) @@ -138,17 +135,17 @@ public class JetFunctionCallUsage extends JetUsageInfo { if (oldParameterIndex != null) { JetParameterInfo parameterInfo = changeInfo.getNewParameters()[oldParameterIndex]; - changeArgumentName(changeInfo, argumentNameExpression, parameterInfo); + changeArgumentName(argumentNameExpression, parameterInfo); } } } } - private void changeArgumentName(JetChangeInfo changeInfo, JetSimpleNameExpression argumentNameExpression, JetParameterInfo parameterInfo) { + private void changeArgumentName(JetSimpleNameExpression argumentNameExpression, JetParameterInfo parameterInfo) { PsiElement identifier = argumentNameExpression != null ? argumentNameExpression.getIdentifier() : null; if (identifier != null) { - String newName = parameterInfo.getInheritedName(isInherited, functionDescriptor, changeInfo.getFunctionDescriptor()); + String newName = parameterInfo.getInheritedName(callee); identifier.replace(JetPsiFactory(getProject()).createIdentifier(newName)); } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java index 8b34b76fa16..206277415b7 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java @@ -18,41 +18,62 @@ package org.jetbrains.jet.plugin.refactoring.changeSignature.usages; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; import kotlin.Pair; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetModifierKeywordToken; import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; import org.jetbrains.jet.plugin.codeInsight.shorten.ShortenPackage; import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil; +import org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetValVar; import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; -public class JetFunctionDefinitionUsage extends JetUsageInfo { - private final boolean isInherited; - private final FunctionDescriptor functionDescriptor; +public class JetFunctionDefinitionUsage extends JetUsageInfo { + @NotNull + private final FunctionDescriptor originalFunctionDescriptor; + + private FunctionDescriptor currentFunctionDescriptor; + + @NotNull + private final JetFunctionDefinitionUsage baseFunction; + private final boolean hasExpectedType; + @Nullable + private final JetType samCallType; + + @Nullable + private TypeSubstitutor typeSubstitutor; + public JetFunctionDefinitionUsage( - @NotNull PsiElement function, - @NotNull FunctionDescriptor functionDescriptor, - boolean isInherited) { + @NotNull T function, + @NotNull FunctionDescriptor originalFunctionDescriptor, + @Nullable JetFunctionDefinitionUsage baseFunction, + @Nullable JetType samCallType) { super(function); - this.isInherited = isInherited; - this.functionDescriptor = functionDescriptor; - this.hasExpectedType = checkIfHasExpectedType(functionDescriptor); + this.originalFunctionDescriptor = originalFunctionDescriptor; + this.baseFunction = baseFunction != null ? baseFunction : this; + this.hasExpectedType = checkIfHasExpectedType(originalFunctionDescriptor, isInherited()); + this.samCallType = samCallType; } - private static boolean checkIfHasExpectedType(@NotNull FunctionDescriptor functionDescriptor) { - if (!(functionDescriptor instanceof AnonymousFunctionDescriptor)) return false; + private static boolean checkIfHasExpectedType(@NotNull FunctionDescriptor functionDescriptor, boolean isInherited) { + if (!(functionDescriptor instanceof AnonymousFunctionDescriptor && isInherited)) return false; JetFunctionLiteral functionLiteral = (JetFunctionLiteral) DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); @@ -65,12 +86,71 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo { return ResolvePackage.analyze(expression).get(BindingContext.EXPECTED_EXPRESSION_TYPE, expression) != null; } - public final boolean isInherited() { - return isInherited; + @NotNull + public JetFunctionDefinitionUsage getBaseFunction() { + return baseFunction; } - public final FunctionDescriptor getFunctionDescriptor() { - return functionDescriptor; + @NotNull + public PsiElement getDeclaration() { + //noinspection ConstantConditions + return getElement(); + } + + @Nullable + public TypeSubstitutor getOrCreateTypeSubstitutor() { + if (!isInherited()) return null; + + if (typeSubstitutor == null) { + if (samCallType == null) { + typeSubstitutor = ChangeSignaturePackage.getFunctionSubstitutor(baseFunction, this); + } + else { + DeclarationDescriptor currentBaseDescriptor = baseFunction.getCurrentFunctionDescriptor(); + DeclarationDescriptor classDescriptor = currentBaseDescriptor != null + ? currentBaseDescriptor.getContainingDeclaration() + : null; + + if (!(classDescriptor instanceof ClassDescriptor)) return null; + + typeSubstitutor = ChangeSignaturePackage.getTypeSubstitutor( + ((ClassDescriptor) classDescriptor).getDefaultType(), + samCallType + ); + } + } + return typeSubstitutor; + } + + public final boolean isInherited() { + return baseFunction != this; + } + + public boolean hasExpectedType() { + return hasExpectedType; + } + + @NotNull + public final FunctionDescriptor getOriginalFunctionDescriptor() { + return originalFunctionDescriptor; + } + + @Nullable + public final FunctionDescriptor getCurrentFunctionDescriptor() { + if (currentFunctionDescriptor == null) { + PsiElement element = getDeclaration(); + + if (element instanceof JetFunction) { + currentFunctionDescriptor = (FunctionDescriptor) ResolvePackage.resolveToDescriptor((JetFunction) element); + } + else if (element instanceof JetClass) { + currentFunctionDescriptor = ((ClassDescriptor) ResolvePackage.resolveToDescriptor((JetClass) element)).getUnsubstitutedPrimaryConstructor(); + } + else if (element instanceof PsiMethod) { + currentFunctionDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) element); + } + } + return currentFunctionDescriptor; } @Override @@ -90,12 +170,12 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo { } } - boolean returnTypeIsNeeded = changeInfo.isRefactoringTarget(functionDescriptor) + boolean returnTypeIsNeeded = changeInfo.isRefactoringTarget(originalFunctionDescriptor) || !(function instanceof JetFunctionLiteral) || function.getTypeReference() != null; if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) { function.setTypeReference(null); - String returnTypeText = changeInfo.getNewReturnTypeText(); + String returnTypeText = changeInfo.renderReturnType(this); //TODO use ChangeFunctionReturnTypeFix.invoke when JetTypeCodeFragment.getType() is ready if (!KotlinBuiltIns.getInstance().getUnitType().toString().equals(returnTypeText)) { @@ -123,11 +203,11 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo { } } else { - newParameterList = psiFactory.createFunctionLiteralParameterList(changeInfo.getNewParametersSignature(functionDescriptor, isInherited, hasExpectedType, 0)); + newParameterList = psiFactory.createFunctionLiteralParameterList(changeInfo.getNewParametersSignature(this, 0)); } } else { - newParameterList = psiFactory.createParameterList(changeInfo.getNewParametersSignature(functionDescriptor, isInherited, hasExpectedType, 0)); + newParameterList = psiFactory.createParameterList(changeInfo.getNewParametersSignature(this, 0)); } if (newParameterList != null) { @@ -166,8 +246,9 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo { int paramIndex = 0; for (JetParameter parameter : parameterList.getParameters()) { - JetParameterInfo parameterInfo = changeInfo.getNewParameters()[paramIndex++]; - changeParameter(changeInfo, parameter, parameterInfo); + JetParameterInfo parameterInfo = changeInfo.getNewParameters()[paramIndex]; + changeParameter(paramIndex, parameter, parameterInfo); + paramIndex++; } ShortenPackage.addToShorteningWaitSet(parameterList); @@ -191,7 +272,7 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo { } } - private void changeParameter(JetChangeInfo changeInfo, JetParameter parameter, JetParameterInfo parameterInfo) { + private void changeParameter(int parameterIndex, JetParameter parameter, JetParameterInfo parameterInfo) { ASTNode valOrVarAstNode = parameter.getValOrVarNode(); PsiElement valOrVarNode = valOrVarAstNode != null ? valOrVarAstNode.getPsi() : null; JetValVar valOrVar = parameterInfo.getValOrVar(); @@ -212,14 +293,14 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo { } if (parameterInfo.isTypeChanged() && parameter.getTypeReference() != null) { - JetTypeReference newTypeRef = psiFactory.createType(parameterInfo.getTypeText()); - parameter.setTypeReference(newTypeRef); + String renderedType = parameterInfo.renderType(parameterIndex, this); + parameter.setTypeReference(psiFactory.createType(renderedType)); } PsiElement identifier = parameter.getNameIdentifier(); if (identifier != null) { - String newName = parameterInfo.getInheritedName(isInherited, functionDescriptor, changeInfo.getFunctionDescriptor()); + String newName = parameterInfo.getInheritedName(this); identifier.replace(psiFactory.createIdentifier(newName)); } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetParameterUsage.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetParameterUsage.java index 8f2a7328e74..a595c49042b 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetParameterUsage.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/JetParameterUsage.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.plugin.refactoring.changeSignature.usages; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo; @@ -26,24 +25,21 @@ import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; public class JetParameterUsage extends JetUsageInfo { private final JetParameterInfo parameterInfo; - private final FunctionDescriptor functionDescriptor; - private final boolean isInherited; + private final JetFunctionDefinitionUsage containingFunction; public JetParameterUsage( @NotNull JetSimpleNameExpression element, - JetParameterInfo parameterInfo, - FunctionDescriptor functionDescriptor, - boolean inherited + @NotNull JetParameterInfo parameterInfo, + @NotNull JetFunctionDefinitionUsage containingFunction ) { super(element); this.parameterInfo = parameterInfo; - this.functionDescriptor = functionDescriptor; - isInherited = inherited; + this.containingFunction = containingFunction; } @Override public boolean processUsage(JetChangeInfo changeInfo, JetSimpleNameExpression element) { - String newName = parameterInfo.getInheritedName(isInherited, functionDescriptor, changeInfo.getFunctionDescriptor()); + String newName = parameterInfo.getInheritedName(containingFunction); element.replace(JetPsiFactory(element.getProject()).createSimpleName(newName)); return false; } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/KotlinSAMUsage.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/KotlinSAMUsage.kt index 2903af3107a..b8b28be2748 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/KotlinSAMUsage.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/usages/KotlinSAMUsage.kt @@ -19,8 +19,10 @@ package org.jetbrains.jet.plugin.refactoring.changeSignature.usages import com.intellij.usageView.UsageInfo import org.jetbrains.jet.lang.psi.JetFunctionLiteral import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.types.JetType public class KotlinSAMUsage( val functionLiteral: JetFunctionLiteral, - val functionDescriptor: FunctionDescriptor + val functionDescriptor: FunctionDescriptor, + val samCallType: JetType ): UsageInfo(functionLiteral) diff --git a/idea/testData/refactoring/changeSignature/GenericsWithOverridesAfter.1.java b/idea/testData/refactoring/changeSignature/GenericsWithOverridesAfter.1.java new file mode 100644 index 00000000000..b6c652a9032 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithOverridesAfter.1.java @@ -0,0 +1,34 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +interface J extends T { + @Nullable + @Override + U foofoofoo(@NotNull List a, @Nullable A b, @NotNull U c); +} + +abstract class J1 implements J, U> { + @Nullable + @Override + public U foofoofoo(@NotNull List xu, @Nullable U yu, @NotNull U> c) { + throw new UnsupportedOperationException(); + } +} + +abstract class J2 extends J1 { + @Nullable + @Override + public U foofoofoo(@NotNull List xu, @Nullable U stringU, @NotNull U> c) { + throw new UnsupportedOperationException(); + } +} + +class J3 extends J2 { + @Nullable + @Override + public U foofoofoo(@NotNull List objectU, @Nullable U stringU, @NotNull U> c) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithOverridesAfter.kt b/idea/testData/refactoring/changeSignature/GenericsWithOverridesAfter.kt new file mode 100644 index 00000000000..a171fdcae4e --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithOverridesAfter.kt @@ -0,0 +1,23 @@ +class U + +trait T { + fun foofoofoo(a: List, b: A?, c: U): U? +} + +abstract class T1 : T, U> { + override fun foofoofoo(a: List, b: U?, c: U>): U? { + throw UnsupportedOperationException() + } +} + +abstract class T2 : T1() { + override fun foofoofoo(a: List, b: U?, c: U>): U? { + throw UnsupportedOperationException() + } +} + +class T3 : T2() { + override fun foofoofoo(a: List, b: U?, c: U>): U? { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithOverridesBefore.1.java b/idea/testData/refactoring/changeSignature/GenericsWithOverridesBefore.1.java new file mode 100644 index 00000000000..62e85892c6f --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithOverridesBefore.1.java @@ -0,0 +1,25 @@ +interface J extends T { + @Override + int foofoofoo(A a, B b, C c); +} + +abstract class J1 implements J, U> { + @Override + public int foofoofoo(U xu, U yu, C c) { + throw new UnsupportedOperationException(); + } +} + +abstract class J2 extends J1 { + @Override + public int foofoofoo(U xu, U stringU, C c) { + throw new UnsupportedOperationException(); + } +} + +class J3 extends J2 { + @Override + public int foofoofoo(U objectU, U stringU, D c) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithOverridesBefore.kt b/idea/testData/refactoring/changeSignature/GenericsWithOverridesBefore.kt new file mode 100644 index 00000000000..34c445933d6 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithOverridesBefore.kt @@ -0,0 +1,23 @@ +class U + +trait T { + fun foofoofoo(a: A, b: B, c: C): Int +} + +abstract class T1 : T, U> { + override fun foofoofoo(a: U, b: U, c: C): Int { + throw UnsupportedOperationException() + } +} + +abstract class T2 : T1() { + override fun foofoofoo(a: U, b: U, c: C): Int { + throw UnsupportedOperationException() + } +} + +class T3 : T2() { + override fun foofoofoo(a: U, b: U, c: D): Int { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsAfter.1.kt b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsAfter.1.kt new file mode 100644 index 00000000000..55af593fa40 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsAfter.1.kt @@ -0,0 +1,5 @@ +fun test() { + SamTest.test(Foo { (s, n) -> "" }) + SamTest.test(Foo { (s: MutableList>, n: X>) -> "" }) + SamTest.test(Foo { (s: MutableList>, n: X>): X>? -> "" }) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsAfter.java b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsAfter.java new file mode 100644 index 00000000000..358f91a6a95 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsAfter.java @@ -0,0 +1,16 @@ +import java.util.List; +import java.util.Set; + +class X { + +} + +interface Foo { + X> foo(List> a, X> b); +} + +class SamTest { + static void test(Foo foo) { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsBefore.1.kt b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsBefore.1.kt new file mode 100644 index 00000000000..49329c7ae6c --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsBefore.1.kt @@ -0,0 +1,5 @@ +fun test() { + SamTest.test(Foo { (s, n) -> "" }) + SamTest.test(Foo { (s: String, n: Int) -> "" }) + SamTest.test(Foo { (s: String, n: Int): String -> "" }) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsBefore.java b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsBefore.java new file mode 100644 index 00000000000..b92325eefe0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/GenericsWithSAMConstructorsBefore.java @@ -0,0 +1,13 @@ +class X { + +} + +interface Foo { + A foo(A a, B b); +} + +class SamTest { + static void test(Foo foo) { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/SAMChangeParamTypeAfter.1.kt b/idea/testData/refactoring/changeSignature/SAMChangeParamTypeAfter.1.kt index 4dd3f7e6524..d3c2641ff15 100644 --- a/idea/testData/refactoring/changeSignature/SAMChangeParamTypeAfter.1.kt +++ b/idea/testData/refactoring/changeSignature/SAMChangeParamTypeAfter.1.kt @@ -1,4 +1,4 @@ fun test() { JTest.samTest(SAM { (s, n) -> s + " " }) - JTest.samTest(SAM { (s: Any?, n: Int) -> x + " " }) + JTest.samTest(SAM { (s: Any, n: Int) -> x + " " }) } \ 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 cdf97ea9803..50039c74e26 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java @@ -358,6 +358,19 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { doTest(changeInfo); } + public void testGenericsWithOverrides() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + + JetParameterInfo[] newParameters = changeInfo.getNewParameters(); + newParameters[0].setTypeText("List"); + newParameters[1].setTypeText("A?"); + newParameters[2].setTypeText("U"); + + changeInfo.setNewReturnTypeText("U?"); + + doTest(changeInfo); + } + public void testJavaMethodKotlinUsages() throws Exception { doJavaTest( new JavaRefactoringProvider() { @@ -511,6 +524,29 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { ); } + public void testGenericsWithSAMConstructors() throws Exception { + doJavaTest( + new JavaRefactoringProvider() { + final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); + + @NotNull + @Override + ParameterInfoImpl[] getNewParameters(@NotNull PsiMethod method) { + ParameterInfoImpl[] newParameters = super.getNewParameters(method); + newParameters[0].setType(factory.createTypeFromText("java.util.List>", method.getParameterList())); + newParameters[1].setType(factory.createTypeFromText("X>", method.getParameterList())); + return newParameters; + } + + @Nullable + @Override + PsiType getNewReturnType(@NotNull PsiMethod method) { + return factory.createTypeFromText("X>", method); + } + } + ); + } + public void testFunctionRenameJavaUsages() throws Exception { JetChangeInfo changeInfo = getChangeInfo(); changeInfo.setNewName("bar");