Quickfix for NOTHING_TO_OVERRIDE
This commit is contained in:
committed by
Andrey Breslav
parent
3760922e84
commit
5b1f93b42e
+46
-1
@@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||
@@ -49,6 +48,9 @@ public class FunctionDescriptorUtil {
|
||||
}
|
||||
});
|
||||
|
||||
private FunctionDescriptorUtil() {
|
||||
}
|
||||
|
||||
public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
|
||||
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
|
||||
|
||||
@@ -137,4 +139,47 @@ public class FunctionDescriptorUtil {
|
||||
public static <D extends CallableDescriptor> D alphaConvertTypeParameters(D candidate) {
|
||||
return (D) candidate.substitute(MAKE_TYPE_PARAMETERS_FRESH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns function's copy with new parameter list. Note that parameters may belong to other methods or have incorrect "index" property
|
||||
* -- it will be fixed by this function.
|
||||
*/
|
||||
@NotNull
|
||||
public static FunctionDescriptor replaceFunctionParameters(
|
||||
@NotNull FunctionDescriptor function,
|
||||
@NotNull List<ValueParameterDescriptor> newParameters
|
||||
) {
|
||||
FunctionDescriptorImpl descriptor = new SimpleFunctionDescriptorImpl(
|
||||
function.getContainingDeclaration(),
|
||||
function.getAnnotations(),
|
||||
function.getName(),
|
||||
function.getKind());
|
||||
List<ValueParameterDescriptor> parameters = new ArrayList<ValueParameterDescriptor>(newParameters.size());
|
||||
int idx = 0;
|
||||
for (ValueParameterDescriptor parameter : newParameters) {
|
||||
JetType returnType = parameter.getReturnType();
|
||||
assert returnType != null;
|
||||
|
||||
parameters.add(new ValueParameterDescriptorImpl(
|
||||
descriptor,
|
||||
idx,
|
||||
parameter.getAnnotations(),
|
||||
parameter.getName(),
|
||||
returnType,
|
||||
parameter.declaresDefaultValue(),
|
||||
parameter.getVarargElementType())
|
||||
);
|
||||
idx++;
|
||||
}
|
||||
ReceiverParameterDescriptor receiver = function.getReceiverParameter();
|
||||
descriptor.initialize(
|
||||
receiver == null ? null : receiver.getType(),
|
||||
function.getExpectedThisObject(),
|
||||
function.getTypeParameters(),
|
||||
parameters,
|
||||
function.getReturnType(),
|
||||
function.getModality(),
|
||||
function.getVisibility());
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,24 +240,12 @@ public class OverrideResolver {
|
||||
) {
|
||||
Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden);
|
||||
while (!fromSuperQueue.isEmpty()) {
|
||||
CallableMemberDescriptor notOverriddenFromSuper = findMemberWithMaxVisibility(fromSuperQueue);
|
||||
CallableMemberDescriptor notOverriddenFromSuper = VisibilityUtil.findMemberWithMaxVisibility(fromSuperQueue);
|
||||
Collection<CallableMemberDescriptor> overridables = extractMembersOverridableBy(notOverriddenFromSuper, fromSuperQueue, sink);
|
||||
createAndBindFakeOverride(notOverriddenFromSuper, overridables, current, sink);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static CallableMemberDescriptor findMemberWithMaxVisibility(@NotNull Queue<CallableMemberDescriptor> descriptors) {
|
||||
CallableMemberDescriptor descriptor = descriptors.element();
|
||||
for (CallableMemberDescriptor candidate : descriptors) {
|
||||
Integer result = Visibilities.compare(descriptor.getVisibility(), candidate.getVisibility());
|
||||
if (result != null && result < 0) {
|
||||
descriptor = candidate;
|
||||
}
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private static void createAndBindFakeOverride(
|
||||
@NotNull CallableMemberDescriptor notOverriddenFromSuper,
|
||||
@NotNull Collection<CallableMemberDescriptor> overridables,
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.lang.resolve;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.Visibilities;
|
||||
|
||||
import java.util.Queue;
|
||||
|
||||
public class VisibilityUtil {
|
||||
@NotNull
|
||||
public static CallableMemberDescriptor findMemberWithMaxVisibility(@NotNull Queue<CallableMemberDescriptor> descriptors) {
|
||||
CallableMemberDescriptor descriptor = descriptors.element();
|
||||
for (CallableMemberDescriptor candidate : descriptors) {
|
||||
Integer result = Visibilities.compare(descriptor.getVisibility(), candidate.getVisibility());
|
||||
if (result != null && result < 0) {
|
||||
descriptor = candidate;
|
||||
}
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
@@ -139,9 +139,13 @@ surround.with.function.template={ }
|
||||
surround.with.cannot.perform.action=Cannot perform Surround With action to the current contextsurround.with.function.template={ }
|
||||
remove.variable.family.name=Remove variable
|
||||
remove.variable.action=Remove variable ''{0}''
|
||||
|
||||
kotlin.code.transformations=Kotlin Code Transformations
|
||||
transform.if.statement.with.assignments.to.expression=Transform 'if' statement with assignments to expression
|
||||
transform.assignment.with.if.expression.to.statement=Transform assignment with 'if' expression to statement
|
||||
transform.if.statement.with.assignments.to.expression.family=Transform 'if' Statement with Assignments to Expression
|
||||
transform.assignment.with.if.expression.to.statement.family=Transform Assignment with 'if' Expression to Statement
|
||||
change.function.signature.action.single=Change function signature to ''{0}''
|
||||
change.function.signature.action.multiple=Change function signature...
|
||||
change.function.signature.family=Change function signature
|
||||
change.function.signature.chooser.title=Choose signature
|
||||
change.function.signature.action=Change function signature
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.actions;
|
||||
|
||||
import com.intellij.codeInsight.hint.QuestionAction;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.PopupStep;
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
||||
import org.jetbrains.jet.plugin.JetBundle;
|
||||
import org.jetbrains.jet.plugin.codeInsight.OverrideUtil;
|
||||
import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Changes method signature to one of provided signatures.
|
||||
* Based on {@link JetAddImportAction}
|
||||
*/
|
||||
public class JetChangeFunctionSignatureAction implements QuestionAction {
|
||||
|
||||
private final Project project;
|
||||
private final Editor editor;
|
||||
private final JetNamedFunction element;
|
||||
private final List<FunctionDescriptor> signatures;
|
||||
|
||||
/**
|
||||
* @param project Project where action takes place.
|
||||
* @param editor Editor where modification should be done.
|
||||
* @param element Function element which signature should be changed.
|
||||
* @param signatures Variants for new function signature.
|
||||
*/
|
||||
public JetChangeFunctionSignatureAction(
|
||||
@NotNull Project project,
|
||||
@NotNull Editor editor,
|
||||
@NotNull JetNamedFunction element,
|
||||
@NotNull Collection<FunctionDescriptor> signatures
|
||||
) {
|
||||
this.project = project;
|
||||
this.editor = editor;
|
||||
this.element = element;
|
||||
this.signatures = new ArrayList<FunctionDescriptor>(signatures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
if (!element.isValid() || signatures.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (signatures.size() == 1 || !editor.getComponent().isShowing()) {
|
||||
changeSignature(element, project, signatures.get(0));
|
||||
}
|
||||
else {
|
||||
chooseSignatureAndChange();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private BaseListPopupStep getSignaturePopup() {
|
||||
return new BaseListPopupStep<FunctionDescriptor>(
|
||||
JetBundle.message("change.function.signature.chooser.title"), signatures) {
|
||||
@Override
|
||||
public boolean isAutoSelectionEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PopupStep onChosen(FunctionDescriptor selectedValue, boolean finalChoice) {
|
||||
if (finalChoice) {
|
||||
changeSignature(element, project, selectedValue);
|
||||
}
|
||||
return FINAL_CHOICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIconFor(FunctionDescriptor aValue) {
|
||||
return PlatformIcons.FUNCTION_ICON;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getTextFor(FunctionDescriptor aValue) {
|
||||
return OverrideUtil.createOverridenFunctionSignatureStringFromDescriptor(
|
||||
project,
|
||||
aValue,
|
||||
/* shortTypeNames = */ true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void changeSignature(final JetNamedFunction element, final Project project, FunctionDescriptor signature) {
|
||||
final String signatureString = OverrideUtil.createOverridenFunctionSignatureStringFromDescriptor(
|
||||
project,
|
||||
signature,
|
||||
/* shortTypeNames = */ false);
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
JetExpression bodyExpression = element.getBodyExpression();
|
||||
JetNamedFunction newElement;
|
||||
|
||||
if (bodyExpression != null) {
|
||||
if (element.hasBlockBody()) {
|
||||
newElement = JetPsiFactory.createFunction(project, signatureString + "{}");
|
||||
}
|
||||
else {
|
||||
newElement = JetPsiFactory.createFunction(project, signatureString + "= \"dummy\"");
|
||||
}
|
||||
JetExpression newBodyExpression = newElement.getBodyExpression();
|
||||
assert newBodyExpression != null;
|
||||
newBodyExpression.replace(bodyExpression);
|
||||
}
|
||||
else {
|
||||
newElement = JetPsiFactory.createFunction(project, signatureString);
|
||||
}
|
||||
newElement = (JetNamedFunction) element.replace(newElement);
|
||||
ReferenceToClassesShortening.compactReferenceToClasses(Collections.singletonList(newElement));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, JetBundle.message("change.function.signature.action"), null);
|
||||
}
|
||||
|
||||
private void chooseSignatureAndChange() {
|
||||
JBPopupFactory.getInstance().createListPopup(getSignaturePopup()).showInBestPositionFor(editor);
|
||||
}
|
||||
}
|
||||
+9
-132
@@ -24,21 +24,20 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -119,140 +118,18 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns
|
||||
for (DescriptorClassMember selectedElement : selectedElements) {
|
||||
DeclarationDescriptor descriptor = selectedElement.getDescriptor();
|
||||
if (descriptor instanceof SimpleFunctionDescriptor) {
|
||||
overridingMembers.add(overrideFunction(file.getProject(), (SimpleFunctionDescriptor) descriptor));
|
||||
overridingMembers.add(OverrideUtil.createOverridenFunctionElementFromDescriptor(file.getProject(),
|
||||
(SimpleFunctionDescriptor) descriptor, /* shortTypeNames = */
|
||||
false));
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
overridingMembers.add(overrideProperty(file.getProject(), (PropertyDescriptor) descriptor));
|
||||
overridingMembers.add(
|
||||
OverrideUtil.createOverridenPropertyElementFromDescriptor(file.getProject(), (PropertyDescriptor) descriptor));
|
||||
}
|
||||
}
|
||||
return overridingMembers;
|
||||
}
|
||||
|
||||
private static JetElement overrideProperty(Project project, PropertyDescriptor descriptor) {
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
bodyBuilder.append(displayableVisibility(descriptor)).append("override ");
|
||||
if (descriptor.isVar()) {
|
||||
bodyBuilder.append("var ");
|
||||
}
|
||||
else {
|
||||
bodyBuilder.append("val ");
|
||||
}
|
||||
|
||||
addReceiverParameter(descriptor, bodyBuilder);
|
||||
|
||||
bodyBuilder.append(descriptor.getName()).append(" : ").append(
|
||||
DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(descriptor.getType()));
|
||||
String initializer = CodeInsightUtils.defaultInitializer(descriptor.getType());
|
||||
if (initializer != null) {
|
||||
bodyBuilder.append(" = ").append(initializer);
|
||||
}
|
||||
else {
|
||||
bodyBuilder.append(" = ?");
|
||||
}
|
||||
return JetPsiFactory.createProperty(project, bodyBuilder.toString());
|
||||
}
|
||||
|
||||
private static String renderType(JetType type) {
|
||||
return DescriptorRenderer.TEXT.renderType(type);
|
||||
}
|
||||
|
||||
private static JetElement overrideFunction(Project project, SimpleFunctionDescriptor descriptor) {
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
bodyBuilder.append(displayableVisibility(descriptor));
|
||||
bodyBuilder.append("override fun ");
|
||||
|
||||
List<String> whereRestrictions = new ArrayList<String>();
|
||||
if (!descriptor.getTypeParameters().isEmpty()) {
|
||||
bodyBuilder.append("<");
|
||||
boolean first = true;
|
||||
for (TypeParameterDescriptor param : descriptor.getTypeParameters()) {
|
||||
if (!first) {
|
||||
bodyBuilder.append(", ");
|
||||
}
|
||||
|
||||
bodyBuilder.append(param.getName());
|
||||
Set<JetType> upperBounds = param.getUpperBounds();
|
||||
if (!upperBounds.isEmpty()) {
|
||||
boolean firstUpperBound = true;
|
||||
for (JetType upperBound : upperBounds) {
|
||||
String upperBoundText = " : " + renderType(upperBound);
|
||||
if (!KotlinBuiltIns.getInstance().getDefaultBound().equals(upperBound)) {
|
||||
if (firstUpperBound) {
|
||||
bodyBuilder.append(upperBoundText);
|
||||
}
|
||||
else {
|
||||
whereRestrictions.add(param.getName() + upperBoundText);
|
||||
}
|
||||
}
|
||||
firstUpperBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
bodyBuilder.append("> ");
|
||||
}
|
||||
|
||||
addReceiverParameter(descriptor, bodyBuilder);
|
||||
|
||||
bodyBuilder.append(descriptor.getName()).append("(");
|
||||
boolean isAbstractFun = descriptor.getModality() == Modality.ABSTRACT;
|
||||
StringBuilder delegationBuilder = new StringBuilder();
|
||||
if (isAbstractFun) {
|
||||
delegationBuilder.append("throw UnsupportedOperationException()");
|
||||
}
|
||||
else {
|
||||
delegationBuilder.append("super<").append(descriptor.getContainingDeclaration().getName());
|
||||
delegationBuilder.append(">.").append(descriptor.getName()).append("(");
|
||||
}
|
||||
boolean first = true;
|
||||
for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) {
|
||||
if (!first) {
|
||||
bodyBuilder.append(",");
|
||||
if (!isAbstractFun) {
|
||||
delegationBuilder.append(",");
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
bodyBuilder.append(parameterDescriptor.getName());
|
||||
bodyBuilder.append(" : ");
|
||||
bodyBuilder.append(renderType(parameterDescriptor.getType()));
|
||||
|
||||
if (!isAbstractFun) {
|
||||
delegationBuilder.append(parameterDescriptor.getName());
|
||||
}
|
||||
}
|
||||
bodyBuilder.append(")");
|
||||
if (!isAbstractFun) {
|
||||
delegationBuilder.append(")");
|
||||
}
|
||||
JetType returnType = descriptor.getReturnType();
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
|
||||
boolean returnsNotUnit = returnType != null && !builtIns.getUnitType().equals(returnType);
|
||||
if (returnsNotUnit) {
|
||||
bodyBuilder.append(" : ").append(renderType(returnType));
|
||||
}
|
||||
if (!whereRestrictions.isEmpty()) {
|
||||
bodyBuilder.append("\n").append("where ").append(StringUtil.join(whereRestrictions, ", "));
|
||||
}
|
||||
bodyBuilder.append("{").append(returnsNotUnit && !isAbstractFun ? "return " : "").append(delegationBuilder.toString()).append("}");
|
||||
|
||||
return JetPsiFactory.createFunction(project, bodyBuilder.toString());
|
||||
}
|
||||
|
||||
private static void addReceiverParameter(CallableDescriptor descriptor, StringBuilder bodyBuilder) {
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
|
||||
if (receiverParameter != null) {
|
||||
bodyBuilder.append(receiverParameter.getType()).append(".");
|
||||
}
|
||||
}
|
||||
|
||||
private static String displayableVisibility(MemberDescriptor descriptor) {
|
||||
Visibility visibility = descriptor.getVisibility().normalize();
|
||||
return visibility != Visibilities.INTERNAL ? visibility.toString() + " " : "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<CallableMemberDescriptor> collectMethodsToGenerate(@NotNull JetClassOrObject classOrObject, BindingContext bindingContext) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.codeInsight;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class OverrideUtil {
|
||||
|
||||
private OverrideUtil() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetElement createOverridenPropertyElementFromDescriptor(@NotNull Project project, @NotNull PropertyDescriptor descriptor) {
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
bodyBuilder.append(displayableVisibility(descriptor)).append("override ");
|
||||
if (descriptor.isVar()) {
|
||||
bodyBuilder.append("var ");
|
||||
}
|
||||
else {
|
||||
bodyBuilder.append("val ");
|
||||
}
|
||||
|
||||
addReceiverParameter(descriptor, bodyBuilder);
|
||||
|
||||
bodyBuilder.append(descriptor.getName()).append(" : ").append(
|
||||
DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(descriptor.getType()));
|
||||
String initializer = CodeInsightUtils.defaultInitializer(descriptor.getType());
|
||||
if (initializer != null) {
|
||||
bodyBuilder.append(" = ").append(initializer);
|
||||
}
|
||||
else {
|
||||
bodyBuilder.append(" = ?");
|
||||
}
|
||||
return JetPsiFactory.createProperty(project, bodyBuilder.toString());
|
||||
}
|
||||
|
||||
private static String displayableVisibility(MemberDescriptor descriptor) {
|
||||
Visibility visibility = descriptor.getVisibility().normalize();
|
||||
return visibility != Visibilities.INTERNAL ? visibility.toString() + " ": "";
|
||||
}
|
||||
|
||||
private static String renderType(JetType type, boolean shortNames) {
|
||||
if (shortNames) return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
|
||||
else return DescriptorRenderer.TEXT.renderType(type);
|
||||
}
|
||||
|
||||
private static void addReceiverParameter(CallableDescriptor descriptor, StringBuilder bodyBuilder) {
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
|
||||
if (receiverParameter != null) {
|
||||
bodyBuilder.append(receiverParameter.getType()).append(".");
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String createOverridenFunctionSignatureStringFromDescriptor(
|
||||
@NotNull Project project,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
boolean shortTypeNames
|
||||
) {
|
||||
JetNamedFunction functionElement = createOverridenFunctionElementFromDescriptor(project, descriptor, shortTypeNames);
|
||||
JetExpression bodyExpression = functionElement.getBodyExpression();
|
||||
assert bodyExpression != null : "createOverridenFunctionElementFromDescriptor should always return function with body.";
|
||||
bodyExpression.replace(JetPsiFactory.createWhiteSpace(project));
|
||||
return functionElement.getText().trim();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetNamedFunction createOverridenFunctionElementFromDescriptor(
|
||||
@NotNull Project project,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
boolean shortNames
|
||||
) {
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
bodyBuilder.append(displayableVisibility(descriptor));
|
||||
bodyBuilder.append("override fun ");
|
||||
|
||||
List<String> whereRestrictions = new ArrayList<String>();
|
||||
if (!descriptor.getTypeParameters().isEmpty()) {
|
||||
bodyBuilder.append("<");
|
||||
boolean first = true;
|
||||
for (TypeParameterDescriptor param : descriptor.getTypeParameters()) {
|
||||
if (!first) {
|
||||
bodyBuilder.append(", ");
|
||||
}
|
||||
|
||||
bodyBuilder.append(param.getName());
|
||||
Set<JetType> upperBounds = param.getUpperBounds();
|
||||
if (!upperBounds.isEmpty()) {
|
||||
boolean firstUpperBound = true;
|
||||
for (JetType upperBound : upperBounds) {
|
||||
String upperBoundText = ": " + renderType(upperBound, shortNames);
|
||||
if (!KotlinBuiltIns.getInstance().getDefaultBound().equals(upperBound)) {
|
||||
if (firstUpperBound) {
|
||||
bodyBuilder.append(upperBoundText);
|
||||
}
|
||||
else {
|
||||
whereRestrictions.add(param.getName() + upperBoundText);
|
||||
}
|
||||
}
|
||||
firstUpperBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
bodyBuilder.append("> ");
|
||||
}
|
||||
|
||||
addReceiverParameter(descriptor, bodyBuilder);
|
||||
|
||||
bodyBuilder.append(descriptor.getName()).append("(");
|
||||
boolean isAbstractFun = descriptor.getModality() == Modality.ABSTRACT;
|
||||
StringBuilder delegationBuilder = new StringBuilder();
|
||||
if (isAbstractFun) {
|
||||
delegationBuilder.append("throw UnsupportedOperationException()");
|
||||
}
|
||||
else {
|
||||
delegationBuilder.append("super<").append(descriptor.getContainingDeclaration().getName());
|
||||
delegationBuilder.append(">.").append(descriptor.getName()).append("(");
|
||||
}
|
||||
boolean first = true;
|
||||
for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) {
|
||||
if (!first) {
|
||||
bodyBuilder.append(", ");
|
||||
if (!isAbstractFun) {
|
||||
delegationBuilder.append(", ");
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
bodyBuilder.append(parameterDescriptor.getName());
|
||||
bodyBuilder.append(": ");
|
||||
bodyBuilder.append(renderType(parameterDescriptor.getType(), shortNames));
|
||||
|
||||
if (!isAbstractFun) {
|
||||
delegationBuilder.append(parameterDescriptor.getName());
|
||||
}
|
||||
}
|
||||
bodyBuilder.append(")");
|
||||
if (!isAbstractFun) {
|
||||
delegationBuilder.append(")");
|
||||
}
|
||||
JetType returnType = descriptor.getReturnType();
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
|
||||
boolean returnsNotUnit = returnType != null && !builtIns.getUnitType().equals(returnType);
|
||||
if (returnsNotUnit) {
|
||||
bodyBuilder.append(": ").append(renderType(returnType, shortNames));
|
||||
}
|
||||
if (!whereRestrictions.isEmpty()) {
|
||||
bodyBuilder.append("\n").append("where ").append(StringUtil.join(whereRestrictions, ", "));
|
||||
}
|
||||
bodyBuilder.append("{").append(returnsNotUnit && !isAbstractFun ? "return " : "").append(delegationBuilder.toString()).append("}");
|
||||
|
||||
return JetPsiFactory.createFunction(project, bodyBuilder.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.quickfix;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Queues;
|
||||
import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.VisibilityUtil;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.plugin.JetBundle;
|
||||
import org.jetbrains.jet.plugin.actions.JetChangeFunctionSignatureAction;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil;
|
||||
import org.jetbrains.jet.plugin.codeInsight.OverrideUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Fix that changes member function's signature to match one of super functions' signatures.
|
||||
*/
|
||||
public class ChangeMemberFunctionSignatureFix extends JetHintAction<JetNamedFunction> {
|
||||
private final List<FunctionDescriptor> possibleSignatures;
|
||||
|
||||
public ChangeMemberFunctionSignatureFix(@NotNull JetNamedFunction element) {
|
||||
super(element);
|
||||
this.possibleSignatures = computePossibleSignatures(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
return super.isAvailable(project, editor, file) && !possibleSignatures.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
if (possibleSignatures.size() == 1)
|
||||
return JetBundle.message("change.function.signature.action.single",
|
||||
getFunctionSignatureString(
|
||||
possibleSignatures.get(0),
|
||||
/* shortTypeNames = */ true));
|
||||
else
|
||||
return JetBundle.message("change.function.signature.action.multiple");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getFunctionSignatureString(@NotNull FunctionDescriptor functionSignature, boolean shortTypeNames) {
|
||||
return OverrideUtil.createOverridenFunctionSignatureStringFromDescriptor(
|
||||
element.getProject(), functionSignature, shortTypeNames);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return JetBundle.message("change.function.signature.family");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, @NotNull final Editor editor, PsiFile file)
|
||||
throws IncorrectOperationException {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
createAction(project, editor).execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetChangeFunctionSignatureAction createAction(@NotNull Project project, @NotNull Editor editor) {
|
||||
return new JetChangeFunctionSignatureAction(project, editor, element, possibleSignatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes all the signatures a 'functionElement' could be changed to in order to remove NOTHING_TO_OVERRIDE error.
|
||||
*/
|
||||
@NotNull
|
||||
private List<FunctionDescriptor> computePossibleSignatures(JetNamedFunction functionElement) {
|
||||
BindingContext context = KotlinCacheManagerUtil.getDeclarationsFromProject(functionElement).getBindingContext();
|
||||
FunctionDescriptor functionDescriptor = context.get(BindingContext.FUNCTION, functionElement);
|
||||
if (functionDescriptor == null) return Lists.newArrayList();
|
||||
List<FunctionDescriptor> superFunctions = getPossibleSuperFunctionsDescriptors(functionDescriptor);
|
||||
Map<String, FunctionDescriptor> possibleSignatures = Maps.newHashMap();
|
||||
for (FunctionDescriptor superFunction : superFunctions) {
|
||||
if (!superFunction.getKind().isReal()) continue;
|
||||
FunctionDescriptor signature = changeSignatureToMatch(functionDescriptor, superFunction);
|
||||
possibleSignatures.put(getFunctionSignatureString(signature, /* shortTypeNames = */ false), signature);
|
||||
}
|
||||
return Lists.newArrayList(possibleSignatures.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes function's signature to match superFunction's signature. Returns new descriptor.
|
||||
*/
|
||||
private static FunctionDescriptor changeSignatureToMatch(FunctionDescriptor function, FunctionDescriptor superFunction) {
|
||||
List<ValueParameterDescriptor> superParameters = superFunction.getValueParameters();
|
||||
List<ValueParameterDescriptor> parameters = function.getValueParameters();
|
||||
List<ValueParameterDescriptor> newParameters = Lists.newArrayList(superParameters);
|
||||
|
||||
// Parameters in superFunction, which are matched in new function signature:
|
||||
BitSet matched = new BitSet(superParameters.size());
|
||||
// Parameters in this function, which are used in new function signature:
|
||||
BitSet used = new BitSet(superParameters.size());
|
||||
|
||||
matchParameters(MATCH_NAMES, superParameters, parameters, newParameters, matched, used);
|
||||
matchParameters(MATCH_TYPES, superParameters, parameters, newParameters, matched, used);
|
||||
|
||||
return FunctionDescriptorUtil.replaceFunctionParameters(
|
||||
superFunction.copy(
|
||||
function.getContainingDeclaration(),
|
||||
Modality.OPEN,
|
||||
getVisibility(function, superFunction),
|
||||
CallableMemberDescriptor.Kind.DELEGATION,
|
||||
/* copyOverrides = */ true),
|
||||
newParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new visibility for 'function' modified to override 'superFunction'.
|
||||
*/
|
||||
private static Visibility getVisibility(FunctionDescriptor function, FunctionDescriptor superFunction) {
|
||||
ArrayDeque<CallableMemberDescriptor> descriptors =
|
||||
Queues.<CallableMemberDescriptor>newArrayDeque(Arrays.asList(superFunction, function));
|
||||
return VisibilityUtil.findMemberWithMaxVisibility(descriptors).getVisibility();
|
||||
}
|
||||
|
||||
/** Helper interface for matchParameters(..) method. */
|
||||
private interface ParameterChooser {
|
||||
/**
|
||||
* Checks if 'parameter' may be used to match 'superParameter'.
|
||||
* If so, returns (possibly modified) descriptor to be used as the new parameter.
|
||||
* If not, returns null.
|
||||
*/
|
||||
@Nullable
|
||||
ValueParameterDescriptor choose(@NotNull ValueParameterDescriptor parameter, @NotNull ValueParameterDescriptor superParameter);
|
||||
}
|
||||
|
||||
private static final ParameterChooser MATCH_NAMES = new ParameterChooser() {
|
||||
@Nullable
|
||||
@Override
|
||||
public ValueParameterDescriptor choose(
|
||||
@NotNull ValueParameterDescriptor parameter,
|
||||
@NotNull ValueParameterDescriptor superParameter
|
||||
) {
|
||||
return parameter.getName().equals(superParameter.getName()) ? superParameter : null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final ParameterChooser MATCH_TYPES = new ParameterChooser() {
|
||||
@Nullable
|
||||
@Override
|
||||
public ValueParameterDescriptor choose(
|
||||
@NotNull ValueParameterDescriptor parameter,
|
||||
@NotNull ValueParameterDescriptor superParameter
|
||||
) {
|
||||
return JetTypeChecker.INSTANCE.equalTypes(parameter.getType(), superParameter.getType()) ? parameter : null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Match function's parameters with super function's parameters using parameterChooser.
|
||||
* Doesn't have to preserve ordering, parameter names or types.
|
||||
* @param superParameters - super function's parameters
|
||||
* @param parameters - function's parameters
|
||||
* @param newParameters - new parameters (may be modified by this function)
|
||||
* @param matched - true iff this parameter in super function is matched by some parameter in function (may be modified by this function)
|
||||
* @param used - true iff this parameter in function is used to match some parameter in super function (may be modified by this function)
|
||||
*/
|
||||
private static void matchParameters(
|
||||
@NotNull ParameterChooser parameterChooser,
|
||||
@NotNull List<ValueParameterDescriptor> superParameters,
|
||||
@NotNull List<ValueParameterDescriptor> parameters,
|
||||
@NotNull List<ValueParameterDescriptor> newParameters,
|
||||
@NotNull BitSet matched,
|
||||
@NotNull BitSet used
|
||||
) {
|
||||
for (ValueParameterDescriptor superParameter : superParameters) {
|
||||
if (!matched.get(superParameter.getIndex())) {
|
||||
for (ValueParameterDescriptor parameter : parameters) {
|
||||
ValueParameterDescriptor choice = parameterChooser.choose(parameter, superParameter);
|
||||
if (!used.get(parameter.getIndex()) && choice != null) {
|
||||
used.set(parameter.getIndex(), true);
|
||||
matched.set(superParameter.getIndex(), true);
|
||||
newParameters.set(superParameter.getIndex(), choice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all open functions in superclasses which have the same name as 'functionDescriptor' (but possibly
|
||||
* different parameters/return type).
|
||||
*/
|
||||
@NotNull
|
||||
private static List<FunctionDescriptor> getPossibleSuperFunctionsDescriptors(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
|
||||
List<FunctionDescriptor> superFunctions = Lists.newArrayList();
|
||||
if (!(containingDeclaration instanceof ClassDescriptor)) return superFunctions;
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
|
||||
|
||||
Name name = functionDescriptor.getName();
|
||||
for (ClassDescriptor superclass : DescriptorUtils.getSuperclassDescriptors(classDescriptor)) {
|
||||
JetType type = superclass.getDefaultType();
|
||||
JetScope scope = type.getMemberScope();
|
||||
for (FunctionDescriptor function : scope.getFunctions(name)) {
|
||||
if (!function.getKind().isReal()) continue;
|
||||
if (function.getModality().isOverridable())
|
||||
superFunctions.add(function);
|
||||
}
|
||||
}
|
||||
return superFunctions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetIntentionActionFactory createFactory() {
|
||||
return new JetIntentionActionFactory() {
|
||||
@Nullable
|
||||
@Override
|
||||
public IntentionAction createAction(Diagnostic diagnostic) {
|
||||
JetNamedFunction function = QuickFixUtil.getParentElementOfType(diagnostic, JetNamedFunction.class);
|
||||
return function == null ? null : new ChangeMemberFunctionSignatureFix(function);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showHint(@NotNull Editor editor) {
|
||||
if (possibleSignatures.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Project project = editor.getProject();
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,7 @@ public class QuickFixes {
|
||||
factories.put(NON_MEMBER_FUNCTION_NO_BODY, addFunctionBodyFactory);
|
||||
|
||||
factories.put(NOTHING_TO_OVERRIDE, RemoveModifierFix.createRemoveModifierFromListOwnerFactory(OVERRIDE_KEYWORD));
|
||||
factories.put(NOTHING_TO_OVERRIDE, ChangeMemberFunctionSignatureFix.createFactory());
|
||||
factories.put(VIRTUAL_MEMBER_HIDDEN, AddModifierFix.createFactory(OVERRIDE_KEYWORD));
|
||||
|
||||
factories.put(USELESS_CAST_STATIC_ASSERT_IS_FINE, ReplaceOperationInBinaryExpressionFix.createChangeCastToStaticAssertFactory());
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f(a: Int) {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Change function signature..." "true"
|
||||
// ERROR: <html>Class 'B' must be declared abstract or implement abstract member<br/><b>abstract</b> <b>fun</b> f(a: jet.String): jet.Unit <i>defined in</i> A</html>
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
fun f(a: String)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f(a: Int) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'public override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
public <caret>override fun f(a: Int) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
open class A {
|
||||
open fun f(a: Int) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: Int) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
abstract class A {
|
||||
abstract fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: Int) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
trait B : A {
|
||||
<caret>override fun f(a: Int)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(x: Int, t: String, z: Double)'" "true"
|
||||
open class A {
|
||||
open fun f(x: Int, y: String, z: Double) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(x: Int, t: String, z: Double) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(y: Int, x: String)'" "true"
|
||||
open class A {
|
||||
open fun f(a: Int, b: String) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(y: Int, x: String) {}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Change function signature to 'override fun f()'" "true"
|
||||
open class A {
|
||||
open fun f() {}
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
open override fun f() {}
|
||||
}
|
||||
|
||||
class C : B() {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Change function signature to 'override fun f(a: Int): Int'" "true"
|
||||
open class A {
|
||||
open fun f(a: Int): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: Int): Int = 7
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f(a: Int) {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Change function signature to 'override fun f(a: Int): Int'" "true"
|
||||
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>jet.Int</td></tr><tr><td>Found:</td><td>jet.String</td></tr></table></html>
|
||||
open class A {
|
||||
open fun f(a: Int): Int = 0
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
// Note that when parameter types match, RETURN_TYPE_MISMATCH_ON_OVERRIDE error is reported
|
||||
// and "Change function signature" quickfix is not present.
|
||||
<caret>override fun f(a: Int): Int = "FOO"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "false"
|
||||
// ERROR: 'f' overrides nothing
|
||||
// ACTION: Remove 'override' modifier
|
||||
open class A {
|
||||
open fun foo() {}
|
||||
fun f(a: Int) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: String) {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Change function signature to 'protected override fun next(p0: Int): Int'" "true"
|
||||
import java.util.Random
|
||||
|
||||
class MyRandom : Random() {
|
||||
<caret>protected override fun next(p0: Int): Int = 4
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f()'" "true"
|
||||
trait A {
|
||||
fun f()
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Change function signature to 'override fun f()'" "true"
|
||||
trait A {
|
||||
fun f()
|
||||
}
|
||||
trait B {
|
||||
fun f()
|
||||
}
|
||||
|
||||
class C : A, B {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Change function signature..." "true"
|
||||
// ERROR: <html>Class 'B' must be declared abstract or implement abstract member<br/><b>abstract</b> <b>fun</b> f(a: jet.String): jet.Unit <i>defined in</i> A</html>
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
fun f(a: String)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'public override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
public <caret>override fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
open class A {
|
||||
open fun f(a: Int) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: String) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
abstract class A {
|
||||
abstract fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: String) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
trait B : A {
|
||||
<caret>override fun f(a: String)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(x: Int, t: String, z: Double)'" "true"
|
||||
open class A {
|
||||
open fun f(x: Int, y: String, z: Double) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(z: String, x: String, t: String) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(y: Int, x: String)'" "true"
|
||||
open class A {
|
||||
open fun f(a: Int, b: String) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(x: String, y: Int) {}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Change function signature to 'override fun f()'" "true"
|
||||
open class A {
|
||||
open fun f() {}
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
open override fun f() {}
|
||||
}
|
||||
|
||||
class C : B() {
|
||||
<caret>override fun f(a : Int) {}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Change function signature to 'override fun f(a: Int): Int'" "true"
|
||||
open class A {
|
||||
open fun f(a: Int): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: String): Int = 7
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "true"
|
||||
trait A {
|
||||
fun f(a: Int)
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f(a: String) {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Change function signature to 'override fun f(a: Int): Int'" "true"
|
||||
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>jet.Int</td></tr><tr><td>Found:</td><td>jet.String</td></tr></table></html>
|
||||
open class A {
|
||||
open fun f(a: Int): Int = 0
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
// Note that when parameter types match, RETURN_TYPE_MISMATCH_ON_OVERRIDE error is reported
|
||||
// and "Change function signature" quickfix is not present.
|
||||
<caret>override fun f(a : String): String = "FOO"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Change function signature to 'override fun f(a: Int)'" "false"
|
||||
// ERROR: 'f' overrides nothing
|
||||
// ACTION: Remove 'override' modifier
|
||||
open class A {
|
||||
open fun foo() {}
|
||||
fun f(a: Int) {}
|
||||
}
|
||||
|
||||
class B : A(){
|
||||
<caret>override fun f(a: String) {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Change function signature to 'protected override fun next(p0: Int): Int'" "true"
|
||||
import java.util.Random
|
||||
|
||||
class MyRandom : Random() {
|
||||
<caret>override fun next(): Int = 4
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f()'" "true"
|
||||
trait A {
|
||||
fun f()
|
||||
}
|
||||
|
||||
class B : A {
|
||||
<caret>override fun f(a: Int) {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Change function signature to 'override fun f()'" "true"
|
||||
trait A {
|
||||
fun f()
|
||||
}
|
||||
trait B {
|
||||
fun f()
|
||||
}
|
||||
|
||||
class C : A, B {
|
||||
<caret>override fun f(a: String) {}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Change function signature to 'override fun f(a: A)'" "true"
|
||||
// ERROR: 'f' overrides nothing
|
||||
// ERROR: 'f' overrides nothing
|
||||
import a.B
|
||||
import a.A
|
||||
|
||||
class BB : B() {
|
||||
<caret>override fun f(a: A) {}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Change function signature to 'override fun f(a: A)'" "true"
|
||||
// ERROR: 'f' overrides nothing
|
||||
// ERROR: 'f' overrides nothing
|
||||
import a.B
|
||||
class BB : B() {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package a
|
||||
class A {}
|
||||
open class B {
|
||||
override fun f(a: A) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: A)'" "true"
|
||||
// ERROR: 'f' overrides nothing
|
||||
// ERROR: 'f' overrides nothing
|
||||
import a.B
|
||||
class A {}
|
||||
class BB : B() {
|
||||
<caret>override fun f(a: a.A) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Change function signature to 'override fun f(a: A)'" "true"
|
||||
// ERROR: 'f' overrides nothing
|
||||
// ERROR: 'f' overrides nothing
|
||||
import a.B
|
||||
class A {}
|
||||
class BB : B() {
|
||||
<caret>override fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package a
|
||||
class A {}
|
||||
open class B {
|
||||
override fun f(a: A) {}
|
||||
}
|
||||
@@ -193,15 +193,34 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/override")
|
||||
@InnerTestClasses({})
|
||||
@InnerTestClasses({Override.NothingToOverride.class})
|
||||
public static class Override extends AbstractQuickFixMultiFileTest {
|
||||
public void testAllFilesPresentInOverride() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/override"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/override/nothingToOverride")
|
||||
public static class NothingToOverride extends AbstractQuickFixMultiFileTest {
|
||||
public void testAllFilesPresentInNothingToOverride() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/override/nothingToOverride"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("import.before.Main.kt")
|
||||
public void testImport() throws Exception {
|
||||
doTestWithExtraFile("idea/testData/quickfix/override/nothingToOverride/import.before.Main.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("twoPackages.before.Main.kt")
|
||||
public void testTwoPackages() throws Exception {
|
||||
doTestWithExtraFile("idea/testData/quickfix/override/nothingToOverride/twoPackages.before.Main.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Override");
|
||||
suite.addTestSuite(Override.class);
|
||||
suite.addTestSuite(NothingToOverride.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,14 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.quickfix;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
|
||||
import org.jetbrains.jet.plugin.quickfix.AbstractQuickFixTest;
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@@ -715,7 +712,7 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/override")
|
||||
@InnerTestClasses({Override.TypeMismatchOnOverride.class})
|
||||
@InnerTestClasses({Override.NothingToOverride.class, Override.TypeMismatchOnOverride.class})
|
||||
public static class Override extends AbstractQuickFixTest {
|
||||
public void testAllFilesPresentInOverride() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/override"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||
@@ -726,11 +723,6 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest("idea/testData/quickfix/override/beforeChangeToInvocation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeNothingToOverride.kt")
|
||||
public void testNothingToOverride() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/beforeNothingToOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeOverriddingMultipleFinalMethods.kt")
|
||||
public void testOverriddingMultipleFinalMethods() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/beforeOverriddingMultipleFinalMethods.kt");
|
||||
@@ -776,6 +768,99 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest("idea/testData/quickfix/override/beforeVirtualMethodHidden.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/override/nothingToOverride")
|
||||
public static class NothingToOverride extends AbstractQuickFixTest {
|
||||
@TestMetadata("beforeAddParameter.kt")
|
||||
public void testAddParameter() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeAddParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAddParameterMultiple.kt")
|
||||
public void testAddParameterMultiple() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeAddParameterMultiple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAddParameterPreserveVisibility.kt")
|
||||
public void testAddParameterPreserveVisibility() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeAddParameterPreserveVisibility.kt");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNothingToOverride() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/override/nothingToOverride"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterType.kt")
|
||||
public void testChangeParameterType() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeAbstractSuperclass.kt")
|
||||
public void testChangeParameterTypeAbstractSuperclass() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeAbstractSuperclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeInTrait.kt")
|
||||
public void testChangeParameterTypeInTrait() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeInTrait.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeMatchNames.kt")
|
||||
public void testChangeParameterTypeMatchNames() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeMatchNames.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeModifyOrder.kt")
|
||||
public void testChangeParameterTypeModifyOrder() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeModifyOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeOpenOverride.kt")
|
||||
public void testChangeParameterTypeOpenOverride() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeOpenOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeSingleExpressionFunction.kt")
|
||||
public void testChangeParameterTypeSingleExpressionFunction() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeSingleExpressionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeParameterTypeSuperTrait.kt")
|
||||
public void testChangeParameterTypeSuperTrait() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeParameterTypeSuperTrait.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeReturnType.kt")
|
||||
public void testChangeReturnType() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeChangeReturnType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeNoOpenSuperFunction.kt")
|
||||
public void testNoOpenSuperFunction() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeNoOpenSuperFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeOverrideJavaMethod.kt")
|
||||
public void testOverrideJavaMethod() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeOverrideJavaMethod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeRemoveOverride.kt")
|
||||
public void testRemoveOverride() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeRemoveOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeRemoveParameter.kt")
|
||||
public void testRemoveParameter() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeRemoveParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeRemoveParameterTwoTraits.kt")
|
||||
public void testRemoveParameterTwoTraits() throws Exception {
|
||||
doTest("idea/testData/quickfix/override/nothingToOverride/beforeRemoveParameterTwoTraits.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/override/typeMismatchOnOverride")
|
||||
public static class TypeMismatchOnOverride extends AbstractQuickFixTest {
|
||||
public void testAllFilesPresentInTypeMismatchOnOverride() throws Exception {
|
||||
@@ -822,6 +907,7 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Override");
|
||||
suite.addTestSuite(Override.class);
|
||||
suite.addTestSuite(NothingToOverride.class);
|
||||
suite.addTestSuite(TypeMismatchOnOverride.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user