Refactoring: use DescriptionRenderer to generate overriding functions / properties.

This commit is contained in:
Michał Sapalski
2013-04-06 12:36:50 +02:00
committed by Andrey Breslav
parent 01c4826b06
commit 2352d86932
10 changed files with 336 additions and 365 deletions
@@ -32,7 +32,7 @@ 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.CodeInsightUtils;
import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
import javax.swing.*;
@@ -112,8 +112,7 @@ public class JetChangeFunctionSignatureAction implements QuestionAction {
@NotNull
@Override
public String getTextFor(FunctionDescriptor aValue) {
return OverrideUtil.createOverridenFunctionSignatureStringFromDescriptor(
project,
return CodeInsightUtils.createFunctionSignatureStringFromDescriptor(
aValue,
/* shortTypeNames = */ true);
}
@@ -121,8 +120,7 @@ public class JetChangeFunctionSignatureAction implements QuestionAction {
}
private static void changeSignature(final JetNamedFunction element, final Project project, FunctionDescriptor signature) {
final String signatureString = OverrideUtil.createOverridenFunctionSignatureStringFromDescriptor(
project,
final String signatureString = CodeInsightUtils.createFunctionSignatureStringFromDescriptor(
signature,
/* shortTypeNames = */ false);
@@ -12,12 +12,14 @@ import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetBlockExpression;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile;
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;
@@ -167,4 +169,13 @@ public class CodeInsightUtils {
private CodeInsightUtils() {
}
@NotNull
public static String createFunctionSignatureStringFromDescriptor(
@NotNull FunctionDescriptor descriptor,
boolean shortTypeNames
) {
DescriptorRenderer renderer = shortTypeNames ? DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES : DescriptorRenderer.SOURCE_CODE;
return renderer.render(descriptor);
}
}
@@ -30,14 +30,14 @@ 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.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.*;
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;
@@ -118,18 +118,77 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns
for (DescriptorClassMember selectedElement : selectedElements) {
DeclarationDescriptor descriptor = selectedElement.getDescriptor();
if (descriptor instanceof SimpleFunctionDescriptor) {
overridingMembers.add(OverrideUtil.createOverridenFunctionElementFromDescriptor(file.getProject(),
(SimpleFunctionDescriptor) descriptor, /* shortTypeNames = */
false));
overridingMembers.add(overrideFunction(file.getProject(),
(SimpleFunctionDescriptor) descriptor));
}
else if (descriptor instanceof PropertyDescriptor) {
overridingMembers.add(
OverrideUtil.createOverridenPropertyElementFromDescriptor(file.getProject(), (PropertyDescriptor) descriptor));
overrideProperty(file.getProject(), (PropertyDescriptor) descriptor));
}
}
return overridingMembers;
}
@NotNull
private static JetElement overrideProperty(@NotNull Project project, @NotNull PropertyDescriptor descriptor) {
PropertyDescriptor newDescriptor = (PropertyDescriptor) descriptor.copy(
descriptor.getContainingDeclaration(),
Modality.OPEN,
descriptor.getVisibility(),
descriptor.getKind(),
/* copyOverrides = */ true);
newDescriptor.addOverriddenDescriptor(descriptor);
StringBuilder bodyBuilder = new StringBuilder();
String initializer = CodeInsightUtils.defaultInitializer(descriptor.getType());
if (initializer != null) {
bodyBuilder.append(" = ").append(initializer);
}
else {
bodyBuilder.append(" = ?");
}
return JetPsiFactory.createProperty(project, DescriptorRenderer.SOURCE_CODE.render(newDescriptor) + bodyBuilder.toString());
}
@NotNull
private static JetNamedFunction overrideFunction(@NotNull Project project, @NotNull FunctionDescriptor descriptor) {
FunctionDescriptor newDescriptor = descriptor.copy(
descriptor.getContainingDeclaration(),
Modality.OPEN,
descriptor.getVisibility(),
descriptor.getKind(),
/* copyOverrides = */ true);
newDescriptor.addOverriddenDescriptor(descriptor);
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;
if (!isAbstractFun) {
for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) {
if (!first) {
delegationBuilder.append(", ");
}
first = false;
delegationBuilder.append(parameterDescriptor.getName());
}
delegationBuilder.append(")");
}
JetType returnType = descriptor.getReturnType();
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
boolean returnsNotUnit = returnType != null && !builtIns.getUnitType().equals(returnType);
String body = "{" + (returnsNotUnit && !isAbstractFun ? "return " : "") + delegationBuilder.toString() + "}";
return JetPsiFactory.createFunction(project, DescriptorRenderer.SOURCE_CODE.render(newDescriptor) + body);
}
@NotNull
public Set<CallableMemberDescriptor> collectMethodsToGenerate(@NotNull JetClassOrObject classOrObject, BindingContext bindingContext) {
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
@@ -1,184 +0,0 @@
/*
* 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());
}
}
@@ -42,7 +42,7 @@ 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 org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
import java.util.*;
@@ -76,8 +76,8 @@ public class ChangeMemberFunctionSignatureFix extends JetHintAction<JetNamedFunc
@NotNull
private String getFunctionSignatureString(@NotNull FunctionDescriptor functionSignature, boolean shortTypeNames) {
return OverrideUtil.createOverridenFunctionSignatureStringFromDescriptor(
element.getProject(), functionSignature, shortTypeNames);
return CodeInsightUtils.createFunctionSignatureStringFromDescriptor(
functionSignature, shortTypeNames);
}
@NotNull
@@ -136,7 +136,7 @@ public class ChangeMemberFunctionSignatureFix extends JetHintAction<JetNamedFunc
matchParameters(MATCH_NAMES, superParameters, parameters, newParameters, matched, used);
matchParameters(MATCH_TYPES, superParameters, parameters, newParameters, matched, used);
return FunctionDescriptorUtil.replaceFunctionParameters(
FunctionDescriptor newFunction = FunctionDescriptorUtil.replaceFunctionParameters(
superFunction.copy(
function.getContainingDeclaration(),
Modality.OPEN,
@@ -144,6 +144,8 @@ public class ChangeMemberFunctionSignatureFix extends JetHintAction<JetNamedFunc
CallableMemberDescriptor.Kind.DELEGATION,
/* copyOverrides = */ true),
newParameters);
newFunction.addOverriddenDescriptor(superFunction);
return newFunction;
}
/**