J2K: AddFunctionParametersFix.java

This commit is contained in:
Alexey Sedunov
2015-09-11 00:06:30 +03:00
parent 3c48882c4f
commit 670bb1a27d
2 changed files with 94 additions and 153 deletions
@@ -60,10 +60,7 @@ change.function.parameter.type=Change parameter ''{0}'' type of function ''{1}''
change.primary.constructor.parameter.type=Change parameter ''{0}'' type of primary constructor of class ''{1}'' to ''{2}''
change.type=Change type from ''{0}'' to ''{1}''
change.type.family=Change Type
add.parameters.to.function=Add parameter{0} to function ''{1}''
add.parameters.to.constructor=Add parameter{0} to constructor ''{1}''
change.function.signature=Change the signature of function ''{0}''
change.constructor.signature=Change the signature of constructor ''{0}''
change.function.literal.signature=Change the signature of function literal
remove.parameter=Remove parameter ''{0}''
change.signature.family=Change signature of function/constructor
@@ -14,183 +14,127 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix;
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.core.CollectingNameValidator;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.psi.JetCallElement;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.ValueArgument;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureConfiguration
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.JetCallElement
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import java.util.*
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class AddFunctionParametersFix(
private val callElement: JetCallElement,
functionDescriptor: FunctionDescriptor,
private val hasTypeMismatches: Boolean) : ChangeFunctionSignatureFix(callElement, functionDescriptor) {
private val typesToShorten = ArrayList<JetType>()
import static org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature;
override fun getText(): String {
val parameters = functionDescriptor.valueParameters
val arguments = callElement.valueArguments
val newParametersCnt = arguments.size() - parameters.size()
assert(newParametersCnt > 0)
public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
private final JetCallElement callElement;
private final boolean hasTypeMismatches;
private final List<JetType> typesToShorten = new ArrayList<JetType>();
val subjectSuffix = if (newParametersCnt > 1) "s" else ""
public AddFunctionParametersFix(
@NotNull JetCallElement callElement,
@NotNull FunctionDescriptor functionDescriptor,
boolean hasTypeMismatches
) {
super(callElement, functionDescriptor);
this.callElement = callElement;
this.hasTypeMismatches = hasTypeMismatches;
}
@NotNull
@Override
public String getText() {
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
List<? extends ValueArgument> arguments = callElement.getValueArguments();
int newParametersCnt = arguments.size() - parameters.size();
assert newParametersCnt > 0;
String subjectSuffix = newParametersCnt > 1 ? "s" : "";
if (isConstructor()) {
String className = functionDescriptor.getContainingDeclaration().getName().asString();
if (hasTypeMismatches)
return JetBundle.message("change.constructor.signature", className);
else
return JetBundle.message("add.parameters.to.constructor", subjectSuffix, className);
val callableDescription = if (isConstructor()) {
val className = functionDescriptor.containingDeclaration.name.asString()
"constructor '$className'"
}
else {
String functionName = functionDescriptor.getName().asString();
if (hasTypeMismatches)
return JetBundle.message("change.function.signature", functionName);
else
return JetBundle.message("add.parameters.to.function", subjectSuffix, functionName);
}
}
@Override
public boolean isAvailable(
@NotNull Project project, Editor editor, PsiFile file
) {
if (!super.isAvailable(project, editor, file)) {
return false;
val functionName = functionDescriptor.name.asString()
"function '$functionName'"
}
int newParametersCnt = callElement.getValueArguments().size() - functionDescriptor.getValueParameters().size();
if (newParametersCnt <= 0) {
// psi for this quickfix is no longer valid
return false;
}
return true;
return if (hasTypeMismatches)
"Change the signature of $callableDescription"
else
"Add parameter$subjectSuffix to $callableDescription"
}
@Override
public boolean startInWriteAction() {
return true;
override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
if (!super.isAvailable(project, editor, file)) return false
// newParametersCnt <= 0: psi for this quickfix is no longer valid
val newParametersCnt = callElement.valueArguments.size() - functionDescriptor.valueParameters.size()
return newParametersCnt > 0
}
@Override
protected void invoke(@NotNull Project project, Editor editor, JetFile file) {
BindingContext bindingContext = ResolutionUtils.analyzeFully((JetFile) callElement.getContainingFile());
runChangeSignature(project, functionDescriptor, addParameterConfiguration(), bindingContext, callElement, getText());
override fun startInWriteAction() = true
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
runChangeSignature(project, functionDescriptor, addParameterConfiguration(), callElement.analyzeFully(), callElement, text)
}
private JetChangeSignatureConfiguration addParameterConfiguration() {
return new JetChangeSignatureConfiguration() {
@NotNull
@Override
public JetMethodDescriptor configure(@NotNull final JetMethodDescriptor originalDescriptor, @NotNull final BindingContext bindingContext) {
return ChangeSignaturePackage.modify(
originalDescriptor,
new Function1<JetMutableMethodDescriptor, Unit>() {
@Override
public Unit invoke(JetMutableMethodDescriptor descriptor) {
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
List<? extends ValueArgument> arguments = callElement.getValueArguments();
CollectingNameValidator validator = new CollectingNameValidator();
private fun addParameterConfiguration(): JetChangeSignatureConfiguration {
return object : JetChangeSignatureConfiguration {
override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
return originalDescriptor.modify {
val parameters = functionDescriptor.valueParameters
val arguments = callElement.valueArguments
val validator = CollectingNameValidator()
for (int i = 0; i < arguments.size(); i ++) {
ValueArgument argument = arguments.get(i);
JetExpression expression = argument.getArgumentExpression();
for (i in arguments.indices) {
val argument = arguments.get(i)
val expression = argument.getArgumentExpression()
if (i < parameters.size()) {
validator.addName(parameters.get(i).getName().asString());
JetType argumentType = expression != null ? bindingContext.getType(expression) : null;
JetType parameterType = parameters.get(i).getType();
if (i < parameters.size()) {
validator.addName(parameters.get(i).name.asString())
val argumentType = expression?.let { bindingContext.getType(it) }
val parameterType = parameters.get(i).type
if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) {
descriptor.getParameters().get(i).setCurrentTypeText(IdeDescriptorRenderers.SOURCE_CODE.renderType(argumentType));
typesToShorten.add(argumentType);
}
}
else {
JetParameterInfo parameterInfo =
getNewParameterInfo((FunctionDescriptor) originalDescriptor.getBaseDescriptor(), bindingContext, argument, validator);
typesToShorten.add(parameterInfo.getOriginalType());
if (expression != null) {
parameterInfo.setDefaultValueForCall(expression);
}
descriptor.addParameter(parameterInfo);
}
}
return null;
if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) {
it.parameters.get(i).currentTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(argumentType)
typesToShorten.add(argumentType)
}
}
);
}
else {
val parameterInfo = ChangeFunctionSignatureFix.getNewParameterInfo(
originalDescriptor.baseDescriptor as FunctionDescriptor,
bindingContext,
argument,
validator
)
parameterInfo.originalType?.let { typesToShorten.add(it) }
@Override
public boolean performSilently(@NotNull Collection<? extends PsiElement> affectedFunctions) {
if (affectedFunctions.size() != 1) {
return false;
if (expression != null) {
parameterInfo.defaultValueForCall = expression
}
it.addParameter(parameterInfo)
}
}
}
PsiElement onlyFunction = affectedFunctions.iterator().next();
return !hasTypeMismatches && !isConstructor() && !hasOtherUsages(onlyFunction);
}
@Override
public boolean forcePerformForSelectedFunctionOnly() {
return false;
}
};
}
private boolean hasOtherUsages(@NotNull PsiElement function) {
for (PsiReference reference : ReferencesSearch.search(function)) {
JetCallElement call = PsiTreeUtil.getParentOfType(reference.getElement(), JetCallElement.class);
if (call != null && !callElement.equals(call)) {
return true;
override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean {
val onlyFunction = affectedFunctions.singleOrNull() ?: return false
return !hasTypeMismatches && !isConstructor() && !hasOtherUsages(onlyFunction)
}
}
return false;
}
private boolean isConstructor() {
return functionDescriptor instanceof ConstructorDescriptor;
private fun hasOtherUsages(function: PsiElement): Boolean {
return ReferencesSearch.search(function).any {
val call = it.element.getParentOfType<JetCallElement>(false)
call != null && callElement != call
}
}
private fun isConstructor() = functionDescriptor is ConstructorDescriptor
}