Change Signature: Add support of type parameter substitutions in overriding members

This commit is contained in:
Alexey Sedunov
2014-12-02 14:02:15 +03:00
parent 250940c824
commit c917459926
29 changed files with 638 additions and 131 deletions
@@ -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() {
@@ -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<PsiParameterList> by Delegates.blockingLazy {
val cacheManager = CachedValuesManager.getManager(delegate.getProject())
cacheManager.createCachedValue<PsiParameterList>({
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<PsiTypeParameterList> by Delegates.blockingLazy {
val cacheManager = CachedValuesManager.getManager(delegate.getProject())
cacheManager.createCachedValue<PsiTypeParameterList>({
val declaration = if (origin is JetPropertyAccessor) origin.getNonStrictParentOfType<JetProperty>() 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<PsiTypeParameter> =
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() &&
@@ -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());
}
}
@@ -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) }
}
}
@@ -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<JetTypeParameter> parameters = typeParameterListOwner.getTypeParameters();
@@ -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<PsiParameter> myParameters = new ArrayList<PsiParameter>();
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";
@@ -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) {
@@ -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<JetParameterInfo> parameters;
@NotNull
private final Collection<FunctionDescriptor> descriptorsForSignatureChange;
private JetFunctionDefinitionUsage<PsiElement> originalPrimaryFunction;
private Collection<JetFunctionDefinitionUsage<PsiElement>> primaryFunctions = null;
private Collection<UsageInfo> affectedFunctions = null;
public JetChangeSignatureData(
@@ -99,26 +102,61 @@ public final class JetChangeSignatureData implements JetMethodDescriptor {
parameters.clear();
}
@NotNull
@Override
public JetFunctionDefinitionUsage<PsiElement> getOriginalPrimaryFunction() {
if (originalPrimaryFunction == null) {
originalPrimaryFunction = KotlinPackage.first(
getPrimaryFunctions(),
new Function1<JetFunctionDefinitionUsage<PsiElement>, Boolean>() {
@Override
public Boolean invoke(JetFunctionDefinitionUsage<PsiElement> usage) {
return usage.getDeclaration() == baseDeclaration;
}
}
);
}
return originalPrimaryFunction;
}
@Override
@NotNull
public Collection<JetFunctionDefinitionUsage<PsiElement>> getPrimaryFunctions() {
if (primaryFunctions == null) {
primaryFunctions = KotlinPackage.map(
descriptorsForSignatureChange,
new Function1<FunctionDescriptor, JetFunctionDefinitionUsage<PsiElement>>() {
@Override
public JetFunctionDefinitionUsage<PsiElement> invoke(FunctionDescriptor descriptor) {
PsiElement declaration = DescriptorToDeclarationUtil.INSTANCE$.getDeclaration(baseDeclaration.getProject(),
descriptor);
assert declaration != null : "No declaration found for " + descriptor;
return new JetFunctionDefinitionUsage<PsiElement>(declaration, descriptor, null, null);
}
}
);
}
return primaryFunctions;
}
@Override
@NotNull
public Collection<UsageInfo> getAffectedFunctions() {
if (affectedFunctions == null) {
affectedFunctions = KotlinPackage.flatMapTo(
descriptorsForSignatureChange,
getPrimaryFunctions(),
new HashSet<UsageInfo>(),
new Function1<FunctionDescriptor, Iterable<? extends UsageInfo>>() {
new Function1<JetFunctionDefinitionUsage<PsiElement>, Iterable<? extends UsageInfo>>() {
@Override
public Iterable<? extends UsageInfo> invoke(final FunctionDescriptor descriptor) {
PsiElement declaration = DescriptorToDeclarationUtil.INSTANCE$.getDeclaration(baseDeclaration.getProject(),
descriptor);
assert declaration != null : "No declaration found for " + descriptor;
public Iterable<? extends UsageInfo> invoke(final JetFunctionDefinitionUsage<PsiElement> primaryFunction) {
Set<UsageInfo> 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<PsiElement>(declaration,
currentDescriptor,
primaryFunction,
null);
}
return new OverriderUsageInfo(method, baseLightMethod, true, true, true);
@@ -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
@@ -84,12 +84,15 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
JetChangeInfo changeInfo,
Set<UsageInfo> 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<JetFunction>(samUsage.getFunctionLiteral(), javaMethodChangeInfo) {
private final JetFunctionDefinitionUsage<JetFunction> delegateUsage = new JetFunctionDefinitionUsage<JetFunction>(
samUsage.getFunctionLiteral(),
samUsage.getFunctionDescriptor(),
javaMethodChangeInfo.getFunctionDescriptor().getOriginalPrimaryFunction(),
samUsage.getSamCallType()
);
@NotNull
@Override
protected JetUsageInfo<JetFunction> 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;
}
@@ -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<JetParameterInfo, Visibility> {
@NotNull
JetFunctionDefinitionUsage<PsiElement> getOriginalPrimaryFunction();
@NotNull
Collection<JetFunctionDefinitionUsage<PsiElement>> getPrimaryFunctions();
@NotNull
Collection<UsageInfo> getAffectedFunctions();
@@ -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<ValueParameterDescriptor> 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());
}
@@ -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<TypeConstructor, TypeProjection>? {
val substitutedType = TypeCheckingProcedure.findCorrespondingSupertype(derivedType, baseType) ?: return null
val substitution = LinkedHashMap<TypeConstructor, TypeProjection>(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<TypeConstructor, TypeProjection>? {
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)
}
@@ -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<T: JetElement>(
val jetElement: T,
public abstract class JavaMethodKotlinUsageWithDelegate<T: PsiElement>(
val psiElement: T,
val javaMethodChangeInfo: JetChangeInfo): UsageInfo(javaMethodChangeInfo.getMethod()) {
protected abstract val delegateUsage: JetUsageInfo<T>
fun processUsage(): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, jetElement)
fun processUsage(): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, psiElement)
}
public class JavaMethodKotlinCallUsage(
callElement: JetCallElement,
javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetCallElement>(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<JetFunction>(function, javaMethodChangeInfo) {
[suppress("CAST_NEVER_SUCCEEDS")]
override protected val delegateUsage = JetFunctionDefinitionUsage(jetElement, functionDescriptor, true) as JetUsageInfo<JetFunction>
}
override protected val delegateUsage = JetFunctionDefinitionUsage(
psiElement,
functionDescriptor,
javaMethodChangeInfo.getFunctionDescriptor().getOriginalPrimaryFunction(),
null
)
}
@@ -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)
}
@@ -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<JetCallElement> {
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<JetCallElement> {
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<JetCallElement> {
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<JetCallElement> {
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));
}
}
@@ -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<PsiElement> {
private final boolean isInherited;
private final FunctionDescriptor functionDescriptor;
public class JetFunctionDefinitionUsage<T extends PsiElement> extends JetUsageInfo<T> {
@NotNull
private final FunctionDescriptor originalFunctionDescriptor;
private FunctionDescriptor currentFunctionDescriptor;
@NotNull
private final JetFunctionDefinitionUsage<? extends PsiElement> 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<PsiElement> 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<PsiElement> {
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<PsiElement> {
}
}
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<PsiElement> {
}
}
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<PsiElement> {
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<PsiElement> {
}
}
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<PsiElement> {
}
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));
}
}
@@ -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<JetSimpleNameExpression> {
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;
}
@@ -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)
@@ -0,0 +1,34 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
interface J<A, B> extends T<A, B> {
@Nullable
@Override
<C> U<C> foofoofoo(@NotNull List<? extends C> a, @Nullable A b, @NotNull U<B> c);
}
abstract class J1<X, Y> implements J<U<X>, U<Y>> {
@Nullable
@Override
public <C> U<C> foofoofoo(@NotNull List<? extends C> xu, @Nullable U<X> yu, @NotNull U<U<Y>> c) {
throw new UnsupportedOperationException();
}
}
abstract class J2<X> extends J1<X, String> {
@Nullable
@Override
public <C> U<C> foofoofoo(@NotNull List<? extends C> xu, @Nullable U<X> stringU, @NotNull U<U<String>> c) {
throw new UnsupportedOperationException();
}
}
class J3 extends J2<Object> {
@Nullable
@Override
public <D> U<D> foofoofoo(@NotNull List<? extends D> objectU, @Nullable U<Object> stringU, @NotNull U<U<String>> c) {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,23 @@
class U<A>
trait T<A, B> {
fun foofoofoo<C>(a: List<C>, b: A?, c: U<B>): U<C>?
}
abstract class T1<X, Y> : T<U<X>, U<Y>> {
override fun <C> foofoofoo(a: List<C>, b: U<X>?, c: U<U<Y>>): U<C>? {
throw UnsupportedOperationException()
}
}
abstract class T2<X> : T1<X, String>() {
override fun <C> foofoofoo(a: List<C>, b: U<X>?, c: U<U<String>>): U<C>? {
throw UnsupportedOperationException()
}
}
class T3 : T2<Any>() {
override fun foofoofoo<D>(a: List<D>, b: U<Any>?, c: U<U<String>>): U<D>? {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,25 @@
interface J<A, B> extends T<A, B> {
@Override
<C> int foofoofoo(A a, B b, C c);
}
abstract class J1<X, Y> implements J<U<X>, U<Y>> {
@Override
public <C> int foofoofoo(U<X> xu, U<Y> yu, C c) {
throw new UnsupportedOperationException();
}
}
abstract class J2<X> extends J1<X, String> {
@Override
public <C> int foofoofoo(U<X> xu, U<String> stringU, C c) {
throw new UnsupportedOperationException();
}
}
class J3 extends J2<Object> {
@Override
public <D> int foofoofoo(U<Object> objectU, U<String> stringU, D c) {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,23 @@
class U<A>
trait T<A, B> {
fun <caret>foofoofoo<C>(a: A, b: B, c: C): Int
}
abstract class T1<X, Y> : T<U<X>, U<Y>> {
override fun <C> foofoofoo(a: U<X>, b: U<Y>, c: C): Int {
throw UnsupportedOperationException()
}
}
abstract class T2<X> : T1<X, String>() {
override fun <C> foofoofoo(a: U<X>, b: U<String>, c: C): Int {
throw UnsupportedOperationException()
}
}
class T3 : T2<Any>() {
override fun foofoofoo<D>(a: U<Any>, b: U<String>, c: D): Int {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,5 @@
fun test() {
SamTest.test(Foo<String, Int> { (s, n) -> "" })
SamTest.test(Foo { (s: MutableList<X<Int>>, n: X<MutableSet<String>>) -> "" })
SamTest.test(Foo { (s: MutableList<X<Int>>, n: X<MutableSet<String>>): X<MutableList<String>>? -> "" })
}
@@ -0,0 +1,16 @@
import java.util.List;
import java.util.Set;
class X<A> {
}
interface Foo<A, B> {
X<List<A>> foo(List<X<B>> a, X<Set<A>> b);
}
class SamTest {
static <A, B> void test(Foo<A, B> foo) {
}
}
@@ -0,0 +1,5 @@
fun test() {
SamTest.test(Foo<String, Int> { (s, n) -> "" })
SamTest.test(Foo { (s: String, n: Int) -> "" })
SamTest.test(Foo { (s: String, n: Int): String -> "" })
}
@@ -0,0 +1,13 @@
class X<A> {
}
interface Foo<A, B> {
A <caret>foo(A a, B b);
}
class SamTest {
static <A, B> void test(Foo<A, B> foo) {
}
}
@@ -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 + " " })
}
@@ -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<C>");
newParameters[1].setTypeText("A?");
newParameters[2].setTypeText("U<B>");
changeInfo.setNewReturnTypeText("U<C>?");
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<X<B>>", method.getParameterList()));
newParameters[1].setType(factory.createTypeFromText("X<java.util.Set<A>>", method.getParameterList()));
return newParameters;
}
@Nullable
@Override
PsiType getNewReturnType(@NotNull PsiMethod method) {
return factory.createTypeFromText("X<java.util.List<A>>", method);
}
}
);
}
public void testFunctionRenameJavaUsages() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("bar");